[
  {
    "path": ".classpath",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<classpath>\n\t<classpathentry exported=\"true\" kind=\"con\" path=\"com.android.ide.eclipse.adt.ANDROID_FRAMEWORK\"/>\n\t<classpathentry exported=\"true\" kind=\"con\" path=\"com.android.ide.eclipse.adt.LIBRARIES\"/>\n\t<classpathentry exported=\"true\" kind=\"con\" path=\"com.android.ide.eclipse.adt.DEPENDENCIES\"/>\n\t<classpathentry exported=\"true\" kind=\"lib\" path=\"libs/odoo-v2.jar\"/>\n\t<classpathentry kind=\"lib\" path=\"libs/swipe_library.jar\"/>\n\t<classpathentry kind=\"lib\" path=\"libs/android-support-v4.jar\"/>\n\t<classpathentry kind=\"src\" path=\"src\"/>\n\t<classpathentry kind=\"src\" path=\"gen\"/>\n\t<classpathentry kind=\"output\" path=\"bin/classes\"/>\n</classpath>\n"
  },
  {
    "path": "README.md",
    "content": "Odoo Mobile Framework v2.0\n==========================\n\n<b>Android Studio Project</b>\n\n<a href=\"https://www.odoo.com/start\" target=\"_blank\">\n<img alt=\"Odoo Instace\" src=\"https://dharmangsoni.odoo.com/website/image?max_height=768&field=datas&model=ir.attachment&id=42&max_width=250\" style=\"height:50px; width:auto\" />\n</a>\n\nOdoo is a powerful open source framework. With help of this framework we can rapidly develop almost any application.\n\nWorld is contracting with the growth of mobile phone technology. As the number of users is increasing day by day, facilities are also increasing. Now a days mobiles are not used just for making calls but they have innumerable uses and can be used as a Camera , Music player, Tablet PC, T.V. , Web browser etc. And with the new technologies, new software and operating systems are required.\n\nOne of the most widely used mobile OS these days is ANDROID. Android is a software bunch comprising not only operating system but also middleware and key applications.\n\nOdoo Mobile framework is an open source mobile application development framework with Odoo integration. With the help of mobile framework we can rapidly develop almost all Odoo supported application as faster as we can develop in Odoo Framework.\n\nThis framework contains its own ORM to handle mobile’s local database. So you do not have to worry about data comming from Odoo Server. It has pre-developed services and providers to make your application data synchronized with Odoo.\n"
  },
  {
    "path": "app/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "app/build.gradle",
    "content": "apply plugin: 'com.android.application'\n\nandroid {\n    signingConfigs {\n    }\n    compileSdkVersion 22\n    buildToolsVersion \"21.1.2\"\n    defaultConfig {\n        applicationId \"com.odoo.crm\"\n        minSdkVersion 14\n        targetSdkVersion 22\n        versionCode 7\n        versionName \"1.0.7\"\n    }\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n}\ndependencies {\n    compile fileTree(include: ['*.jar'], dir: 'libs')\n    compile files('libs/swipe_library.jar')\n    compile 'com.android.support:appcompat-v7:22.2.0'\n    compile 'com.android.support:cardview-v7:22.0.0'\n    compile 'com.google.android.gms:play-services:7.5.0'\n    compile project(':intro-slider-lib')\n    compile project(':parallax-effect-lib')\n    compile project(':odoo-rpc-v2')\n    compile project(':calendar-lib')\n    compile project(':bottom-sheet-lib')\n    compile project(':snackbar-lib')\n}\n"
  },
  {
    "path": "app/manifest-merger-release-report.txt",
    "content": "-- Merging decision tree log ---\nmanifest\nADDED from AndroidManifest.xml:2:1\n\txmlns:android\n\t\tADDED from AndroidManifest.xml:2:11\n\tpackage\n\t\tADDED from AndroidManifest.xml:3:5\n\t\tINJECTED from AndroidManifest.xml:0:0\n\t\tINJECTED from AndroidManifest.xml:0:0\n\tandroid:versionName\n\t\tINJECTED from AndroidManifest.xml:0:0\n\t\tINJECTED from AndroidManifest.xml:0:0\n\tandroid:versionCode\n\t\tINJECTED from AndroidManifest.xml:0:0\n\t\tINJECTED from AndroidManifest.xml:0:0\nuses-permission#android.permission.INTERNET\nADDED from AndroidManifest.xml:5:5\nMERGED from com.google.android.gms:play-services-ads:7.5.0:20:5\nMERGED from com.google.android.gms:play-services-analytics:7.5.0:21:5\nMERGED from com.google.android.gms:play-services-analytics:7.5.0:21:5\nMERGED from com.google.android.gms:play-services-appinvite:7.5.0:19:5\nMERGED from com.google.android.gms:play-services-maps:7.5.0:21:5\nMERGED from com.google.android.gms:play-services-maps:7.5.0:21:5\nMERGED from com.google.android.gms:play-services-maps:7.5.0:21:5\nMERGED from com.google.android.gms:play-services-wallet:7.5.0:20:5\nMERGED from com.google.android.gms:play-services-maps:7.5.0:21:5\nMERGED from master-crm:odoo-rpc-v2:unspecified:11:5\n\tandroid:name\n\t\tADDED from AndroidManifest.xml:5:22\nuses-permission#android.permission.VIBRATE\nADDED from AndroidManifest.xml:6:5\nMERGED from master-crm:odoo-rpc-v2:unspecified:14:5\n\tandroid:name\n\t\tADDED from AndroidManifest.xml:6:22\nuses-permission#android.permission.ACCESS_WIFI_STATE\nADDED from AndroidManifest.xml:7:5\nMERGED from master-crm:odoo-rpc-v2:unspecified:15:5\n\tandroid:name\n\t\tADDED from AndroidManifest.xml:7:22\nuses-permission#android.permission.ACCESS_NETWORK_STATE\nADDED from AndroidManifest.xml:8:5\nMERGED from com.google.android.gms:play-services-ads:7.5.0:21:5\nMERGED from com.google.android.gms:play-services-analytics:7.5.0:22:5\nMERGED from com.google.android.gms:play-services-analytics:7.5.0:22:5\nMERGED from com.google.android.gms:play-services-maps:7.5.0:20:5\nMERGED from com.google.android.gms:play-services-maps:7.5.0:20:5\nMERGED from com.google.android.gms:play-services-maps:7.5.0:20:5\nMERGED from com.google.android.gms:play-services-nearby:7.5.0:19:5\nMERGED from com.google.android.gms:play-services-maps:7.5.0:20:5\nMERGED from master-crm:odoo-rpc-v2:unspecified:16:5\n\tandroid:name\n\t\tADDED from AndroidManifest.xml:8:22\nuses-permission#android.permission.GET_TASKS\nADDED from AndroidManifest.xml:9:5\n\tandroid:name\n\t\tADDED from AndroidManifest.xml:9:22\nuses-permission#android.permission.AUTHENTICATE_ACCOUNTS\nADDED from AndroidManifest.xml:10:5\n\tandroid:name\n\t\tADDED from AndroidManifest.xml:10:22\nuses-permission#android.permission.GET_ACCOUNTS\nADDED from AndroidManifest.xml:11:5\nMERGED from com.google.android.gms:play-services-wallet:7.5.0:21:5\n\tandroid:name\n\t\tADDED from AndroidManifest.xml:11:22\nuses-permission#android.permission.USE_CREDENTIALS\nADDED from AndroidManifest.xml:12:5\nMERGED from com.google.android.gms:play-services-wallet:7.5.0:22:5\n\tandroid:name\n\t\tADDED from AndroidManifest.xml:12:22\nuses-permission#android.permission.MANAGE_ACCOUNTS\nADDED from AndroidManifest.xml:13:5\n\tandroid:name\n\t\tADDED from AndroidManifest.xml:13:22\nuses-permission#android.permission.READ_SYNC_SETTINGS\nADDED from AndroidManifest.xml:14:5\n\tandroid:name\n\t\tADDED from AndroidManifest.xml:14:22\nuses-permission#android.permission.READ_SYNC_STATS\nADDED from AndroidManifest.xml:15:5\n\tandroid:name\n\t\tADDED from AndroidManifest.xml:15:22\nuses-permission#android.permission.WRITE_SYNC_SETTINGS\nADDED from AndroidManifest.xml:16:5\n\tandroid:name\n\t\tADDED from AndroidManifest.xml:16:22\nuses-permission#android.permission.WAKE_LOCK\nADDED from AndroidManifest.xml:17:5\nMERGED from master-crm:odoo-rpc-v2:unspecified:17:5\n\tandroid:name\n\t\tADDED from AndroidManifest.xml:17:22\nuses-permission#com.google.android.c2dm.permission.RECEIVE\nADDED from AndroidManifest.xml:18:5\nMERGED from master-crm:odoo-rpc-v2:unspecified:13:5\n\tandroid:name\n\t\tADDED from AndroidManifest.xml:18:22\nuses-permission#android.permission.READ_PHONE_STATE\nADDED from AndroidManifest.xml:19:5\nMERGED from master-crm:odoo-rpc-v2:unspecified:12:5\n\tandroid:name\n\t\tADDED from AndroidManifest.xml:19:22\nuses-permission#android.permission.SYSTEM_ALERT_WINDOW\nADDED from AndroidManifest.xml:20:5\n\tandroid:name\n\t\tADDED from AndroidManifest.xml:20:22\nuses-permission#android.permission.CALL_PHONE\nADDED from AndroidManifest.xml:21:5\n\tandroid:name\n\t\tADDED from AndroidManifest.xml:21:22\nuses-permission#android.permission.READ_EXTERNAL_STORAGE\nADDED from AndroidManifest.xml:22:5\n\tandroid:name\n\t\tADDED from AndroidManifest.xml:22:22\nuses-permission#android.permission.WRITE_EXTERNAL_STORAGE\nADDED from AndroidManifest.xml:23:5\nMERGED from com.google.android.gms:play-services-maps:7.5.0:22:5\nMERGED from com.google.android.gms:play-services-maps:7.5.0:22:5\nMERGED from com.google.android.gms:play-services-maps:7.5.0:22:5\nMERGED from com.google.android.gms:play-services-maps:7.5.0:22:5\n\tandroid:name\n\t\tADDED from AndroidManifest.xml:23:22\nuses-permission#android.permission.MANAGE_DOCUMENTS\nADDED from AndroidManifest.xml:24:5\n\tandroid:name\n\t\tADDED from AndroidManifest.xml:24:22\npermission#com.odoo.crm.permission.C2D_MESSAGE\nADDED from AndroidManifest.xml:26:5\n\tandroid:protectionLevel\n\t\tADDED from AndroidManifest.xml:28:9\n\tandroid:name\n\t\tADDED from AndroidManifest.xml:27:9\napplication\nADDED from AndroidManifest.xml:30:5\nMERGED from com.android.support:appcompat-v7:22.2.0:22:5\nMERGED from com.android.support:support-v4:22.2.0:22:5\nMERGED from com.android.support:cardview-v7:22.0.0:22:5\nMERGED from com.google.android.gms:play-services:7.5.0:19:5\nMERGED from com.google.android.gms:play-services-ads:7.5.0:24:5\nMERGED from com.google.android.gms:play-services-base:7.5.0:20:5\nMERGED from com.android.support:support-v4:22.2.0:22:5\nMERGED from com.google.android.gms:play-services-analytics:7.5.0:24:5\nMERGED from com.google.android.gms:play-services-base:7.5.0:20:5\nMERGED from com.android.support:support-v4:22.2.0:22:5\nMERGED from com.google.android.gms:play-services-analytics:7.5.0:24:5\nMERGED from com.google.android.gms:play-services-base:7.5.0:20:5\nMERGED from com.android.support:support-v4:22.2.0:22:5\nMERGED from com.google.android.gms:play-services-appindexing:7.5.0:19:5\nMERGED from com.google.android.gms:play-services-base:7.5.0:20:5\nMERGED from com.android.support:support-v4:22.2.0:22:5\nMERGED from com.google.android.gms:play-services-appinvite:7.5.0:20:5\nMERGED from com.google.android.gms:play-services-base:7.5.0:20:5\nMERGED from com.android.support:support-v4:22.2.0:22:5\nMERGED from com.google.android.gms:play-services-appstate:7.5.0:19:5\nMERGED from com.google.android.gms:play-services-base:7.5.0:20:5\nMERGED from com.android.support:support-v4:22.2.0:22:5\nMERGED from com.google.android.gms:play-services-base:7.5.0:20:5\nMERGED from com.android.support:support-v4:22.2.0:22:5\nMERGED from com.google.android.gms:play-services-cast:7.5.0:19:5\nMERGED from com.google.android.gms:play-services-base:7.5.0:20:5\nMERGED from com.android.support:support-v4:22.2.0:22:5\nMERGED from com.android.support:mediarouter-v7:22.0.0:22:5\nMERGED from com.android.support:appcompat-v7:22.2.0:22:5\nMERGED from com.android.support:support-v4:22.2.0:22:5\nMERGED from com.google.android.gms:play-services-drive:7.5.0:19:5\nMERGED from com.google.android.gms:play-services-base:7.5.0:20:5\nMERGED from com.android.support:support-v4:22.2.0:22:5\nMERGED from com.google.android.gms:play-services-fitness:7.5.0:19:5\nMERGED from com.google.android.gms:play-services-base:7.5.0:20:5\nMERGED from com.android.support:support-v4:22.2.0:22:5\nMERGED from com.google.android.gms:play-services-location:7.5.0:19:5\nMERGED from com.google.android.gms:play-services-base:7.5.0:20:5\nMERGED from com.android.support:support-v4:22.2.0:22:5\nMERGED from com.google.android.gms:play-services-maps:7.5.0:29:5\nMERGED from com.google.android.gms:play-services-base:7.5.0:20:5\nMERGED from com.android.support:support-v4:22.2.0:22:5\nMERGED from com.google.android.gms:play-services-games:7.5.0:19:5\nMERGED from com.google.android.gms:play-services-base:7.5.0:20:5\nMERGED from com.android.support:support-v4:22.2.0:22:5\nMERGED from com.google.android.gms:play-services-drive:7.5.0:19:5\nMERGED from com.google.android.gms:play-services-base:7.5.0:20:5\nMERGED from com.android.support:support-v4:22.2.0:22:5\nMERGED from com.google.android.gms:play-services-gcm:7.5.0:19:5\nMERGED from com.google.android.gms:play-services-base:7.5.0:20:5\nMERGED from com.android.support:support-v4:22.2.0:22:5\nMERGED from com.google.android.gms:play-services-identity:7.5.0:19:5\nMERGED from com.google.android.gms:play-services-base:7.5.0:20:5\nMERGED from com.android.support:support-v4:22.2.0:22:5\nMERGED from com.google.android.gms:play-services-location:7.5.0:19:5\nMERGED from com.google.android.gms:play-services-base:7.5.0:20:5\nMERGED from com.android.support:support-v4:22.2.0:22:5\nMERGED from com.google.android.gms:play-services-maps:7.5.0:29:5\nMERGED from com.google.android.gms:play-services-base:7.5.0:20:5\nMERGED from com.android.support:support-v4:22.2.0:22:5\nMERGED from com.google.android.gms:play-services-maps:7.5.0:29:5\nMERGED from com.google.android.gms:play-services-base:7.5.0:20:5\nMERGED from com.android.support:support-v4:22.2.0:22:5\nMERGED from com.google.android.gms:play-services-nearby:7.5.0:20:5\nMERGED from com.google.android.gms:play-services-base:7.5.0:20:5\nMERGED from com.android.support:support-v4:22.2.0:22:5\nMERGED from com.google.android.gms:play-services-panorama:7.5.0:19:5\nMERGED from com.google.android.gms:play-services-base:7.5.0:20:5\nMERGED from com.android.support:support-v4:22.2.0:22:5\nMERGED from com.google.android.gms:play-services-plus:7.5.0:19:5\nMERGED from com.google.android.gms:play-services-base:7.5.0:20:5\nMERGED from com.android.support:support-v4:22.2.0:22:5\nMERGED from com.google.android.gms:play-services-safetynet:7.5.0:19:5\nMERGED from com.google.android.gms:play-services-base:7.5.0:20:5\nMERGED from com.android.support:support-v4:22.2.0:22:5\nMERGED from com.google.android.gms:play-services-wallet:7.5.0:24:5\nMERGED from com.google.android.gms:play-services-base:7.5.0:20:5\nMERGED from com.android.support:support-v4:22.2.0:22:5\nMERGED from com.google.android.gms:play-services-identity:7.5.0:19:5\nMERGED from com.google.android.gms:play-services-base:7.5.0:20:5\nMERGED from com.android.support:support-v4:22.2.0:22:5\nMERGED from com.google.android.gms:play-services-maps:7.5.0:29:5\nMERGED from com.google.android.gms:play-services-base:7.5.0:20:5\nMERGED from com.android.support:support-v4:22.2.0:22:5\nMERGED from com.google.android.gms:play-services-wearable:7.5.0:19:5\nMERGED from com.google.android.gms:play-services-base:7.5.0:20:5\nMERGED from com.android.support:support-v4:22.2.0:22:5\nMERGED from master-crm:intro-slider-lib:unspecified:11:5\nMERGED from com.android.support:support-v4:22.2.0:22:5\nMERGED from master-crm:parallax-effect-lib:unspecified:11:5\nMERGED from master-crm:odoo-rpc-v2:unspecified:20:5\nMERGED from master-crm:calendar-lib:unspecified:11:5\nMERGED from master-crm:bottom-sheet-lib:unspecified:11:5\nMERGED from master-crm:snackbar-lib:unspecified:11:5\n\tandroid:label\n\t\tADDED from AndroidManifest.xml:35:9\n\tandroid:allowBackup\n\t\tADDED from AndroidManifest.xml:32:9\n\tandroid:icon\n\t\tADDED from AndroidManifest.xml:34:9\n\tandroid:theme\n\t\tADDED from AndroidManifest.xml:37:9\n\tandroid:hardwareAccelerated\n\t\tADDED from AndroidManifest.xml:33:9\n\tandroid:largeHeap\n\t\tADDED from AndroidManifest.xml:36:9\n\tandroid:name\n\t\tADDED from AndroidManifest.xml:31:9\nactivity#com.odoo.core.account.OdooLogin\nADDED from AndroidManifest.xml:38:9\n\tandroid:screenOrientation\n\t\tADDED from AndroidManifest.xml:40:13\n\tandroid:name\n\t\tADDED from AndroidManifest.xml:39:13\nintent-filter#android.intent.action.MAIN+android.intent.category.LAUNCHER\nADDED from AndroidManifest.xml:41:13\naction#android.intent.action.MAIN\nADDED from AndroidManifest.xml:42:17\n\tandroid:name\n\t\tADDED from AndroidManifest.xml:42:25\ncategory#android.intent.category.LAUNCHER\nADDED from AndroidManifest.xml:44:17\n\tandroid:name\n\t\tADDED from AndroidManifest.xml:44:27\nactivity#com.odoo.core.account.ManageAccounts\nADDED from AndroidManifest.xml:47:9\n\tandroid:name\n\t\tADDED from AndroidManifest.xml:47:19\nactivity#com.odoo.OdooActivity\nADDED from AndroidManifest.xml:48:9\n\tandroid:name\n\t\tADDED from AndroidManifest.xml:48:19\nactivity#odoo.controls.SearchableItemActivity\nADDED from AndroidManifest.xml:49:9\n\tandroid:name\n\t\tADDED from AndroidManifest.xml:49:19\nactivity#com.odoo.SettingsActivity\nADDED from AndroidManifest.xml:50:9\n\tandroid:name\n\t\tADDED from AndroidManifest.xml:50:19\nactivity#com.odoo.core.account.AppIntro\nADDED from AndroidManifest.xml:51:9\n\tandroid:screenOrientation\n\t\tADDED from AndroidManifest.xml:53:13\n\tandroid:name\n\t\tADDED from AndroidManifest.xml:52:13\nactivity#com.odoo.base.addons.mail.widget.MailDetailDialog\nADDED from AndroidManifest.xml:54:9\n\tandroid:theme\n\t\tADDED from AndroidManifest.xml:56:13\n\tandroid:name\n\t\tADDED from AndroidManifest.xml:55:13\nactivity#com.odoo.base.addons.mail.widget.MailChatterCompose\nADDED from AndroidManifest.xml:57:9\n\tandroid:theme\n\t\tADDED from AndroidManifest.xml:59:13\n\tandroid:name\n\t\tADDED from AndroidManifest.xml:58:13\nactivity#com.odoo.core.account.OdooAccountQuickManage\nADDED from AndroidManifest.xml:60:9\n\tandroid:windowSoftInputMode\n\t\tADDED from AndroidManifest.xml:61:13\n\tandroid:theme\n\t\tADDED from AndroidManifest.xml:63:13\n\tandroid:name\n\t\tADDED from AndroidManifest.xml:62:13\nactivity#com.odoo.core.account.About\nADDED from AndroidManifest.xml:64:9\n\tandroid:name\n\t\tADDED from AndroidManifest.xml:64:19\nactivity#com.odoo.core.account.Profile\nADDED from AndroidManifest.xml:65:9\n\tandroid:name\n\t\tADDED from AndroidManifest.xml:65:19\nreceiver#com.odoo.core.utils.reminder.ReminderReceiver\nADDED from AndroidManifest.xml:68:9\n\tandroid:name\n\t\tADDED from AndroidManifest.xml:68:19\nreceiver#com.odoo.core.utils.reminder.ReminderActionReceiver\nADDED from AndroidManifest.xml:69:9\n\tandroid:name\n\t\tADDED from AndroidManifest.xml:69:19\nreceiver#com.odoo.news.OdooNewsReceiver\nADDED from AndroidManifest.xml:70:9\n\tandroid:name\n\t\tADDED from AndroidManifest.xml:70:19\nintent-filter#odoo.Odoo.ACTION_ODOO_UPDATES\nADDED from AndroidManifest.xml:71:13\naction#odoo.Odoo.ACTION_ODOO_UPDATES\nADDED from AndroidManifest.xml:72:17\n\tandroid:name\n\t\tADDED from AndroidManifest.xml:72:25\nreceiver#com.odoo.server.notifications.OdooServerNotificationReceiver\nADDED from AndroidManifest.xml:76:9\n\tandroid:name\n\t\tADDED from AndroidManifest.xml:76:19\nintent-filter#com.odoo.odoo.mobile.SERVER_NOTIFICATION\nADDED from AndroidManifest.xml:77:13\naction#com.odoo.odoo.mobile.SERVER_NOTIFICATION\nADDED from AndroidManifest.xml:78:17\n\tandroid:name\n\t\tADDED from AndroidManifest.xml:78:25\nservice#com.odoo.core.auth.OdooAuthService\nADDED from AndroidManifest.xml:82:9\n\tandroid:name\n\t\tADDED from AndroidManifest.xml:82:18\nintent-filter#android.accounts.AccountAuthenticator\nADDED from AndroidManifest.xml:83:13\naction#android.accounts.AccountAuthenticator\nADDED from AndroidManifest.xml:84:17\n\tandroid:name\n\t\tADDED from AndroidManifest.xml:84:25\nmeta-data#android.accounts.AccountAuthenticator\nADDED from AndroidManifest.xml:87:13\n\tandroid:resource\n\t\tADDED from AndroidManifest.xml:89:17\n\tandroid:name\n\t\tADDED from AndroidManifest.xml:88:17\nprovider#com.odoo.core.orm.provider.BaseModelProvider\nADDED from AndroidManifest.xml:92:9\n\tandroid:multiprocess\n\t\tADDED from AndroidManifest.xml:95:13\n\tandroid:authorities\n\t\tADDED from AndroidManifest.xml:94:13\n\tandroid:name\n\t\tADDED from AndroidManifest.xml:93:13\nprovider#com.odoo.base.addons.ir.providers.IrModelProvider\nADDED from AndroidManifest.xml:96:9\n\tandroid:multiprocess\n\t\tADDED from AndroidManifest.xml:99:13\n\tandroid:authorities\n\t\tADDED from AndroidManifest.xml:98:13\n\tandroid:name\n\t\tADDED from AndroidManifest.xml:97:13\nprovider#com.odoo.addons.customers.providers.CustomersSyncProvider\nADDED from AndroidManifest.xml:102:9\n\tandroid:label\n\t\tADDED from AndroidManifest.xml:105:13\n\tandroid:multiprocess\n\t\tADDED from AndroidManifest.xml:106:13\n\tandroid:authorities\n\t\tADDED from AndroidManifest.xml:104:13\n\tandroid:name\n\t\tADDED from AndroidManifest.xml:103:13\nservice#com.odoo.addons.customers.services.CustomerSyncService\nADDED from AndroidManifest.xml:108:9\n\tandroid:process\n\t\tADDED from AndroidManifest.xml:111:13\n\tandroid:exported\n\t\tADDED from AndroidManifest.xml:110:13\n\tandroid:name\n\t\tADDED from AndroidManifest.xml:109:13\nintent-filter#android.content.SyncAdapter\nADDED from AndroidManifest.xml:112:13\naction#android.content.SyncAdapter\nADDED from AndroidManifest.xml:113:17\n\tandroid:name\n\t\tADDED from AndroidManifest.xml:113:25\nmeta-data#android.content.SyncAdapter\nADDED from AndroidManifest.xml:116:13\n\tandroid:resource\n\t\tADDED from AndroidManifest.xml:118:17\n\tandroid:name\n\t\tADDED from AndroidManifest.xml:117:17\nprovider#com.odoo.addons.calendar.providers.CalendarSyncProvider\nADDED from AndroidManifest.xml:121:9\n\tandroid:label\n\t\tADDED from AndroidManifest.xml:124:13\n\tandroid:multiprocess\n\t\tADDED from AndroidManifest.xml:125:13\n\tandroid:authorities\n\t\tADDED from AndroidManifest.xml:123:13\n\tandroid:name\n\t\tADDED from AndroidManifest.xml:122:13\nservice#com.odoo.addons.calendar.services.CalendarSyncService\nADDED from AndroidManifest.xml:127:9\n\tandroid:process\n\t\tADDED from AndroidManifest.xml:130:13\n\tandroid:exported\n\t\tADDED from AndroidManifest.xml:129:13\n\tandroid:name\n\t\tADDED from AndroidManifest.xml:128:13\nprovider#com.odoo.addons.crm.providers.CRMLeadProvider\nADDED from AndroidManifest.xml:140:9\n\tandroid:label\n\t\tADDED from AndroidManifest.xml:143:13\n\tandroid:multiprocess\n\t\tADDED from AndroidManifest.xml:144:13\n\tandroid:authorities\n\t\tADDED from AndroidManifest.xml:142:13\n\tandroid:name\n\t\tADDED from AndroidManifest.xml:141:13\nservice#com.odoo.addons.crm.services.CRMLeadSyncService\nADDED from AndroidManifest.xml:146:9\n\tandroid:process\n\t\tADDED from AndroidManifest.xml:149:13\n\tandroid:exported\n\t\tADDED from AndroidManifest.xml:148:13\n\tandroid:name\n\t\tADDED from AndroidManifest.xml:147:13\nprovider#com.odoo.addons.sale.providers.SaleOrderProvider\nADDED from AndroidManifest.xml:159:9\n\tandroid:label\n\t\tADDED from AndroidManifest.xml:162:13\n\tandroid:multiprocess\n\t\tADDED from AndroidManifest.xml:163:13\n\tandroid:authorities\n\t\tADDED from AndroidManifest.xml:161:13\n\tandroid:name\n\t\tADDED from AndroidManifest.xml:160:13\nservice#com.odoo.addons.sale.services.SaleOrderSyncService\nADDED from AndroidManifest.xml:165:9\n\tandroid:process\n\t\tADDED from AndroidManifest.xml:168:13\n\tandroid:exported\n\t\tADDED from AndroidManifest.xml:167:13\n\tandroid:name\n\t\tADDED from AndroidManifest.xml:166:13\nprovider#com.odoo.addons.phonecall.providers.PhoneCallProvider\nADDED from AndroidManifest.xml:178:9\n\tandroid:label\n\t\tADDED from AndroidManifest.xml:181:13\n\tandroid:multiprocess\n\t\tADDED from AndroidManifest.xml:182:13\n\tandroid:authorities\n\t\tADDED from AndroidManifest.xml:180:13\n\tandroid:name\n\t\tADDED from AndroidManifest.xml:179:13\nservice#com.odoo.addons.phonecall.services.PhoneCallSyncService\nADDED from AndroidManifest.xml:184:9\n\tandroid:process\n\t\tADDED from AndroidManifest.xml:187:13\n\tandroid:exported\n\t\tADDED from AndroidManifest.xml:186:13\n\tandroid:name\n\t\tADDED from AndroidManifest.xml:185:13\nactivity#com.odoo.addons.calendar.EventDetail\nADDED from AndroidManifest.xml:197:9\n\tandroid:windowSoftInputMode\n\t\tADDED from AndroidManifest.xml:199:13\n\tandroid:name\n\t\tADDED from AndroidManifest.xml:198:13\nactivity#com.odoo.addons.customers.CustomerDetails\nADDED from AndroidManifest.xml:200:9\n\tandroid:windowSoftInputMode\n\t\tADDED from AndroidManifest.xml:202:13\n\tandroid:name\n\t\tADDED from AndroidManifest.xml:201:13\nactivity#com.odoo.addons.crm.CRMDetail\nADDED from AndroidManifest.xml:203:9\n\tandroid:windowSoftInputMode\n\t\tADDED from AndroidManifest.xml:205:13\n\tandroid:name\n\t\tADDED from AndroidManifest.xml:204:13\nactivity#com.odoo.addons.crm.ConvertToOpportunityWizard\nADDED from AndroidManifest.xml:206:9\n\tandroid:windowSoftInputMode\n\t\tADDED from AndroidManifest.xml:209:13\n\tandroid:theme\n\t\tADDED from AndroidManifest.xml:208:13\n\tandroid:name\n\t\tADDED from AndroidManifest.xml:207:13\nactivity#com.odoo.addons.crm.ConvertToQuotation\nADDED from AndroidManifest.xml:210:9\n\tandroid:windowSoftInputMode\n\t\tADDED from AndroidManifest.xml:213:13\n\tandroid:theme\n\t\tADDED from AndroidManifest.xml:212:13\n\tandroid:name\n\t\tADDED from AndroidManifest.xml:211:13\nactivity#com.odoo.addons.phonecall.PhoneCallDetail\nADDED from AndroidManifest.xml:214:9\n\tandroid:windowSoftInputMode\n\t\tADDED from AndroidManifest.xml:216:13\n\tandroid:name\n\t\tADDED from AndroidManifest.xml:215:13\nactivity#com.odoo.addons.sale.SalesDetail\nADDED from AndroidManifest.xml:217:9\n\tandroid:windowSoftInputMode\n\t\tADDED from AndroidManifest.xml:220:13\n\tandroid:screenOrientation\n\t\tADDED from AndroidManifest.xml:219:13\n\tandroid:name\n\t\tADDED from AndroidManifest.xml:218:13\nreceiver#com.odoo.addons.phonecall.features.receivers.PhoneStateReceiver\nADDED from AndroidManifest.xml:222:9\n\tandroid:name\n\t\tADDED from AndroidManifest.xml:222:19\nintent-filter#android.intent.action.PHONE_STATE\nADDED from AndroidManifest.xml:223:13\naction#android.intent.action.PHONE_STATE\nADDED from AndroidManifest.xml:224:17\n\tandroid:name\n\t\tADDED from AndroidManifest.xml:224:25\nintent-filter#android.intent.action.NEW_OUTGOING_CALL\nADDED from AndroidManifest.xml:226:13\naction#android.intent.action.NEW_OUTGOING_CALL\nADDED from AndroidManifest.xml:227:17\n\tandroid:name\n\t\tADDED from AndroidManifest.xml:227:25\nactivity#com.odoo.addons.sale.AddProductLineWizard\nADDED from AndroidManifest.xml:231:9\n\tandroid:windowSoftInputMode\n\t\tADDED from AndroidManifest.xml:233:13\n\tandroid:name\n\t\tADDED from AndroidManifest.xml:232:13\nuses-sdk\nINJECTED from AndroidManifest.xml:0:0 reason: use-sdk injection requested\nMERGED from com.android.support:appcompat-v7:22.2.0:20:5\nMERGED from com.android.support:support-v4:22.2.0:20:5\nMERGED from com.android.support:cardview-v7:22.0.0:20:5\nMERGED from com.google.android.gms:play-services:7.5.0:18:5\nMERGED from com.google.android.gms:play-services-ads:7.5.0:23:5\nMERGED from com.google.android.gms:play-services-base:7.5.0:18:5\nMERGED from com.android.support:support-v4:22.2.0:20:5\nMERGED from com.google.android.gms:play-services-analytics:7.5.0:18:5\nMERGED from com.google.android.gms:play-services-base:7.5.0:18:5\nMERGED from com.android.support:support-v4:22.2.0:20:5\nMERGED from com.google.android.gms:play-services-analytics:7.5.0:18:5\nMERGED from com.google.android.gms:play-services-base:7.5.0:18:5\nMERGED from com.android.support:support-v4:22.2.0:20:5\nMERGED from com.google.android.gms:play-services-appindexing:7.5.0:18:5\nMERGED from com.google.android.gms:play-services-base:7.5.0:18:5\nMERGED from com.android.support:support-v4:22.2.0:20:5\nMERGED from com.google.android.gms:play-services-appinvite:7.5.0:18:5\nMERGED from com.google.android.gms:play-services-base:7.5.0:18:5\nMERGED from com.android.support:support-v4:22.2.0:20:5\nMERGED from com.google.android.gms:play-services-appstate:7.5.0:18:5\nMERGED from com.google.android.gms:play-services-base:7.5.0:18:5\nMERGED from com.android.support:support-v4:22.2.0:20:5\nMERGED from com.google.android.gms:play-services-base:7.5.0:18:5\nMERGED from com.android.support:support-v4:22.2.0:20:5\nMERGED from com.google.android.gms:play-services-cast:7.5.0:18:5\nMERGED from com.google.android.gms:play-services-base:7.5.0:18:5\nMERGED from com.android.support:support-v4:22.2.0:20:5\nMERGED from com.android.support:mediarouter-v7:22.0.0:20:5\nMERGED from com.android.support:appcompat-v7:22.2.0:20:5\nMERGED from com.android.support:support-v4:22.2.0:20:5\nMERGED from com.google.android.gms:play-services-drive:7.5.0:18:5\nMERGED from com.google.android.gms:play-services-base:7.5.0:18:5\nMERGED from com.android.support:support-v4:22.2.0:20:5\nMERGED from com.google.android.gms:play-services-fitness:7.5.0:18:5\nMERGED from com.google.android.gms:play-services-base:7.5.0:18:5\nMERGED from com.android.support:support-v4:22.2.0:20:5\nMERGED from com.google.android.gms:play-services-location:7.5.0:18:5\nMERGED from com.google.android.gms:play-services-base:7.5.0:18:5\nMERGED from com.android.support:support-v4:22.2.0:20:5\nMERGED from com.google.android.gms:play-services-maps:7.5.0:28:5\nMERGED from com.google.android.gms:play-services-base:7.5.0:18:5\nMERGED from com.android.support:support-v4:22.2.0:20:5\nMERGED from com.google.android.gms:play-services-games:7.5.0:18:5\nMERGED from com.google.android.gms:play-services-base:7.5.0:18:5\nMERGED from com.android.support:support-v4:22.2.0:20:5\nMERGED from com.google.android.gms:play-services-drive:7.5.0:18:5\nMERGED from com.google.android.gms:play-services-base:7.5.0:18:5\nMERGED from com.android.support:support-v4:22.2.0:20:5\nMERGED from com.google.android.gms:play-services-gcm:7.5.0:18:5\nMERGED from com.google.android.gms:play-services-base:7.5.0:18:5\nMERGED from com.android.support:support-v4:22.2.0:20:5\nMERGED from com.google.android.gms:play-services-identity:7.5.0:18:5\nMERGED from com.google.android.gms:play-services-base:7.5.0:18:5\nMERGED from com.android.support:support-v4:22.2.0:20:5\nMERGED from com.google.android.gms:play-services-location:7.5.0:18:5\nMERGED from com.google.android.gms:play-services-base:7.5.0:18:5\nMERGED from com.android.support:support-v4:22.2.0:20:5\nMERGED from com.google.android.gms:play-services-maps:7.5.0:28:5\nMERGED from com.google.android.gms:play-services-base:7.5.0:18:5\nMERGED from com.android.support:support-v4:22.2.0:20:5\nMERGED from com.google.android.gms:play-services-maps:7.5.0:28:5\nMERGED from com.google.android.gms:play-services-base:7.5.0:18:5\nMERGED from com.android.support:support-v4:22.2.0:20:5\nMERGED from com.google.android.gms:play-services-nearby:7.5.0:18:5\nMERGED from com.google.android.gms:play-services-base:7.5.0:18:5\nMERGED from com.android.support:support-v4:22.2.0:20:5\nMERGED from com.google.android.gms:play-services-panorama:7.5.0:18:5\nMERGED from com.google.android.gms:play-services-base:7.5.0:18:5\nMERGED from com.android.support:support-v4:22.2.0:20:5\nMERGED from com.google.android.gms:play-services-plus:7.5.0:18:5\nMERGED from com.google.android.gms:play-services-base:7.5.0:18:5\nMERGED from com.android.support:support-v4:22.2.0:20:5\nMERGED from com.google.android.gms:play-services-safetynet:7.5.0:18:5\nMERGED from com.google.android.gms:play-services-base:7.5.0:18:5\nMERGED from com.android.support:support-v4:22.2.0:20:5\nMERGED from com.google.android.gms:play-services-wallet:7.5.0:19:5\nMERGED from com.google.android.gms:play-services-base:7.5.0:18:5\nMERGED from com.android.support:support-v4:22.2.0:20:5\nMERGED from com.google.android.gms:play-services-identity:7.5.0:18:5\nMERGED from com.google.android.gms:play-services-base:7.5.0:18:5\nMERGED from com.android.support:support-v4:22.2.0:20:5\nMERGED from com.google.android.gms:play-services-maps:7.5.0:28:5\nMERGED from com.google.android.gms:play-services-base:7.5.0:18:5\nMERGED from com.android.support:support-v4:22.2.0:20:5\nMERGED from com.google.android.gms:play-services-wearable:7.5.0:18:5\nMERGED from com.google.android.gms:play-services-base:7.5.0:18:5\nMERGED from com.android.support:support-v4:22.2.0:20:5\nMERGED from master-crm:intro-slider-lib:unspecified:7:5\nMERGED from com.android.support:support-v4:22.2.0:20:5\nMERGED from master-crm:parallax-effect-lib:unspecified:7:5\nMERGED from master-crm:odoo-rpc-v2:unspecified:7:5\nMERGED from master-crm:calendar-lib:unspecified:7:5\nMERGED from master-crm:bottom-sheet-lib:unspecified:7:5\nMERGED from master-crm:snackbar-lib:unspecified:7:5\n\tandroid:targetSdkVersion\n\t\tINJECTED from AndroidManifest.xml:0:0\n\t\tINJECTED from AndroidManifest.xml:0:0\n\tandroid:minSdkVersion\n\t\tINJECTED from AndroidManifest.xml:0:0\n\t\tINJECTED from AndroidManifest.xml:0:0\nactivity#com.google.android.gms.ads.AdActivity\nADDED from com.google.android.gms:play-services-ads:7.5.0:26:9\n\tandroid:configChanges\n\t\tADDED from com.google.android.gms:play-services-ads:7.5.0:28:13\n\tandroid:theme\n\t\tADDED from com.google.android.gms:play-services-ads:7.5.0:29:13\n\tandroid:name\n\t\tADDED from com.google.android.gms:play-services-ads:7.5.0:27:13\nactivity#com.google.android.gms.ads.purchase.InAppPurchaseActivity\nADDED from com.google.android.gms:play-services-ads:7.5.0:30:9\n\tandroid:theme\n\t\tADDED from com.google.android.gms:play-services-ads:7.5.0:31:13\n\tandroid:name\n\t\tADDED from com.google.android.gms:play-services-ads:7.5.0:30:19\nmeta-data#com.google.android.gms.version\nADDED from com.google.android.gms:play-services-base:7.5.0:21:9\nMERGED from com.google.android.gms:play-services-base:7.5.0:21:9\nMERGED from com.google.android.gms:play-services-base:7.5.0:21:9\nMERGED from com.google.android.gms:play-services-base:7.5.0:21:9\nMERGED from com.google.android.gms:play-services-base:7.5.0:21:9\nMERGED from com.google.android.gms:play-services-base:7.5.0:21:9\nMERGED from com.google.android.gms:play-services-base:7.5.0:21:9\nMERGED from com.google.android.gms:play-services-base:7.5.0:21:9\nMERGED from com.google.android.gms:play-services-base:7.5.0:21:9\nMERGED from com.google.android.gms:play-services-base:7.5.0:21:9\nMERGED from com.google.android.gms:play-services-base:7.5.0:21:9\nMERGED from com.google.android.gms:play-services-base:7.5.0:21:9\nMERGED from com.google.android.gms:play-services-base:7.5.0:21:9\nMERGED from com.google.android.gms:play-services-base:7.5.0:21:9\nMERGED from com.google.android.gms:play-services-base:7.5.0:21:9\nMERGED from com.google.android.gms:play-services-base:7.5.0:21:9\nMERGED from com.google.android.gms:play-services-base:7.5.0:21:9\nMERGED from com.google.android.gms:play-services-base:7.5.0:21:9\nMERGED from com.google.android.gms:play-services-base:7.5.0:21:9\nMERGED from com.google.android.gms:play-services-base:7.5.0:21:9\nMERGED from com.google.android.gms:play-services-base:7.5.0:21:9\nMERGED from com.google.android.gms:play-services-base:7.5.0:21:9\nMERGED from com.google.android.gms:play-services-base:7.5.0:21:9\nMERGED from com.google.android.gms:play-services-base:7.5.0:21:9\nMERGED from com.google.android.gms:play-services-base:7.5.0:21:9\nMERGED from com.google.android.gms:play-services-base:7.5.0:21:9\nMERGED from com.google.android.gms:play-services-base:7.5.0:21:9\n\tandroid:name\n\t\tADDED from com.google.android.gms:play-services-base:7.5.0:22:13\n\tandroid:value\n\t\tADDED from com.google.android.gms:play-services-base:7.5.0:23:13\nuses-permission#android.permission.ACCESS_COARSE_LOCATION\nADDED from com.google.android.gms:play-services-maps:7.5.0:23:5\nMERGED from com.google.android.gms:play-services-maps:7.5.0:23:5\nMERGED from com.google.android.gms:play-services-maps:7.5.0:23:5\nMERGED from com.google.android.gms:play-services-maps:7.5.0:23:5\n\tandroid:name\n\t\tADDED from com.google.android.gms:play-services-maps:7.5.0:23:22\nuses-feature#0x00020000\nADDED from com.google.android.gms:play-services-maps:7.5.0:24:5\nMERGED from com.google.android.gms:play-services-maps:7.5.0:24:5\nMERGED from com.google.android.gms:play-services-maps:7.5.0:24:5\nMERGED from com.google.android.gms:play-services-maps:7.5.0:24:5\n\tandroid:required\n\t\tADDED from com.google.android.gms:play-services-maps:7.5.0:26:8\n\tandroid:glEsVersion\n\t\tADDED from com.google.android.gms:play-services-maps:7.5.0:25:8\nmeta-data#com.google.android.gms.wallet.api.enabled\nADDED from com.google.android.gms:play-services-wallet:7.5.0:25:9\n\tandroid:name\n\t\tADDED from com.google.android.gms:play-services-wallet:7.5.0:26:13\n\tandroid:value\n\t\tADDED from com.google.android.gms:play-services-wallet:7.5.0:27:13\nreceiver#com.google.android.gms.wallet.EnableWalletOptimizationReceiver\nADDED from com.google.android.gms:play-services-wallet:7.5.0:28:9\n\tandroid:exported\n\t\tADDED from com.google.android.gms:play-services-wallet:7.5.0:30:13\n\tandroid:name\n\t\tADDED from com.google.android.gms:play-services-wallet:7.5.0:29:13\nintent-filter#com.google.android.gms.wallet.ENABLE_WALLET_OPTIMIZATION\nADDED from com.google.android.gms:play-services-wallet:7.5.0:31:13\naction#com.google.android.gms.wallet.ENABLE_WALLET_OPTIMIZATION\nADDED from com.google.android.gms:play-services-wallet:7.5.0:32:17\n\tandroid:name\n\t\tADDED from com.google.android.gms:play-services-wallet:7.5.0:32:25\nuses-permission#android.permission.CAMERA\nADDED from master-crm:odoo-rpc-v2:unspecified:18:5\n\tandroid:name\n\t\tADDED from master-crm:odoo-rpc-v2:unspecified:18:22\nreceiver#odoo.kernel.handler.ActionHandler\nADDED from master-crm:odoo-rpc-v2:unspecified:24:9\n\tandroid:permission\n\t\tADDED from master-crm:odoo-rpc-v2:unspecified:26:13\n\tandroid:name\n\t\tADDED from master-crm:odoo-rpc-v2:unspecified:25:13\nintent-filter#com.google.android.c2dm.intent.RECEIVE+com.google.android.c2dm.intent.REGISTRATION\nADDED from master-crm:odoo-rpc-v2:unspecified:27:13\naction#com.google.android.c2dm.intent.RECEIVE\nADDED from master-crm:odoo-rpc-v2:unspecified:28:17\n\tandroid:name\n\t\tADDED from master-crm:odoo-rpc-v2:unspecified:28:25\naction#com.google.android.c2dm.intent.REGISTRATION\nADDED from master-crm:odoo-rpc-v2:unspecified:29:17\n\tandroid:name\n\t\tADDED from master-crm:odoo-rpc-v2:unspecified:29:25\nservice#odoo.kernel.handler.ActionHandlerService\nADDED from master-crm:odoo-rpc-v2:unspecified:33:9\n\tandroid:name\n\t\tADDED from master-crm:odoo-rpc-v2:unspecified:33:18\nactivity#odoo.zxing.handler.OdooMobileQRReader\nADDED from master-crm:odoo-rpc-v2:unspecified:35:9\n\tandroid:screenOrientation\n\t\tADDED from master-crm:odoo-rpc-v2:unspecified:37:13\n\tandroid:name\n\t\tADDED from master-crm:odoo-rpc-v2:unspecified:36:13\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/dpr/eclipse-adt/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"
  },
  {
    "path": "app/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.odoo\">\n\n    <uses-permission android:name=\"android.permission.INTERNET\" />\n    <uses-permission android:name=\"android.permission.VIBRATE\" />\n    <uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\" />\n    <uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\" />\n    <uses-permission android:name=\"android.permission.GET_TASKS\" />\n    <uses-permission android:name=\"android.permission.AUTHENTICATE_ACCOUNTS\" />\n    <uses-permission android:name=\"android.permission.GET_ACCOUNTS\" />\n    <uses-permission android:name=\"android.permission.USE_CREDENTIALS\" />\n    <uses-permission android:name=\"android.permission.MANAGE_ACCOUNTS\" />\n    <uses-permission android:name=\"android.permission.READ_SYNC_SETTINGS\" />\n    <uses-permission android:name=\"android.permission.READ_SYNC_STATS\" />\n    <uses-permission android:name=\"android.permission.WRITE_SYNC_SETTINGS\" />\n    <uses-permission android:name=\"android.permission.WAKE_LOCK\" />\n    <uses-permission android:name=\"com.google.android.c2dm.permission.RECEIVE\" />\n    <uses-permission android:name=\"android.permission.READ_PHONE_STATE\" />\n    <uses-permission android:name=\"android.permission.SYSTEM_ALERT_WINDOW\" />\n    <uses-permission android:name=\"android.permission.CALL_PHONE\" />\n    <uses-permission android:name=\"android.permission.READ_EXTERNAL_STORAGE\" />\n    <uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\" />\n    <uses-permission android:name=\"android.permission.MANAGE_DOCUMENTS\" />\n\n    <permission\n        android:name=\"com.odoo.crm.permission.C2D_MESSAGE\"\n        android:protectionLevel=\"signature\" />\n\n    <application\n        android:name=\"com.odoo.App\"\n        android:allowBackup=\"true\"\n        android:hardwareAccelerated=\"true\"\n        android:icon=\"@drawable/ic_launcher\"\n        android:label=\"@string/app_name\"\n        android:largeHeap=\"true\"\n        android:theme=\"@style/AppTheme\">\n        <activity\n            android:name=\"com.odoo.core.account.OdooLogin\"\n            android:screenOrientation=\"portrait\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.MAIN\" />\n\n                <category android:name=\"android.intent.category.LAUNCHER\" />\n            </intent-filter>\n        </activity>\n        <activity android:name=\"com.odoo.core.account.ManageAccounts\" />\n        <activity android:name=\"com.odoo.OdooActivity\" />\n        <activity android:name=\"odoo.controls.SearchableItemActivity\" />\n        <activity android:name=\"com.odoo.SettingsActivity\" />\n        <activity\n            android:name=\"com.odoo.core.account.AppIntro\"\n            android:screenOrientation=\"portrait\" />\n        <activity\n            android:name=\".base.addons.mail.widget.MailDetailDialog\"\n            android:theme=\"@style/Theme.AppCompat.Light.Dialog\" />\n        <activity\n            android:name=\".base.addons.mail.widget.MailChatterCompose\"\n            android:theme=\"@style/Theme.AppCompat.Light.Dialog\" />\n        <activity\n            android:windowSoftInputMode=\"adjustPan\"\n            android:name=\"com.odoo.core.account.OdooAccountQuickManage\"\n            android:theme=\"@style/Theme.AppCompat.Light.Dialog\" />\n        <activity android:name=\"com.odoo.core.account.About\" />\n        <activity android:name=\"com.odoo.core.account.Profile\" />\n\n        <!-- Reminder Receivers// -->\n        <receiver android:name=\"com.odoo.core.utils.reminder.ReminderReceiver\" />\n        <receiver android:name=\"com.odoo.core.utils.reminder.ReminderActionReceiver\" />\n        <receiver android:name=\".news.OdooNewsReceiver\">\n            <intent-filter>\n                <action android:name=\"odoo.Odoo.ACTION_ODOO_UPDATES\" />\n            </intent-filter>\n        </receiver>\n        \n        <receiver android:name=\".server.notifications.OdooServerNotificationReceiver\">\n            <intent-filter>\n                <action android:name=\"com.odoo.odoo.mobile.SERVER_NOTIFICATION\" />\n            </intent-filter>\n        </receiver>\n\n        <service android:name=\"com.odoo.core.auth.OdooAuthService\">\n            <intent-filter>\n                <action android:name=\"android.accounts.AccountAuthenticator\" />\n            </intent-filter>\n\n            <meta-data\n                android:name=\"android.accounts.AccountAuthenticator\"\n                android:resource=\"@xml/authenticator\" />\n        </service>\n\n        <provider\n            android:name=\"com.odoo.core.orm.provider.BaseModelProvider\"\n            android:authorities=\"com.odoo.crm.core.provider.content\"\n            android:multiprocess=\"true\" />\n        <provider\n            android:name=\"com.odoo.base.addons.ir.providers.IrModelProvider\"\n            android:authorities=\"com.odoo.crm.core.provider.content.sync.ir_model\"\n            android:multiprocess=\"true\" />\n\n        <!-- Sync Provider & Service  // -->\n        <provider\n            android:name=\"com.odoo.addons.customers.providers.CustomersSyncProvider\"\n            android:authorities=\"com.odoo.core.crm.provider.content.sync.res_partner\"\n            android:label=\"@string/sync_label_customers\"\n            android:multiprocess=\"true\" />\n\n        <service\n            android:name=\"com.odoo.addons.customers.services.CustomerSyncService\"\n            android:exported=\"true\"\n            android:process=\":sync_customer\">\n            <intent-filter>\n                <action android:name=\"android.content.SyncAdapter\" />\n            </intent-filter>\n\n            <meta-data\n                android:name=\"android.content.SyncAdapter\"\n                android:resource=\"@xml/customer_sync_adapter\" />\n        </service>\n\n        <provider\n            android:name=\"com.odoo.addons.calendar.providers.CalendarSyncProvider\"\n            android:authorities=\"com.odoo.core.crm.provider.content.sync.calendar_event\"\n            android:label=\"@string/sync_label_calendar\"\n            android:multiprocess=\"true\" />\n\n        <service\n            android:name=\"com.odoo.addons.calendar.services.CalendarSyncService\"\n            android:exported=\"true\"\n            android:process=\":sync_agenda\">\n            <intent-filter>\n                <action android:name=\"android.content.SyncAdapter\" />\n            </intent-filter>\n\n            <meta-data\n                android:name=\"android.content.SyncAdapter\"\n                android:resource=\"@xml/calendar_sync_adapter\" />\n        </service>\n\n        <provider\n            android:name=\"com.odoo.addons.crm.providers.CRMLeadProvider\"\n            android:authorities=\"com.odoo.core.crm.provider.content.sync.crm_lead\"\n            android:label=\"@string/sync_label_lead_opportunities\"\n            android:multiprocess=\"true\" />\n\n        <service\n            android:name=\"com.odoo.addons.crm.services.CRMLeadSyncService\"\n            android:exported=\"true\"\n            android:process=\":sync_leads\">\n            <intent-filter>\n                <action android:name=\"android.content.SyncAdapter\" />\n            </intent-filter>\n\n            <meta-data\n                android:name=\"android.content.SyncAdapter\"\n                android:resource=\"@xml/crm_sync_adapter\" />\n        </service>\n\n        <provider\n            android:name=\"com.odoo.addons.sale.providers.SaleOrderProvider\"\n            android:authorities=\"com.odoo.core.crm.provider.content.sync.sale_order\"\n            android:label=\"@string/sync_label_quotation_sales_orders\"\n            android:multiprocess=\"true\" />\n\n        <service\n            android:name=\"com.odoo.addons.sale.services.SaleOrderSyncService\"\n            android:exported=\"true\"\n            android:process=\":sync_sale_orders\">\n            <intent-filter>\n                <action android:name=\"android.content.SyncAdapter\" />\n            </intent-filter>\n\n            <meta-data\n                android:name=\"android.content.SyncAdapter\"\n                android:resource=\"@xml/sale_sync_adapter\" />\n        </service>\n\n        <provider\n            android:name=\"com.odoo.addons.phonecall.providers.PhoneCallProvider\"\n            android:authorities=\"com.odoo.core.crm.provider.content.sync.crm_phonecall\"\n            android:label=\"@string/sync_label_phonecalls\"\n            android:multiprocess=\"true\" />\n\n        <service\n            android:name=\"com.odoo.addons.phonecall.services.PhoneCallSyncService\"\n            android:exported=\"true\"\n            android:process=\":sync_phone_calls\">\n            <intent-filter>\n                <action android:name=\"android.content.SyncAdapter\" />\n            </intent-filter>\n\n            <meta-data\n                android:name=\"android.content.SyncAdapter\"\n                android:resource=\"@xml/phonecall_sync_adapter\" />\n        </service>\n\n        <activity\n            android:name=\"com.odoo.addons.calendar.EventDetail\"\n            android:windowSoftInputMode=\"adjustPan\" />\n        <activity\n            android:name=\"com.odoo.addons.customers.CustomerDetails\"\n            android:windowSoftInputMode=\"adjustPan\" />\n        <activity\n            android:name=\"com.odoo.addons.crm.CRMDetail\"\n            android:windowSoftInputMode=\"adjustPan\" />\n        <activity\n            android:name=\"com.odoo.addons.crm.ConvertToOpportunityWizard\"\n            android:theme=\"@style/Theme.AppCompat.Light.Dialog\"\n            android:windowSoftInputMode=\"adjustPan\" />\n        <activity\n            android:name=\"com.odoo.addons.crm.ConvertToQuotation\"\n            android:theme=\"@style/Theme.AppCompat.Light.Dialog\"\n            android:windowSoftInputMode=\"adjustPan\" />\n        <activity\n            android:name=\"com.odoo.addons.phonecall.PhoneCallDetail\"\n            android:windowSoftInputMode=\"adjustPan\" />\n        <activity\n            android:name=\"com.odoo.addons.sale.SalesDetail\"\n            android:screenOrientation=\"portrait\"\n            android:windowSoftInputMode=\"adjustPan\" />\n        <!-- Phone state receiver// -->\n        <receiver android:name=\"com.odoo.addons.phonecall.features.receivers.PhoneStateReceiver\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.PHONE_STATE\" />\n            </intent-filter>\n            <intent-filter>\n                <action android:name=\"android.intent.action.NEW_OUTGOING_CALL\" />\n            </intent-filter>\n        </receiver>\n\n        <activity\n            android:name=\"com.odoo.addons.sale.AddProductLineWizard\"\n            android:windowSoftInputMode=\"adjustPan\" />\n\n    </application>\n\n</manifest>\n"
  },
  {
    "path": "app/src/main/java/com/odoo/App.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 17/12/14 6:06 PM\n */\npackage com.odoo;\n\nimport android.app.ActivityManager;\nimport android.app.Application;\nimport android.content.ComponentName;\nimport android.content.Context;\nimport android.content.pm.PackageManager;\nimport android.net.ConnectivityManager;\nimport android.net.NetworkInfo;\n\nimport com.odoo.core.support.OUser;\n\nimport java.util.HashMap;\nimport java.util.List;\n\nimport odoo.Odoo;\n\npublic class App extends Application {\n\n    public static final String TAG = App.class.getSimpleName();\n    private static HashMap<String, Odoo> mOdooInstances = new HashMap<>();\n\n    @Override\n    public void onCreate() {\n        super.onCreate();\n    }\n\n    public Odoo getOdoo(OUser user) {\n        if (mOdooInstances.containsKey(user.getAndroidName())) {\n            return mOdooInstances.get(user.getAndroidName());\n        }\n        return null;\n    }\n\n    public void setOdoo(Odoo odoo, OUser user) {\n        if (user != null)\n            mOdooInstances.put(user.getAndroidName(), odoo);\n    }\n\n    /**\n     * Checks for network availability\n     *\n     * @return true, if network available\n     */\n    public boolean inNetwork() {\n        boolean isConnected = false;\n        ConnectivityManager manager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);\n        NetworkInfo nInfo = manager.getActiveNetworkInfo();\n        if (nInfo != null && nInfo.isConnectedOrConnecting()) {\n            isConnected = true;\n        }\n        return isConnected;\n    }\n\n    /**\n     * Checks for installed application\n     *\n     * @param appPackage\n     * @return true, if application installed on device\n     */\n    public boolean appInstalled(String appPackage) {\n        boolean mInstalled = false;\n        try {\n            PackageManager mPackage = getPackageManager();\n            mPackage.getPackageInfo(appPackage, PackageManager.GET_ACTIVITIES);\n            mInstalled = true;\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return mInstalled;\n    }\n\n    /**\n     * Check for app is on top of screen\n     *\n     * @return true, if application is running on top\n     */\n    public boolean meOnTop() {\n        boolean meOnTop = false;\n        ActivityManager aManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);\n        List<ActivityManager.RunningTaskInfo> taskInfo = aManager.getRunningTasks(1);\n        ComponentName componentName = taskInfo.get(0).topActivity;\n        if (componentName.getPackageName().equalsIgnoreCase(getPackageName())) {\n            meOnTop = true;\n        }\n        return meOnTop;\n    }\n\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/OdooActivity.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 18/12/14 5:25 PM\n */\npackage com.odoo;\n\nimport android.animation.Animator;\nimport android.animation.AnimatorListenerAdapter;\nimport android.animation.AnimatorSet;\nimport android.animation.ObjectAnimator;\nimport android.app.Activity;\nimport android.content.Intent;\nimport android.content.res.Configuration;\nimport android.graphics.Bitmap;\nimport android.graphics.Typeface;\nimport android.os.Bundle;\nimport android.os.Handler;\nimport android.support.v4.app.Fragment;\nimport android.support.v4.widget.DrawerLayout;\nimport android.support.v7.app.ActionBar;\nimport android.support.v7.app.ActionBarActivity;\nimport android.support.v7.app.ActionBarDrawerToggle;\nimport android.util.Log;\nimport android.view.Gravity;\nimport android.view.LayoutInflater;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.widget.ImageView;\nimport android.widget.LinearLayout;\nimport android.widget.Spinner;\nimport android.widget.TextView;\n\nimport com.odoo.core.account.AppIntro;\nimport com.odoo.core.account.ManageAccounts;\nimport com.odoo.core.account.OdooLogin;\nimport com.odoo.core.account.OdooUserAskPassword;\nimport com.odoo.core.auth.OdooAccountManager;\nimport com.odoo.core.auth.OdooAuthenticator;\nimport com.odoo.core.orm.OModel;\nimport com.odoo.core.support.OUser;\nimport com.odoo.core.support.addons.fragment.IBaseFragment;\nimport com.odoo.core.support.drawer.ODrawerItem;\nimport com.odoo.core.support.sync.SyncUtils;\nimport com.odoo.core.utils.BitmapUtils;\nimport com.odoo.core.utils.OActionBarUtils;\nimport com.odoo.core.utils.OAlert;\nimport com.odoo.core.utils.OControls;\nimport com.odoo.core.utils.OFragmentUtils;\nimport com.odoo.core.utils.OPreferenceManager;\nimport com.odoo.core.utils.OResource;\nimport com.odoo.core.utils.drawer.DrawerUtils;\nimport com.odoo.core.utils.sys.IOnActivityResultListener;\nimport com.odoo.core.utils.sys.IOnBackPressListener;\nimport com.odoo.R;\n\nimport java.util.List;\n\npublic class OdooActivity extends ActionBarActivity {\n\n    public static final String TAG = OdooActivity.class.getSimpleName();\n    public static final Integer DRAWER_ITEM_LAUNCH_DELAY = 300;\n    public static final Integer DRAWER_ACCOUNT_BOX_ANIMATION_DURATION = 250;\n    public static final String KEY_ACCOUNT_REQUEST = \"key_account_request\";\n    public static final String KEY_NEW_USER_NAME = \"key_new_account_username\";\n    public static final String KEY_CURRENT_DRAWER_ITEM = \"key_drawer_item_index\";\n    public static final String KEY_APP_TITLE = \"key_app_title\";\n    public static final String KEY_HAS_ACTIONBAR_SPINNER = \"key_has_actionbar_spinner\";\n    public static final Integer REQUEST_ACCOUNT_CREATE = 1101;\n    public static final Integer REQUEST_ACCOUNTS_MANAGE = 1102;\n    public static final String KEY_FRESH_LOGIN = \"key_fresh_login\";\n\n    private DrawerLayout mDrawerLayout = null;\n    private ActionBarDrawerToggle mDrawerToggle = null;\n    private IOnBackPressListener backPressListener = null;\n    private IOnActivityResultListener mIOnActivityResultListener = null;\n    //Drawer Containers\n    private LinearLayout mDrawerAccountContainer = null;\n    private LinearLayout mDrawerItemContainer = null;\n    private Boolean mAccountBoxExpanded = false;\n    private Bundle mSavedInstanceState = null;\n    private Spinner spinner_nav = null;\n    private Integer mDrawerSelectedIndex = -1;\n    private Boolean mHasActionBarSpinner = false;\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        Log.i(TAG, \"OdooActivity->onCreate\");\n        mSavedInstanceState = savedInstanceState;\n        OPreferenceManager preferenceManager = new OPreferenceManager(this);\n        if (!preferenceManager.getBoolean(KEY_FRESH_LOGIN, false)) {\n            preferenceManager.setBoolean(KEY_FRESH_LOGIN, true);\n            new Handler().postDelayed(new Runnable() {\n                @Override\n                public void run() {\n                    startActivity(new Intent(OdooActivity.this, AppIntro.class));\n                }\n            }, 1000);\n        }\n        setContentView(R.layout.odoo_activity);\n        OActionBarUtils.setActionBar(this, true);\n        setupDrawer();\n    }\n\n    // Creating drawer\n    private void setupDrawer() {\n        mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);\n        mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout, R.string.app_name, R.string.app_name) {\n\n            @Override\n            public void onDrawerClosed(View drawerView) {\n                super.onDrawerClosed(drawerView);\n                setTitle(getResources().getString(R.string.app_name));\n                invalidateOptionsMenu();\n            }\n\n            @Override\n            public void onDrawerOpened(View drawerView) {\n                super.onDrawerOpened(drawerView);\n                invalidateOptionsMenu();\n                setTitle(R.string.app_name);\n            }\n\n            @Override\n            public void onDrawerStateChanged(int newState) {\n                super.onDrawerStateChanged(newState);\n                invalidateOptionsMenu();\n            }\n\n            @Override\n            public void onDrawerSlide(View drawerView, float slideOffset) {\n                super.onDrawerSlide(drawerView, slideOffset);\n                invalidateOptionsMenu();\n            }\n        };\n        mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow, Gravity.START);\n        mDrawerToggle.syncState();\n\n        setupAccountBox();\n        setupDrawerBox();\n    }\n\n    private void setupDrawerBox() {\n        mDrawerItemContainer = (LinearLayout) findViewById(R.id.drawerItemList);\n        mDrawerItemContainer.removeAllViews();\n        List<ODrawerItem> items = DrawerUtils.getDrawerItems(this);\n        for (ODrawerItem item : items) {\n            View view = LayoutInflater.from(this).\n                    inflate((item.isGroupTitle()) ? R.layout.base_drawer_group_layout :\n                            R.layout.base_drawer_menu_item, mDrawerItemContainer, false);\n            view.setTag(item);\n            if (!item.isGroupTitle()) {\n                view.setOnClickListener(drawerItemClick);\n            }\n            mDrawerItemContainer.addView(DrawerUtils.fillDrawerItemValue(view, item));\n        }\n    }\n\n    private View.OnClickListener drawerItemClick = new View.OnClickListener() {\n        @Override\n        public void onClick(View v) {\n            int index = mDrawerItemContainer.indexOfChild(v);\n            if (mDrawerSelectedIndex != index) {\n                ODrawerItem item = (ODrawerItem) v.getTag();\n                if (item.getInstance() instanceof Fragment) {\n                    focusOnDrawerItem(index);\n                    setTitle(item.getTitle());\n                }\n                loadDrawerItemInstance(item.getInstance(), item.getExtra());\n            } else {\n                closeDrawer();\n            }\n        }\n    };\n\n    public void closeDrawer() {\n        new Handler().postDelayed(new Runnable() {\n            @Override\n            public void run() {\n                mDrawerLayout.closeDrawer(Gravity.START);\n            }\n        }, DRAWER_ITEM_LAUNCH_DELAY);\n\n    }\n\n    /**\n     * Loads fragment or start intent\n     *\n     * @param instance, instance of fragment or intent\n     */\n    private void loadDrawerItemInstance(Object instance, Bundle extra) {\n        if (instance != null) {\n            if (instance instanceof Intent) {\n                Log.i(TAG, \"Loading intent: \" + instance.getClass().getCanonicalName());\n                startActivity((Intent) instance);\n            }\n            if (instance instanceof Class<?>) {\n                Class<?> cls = (Class<?>) instance;\n                Intent intent = null;\n                if (cls.getSuperclass().isAssignableFrom(Activity.class)) {\n                    intent = new Intent(this, cls);\n                }\n                if (cls.getSuperclass().isAssignableFrom(ActionBarActivity.class)) {\n                    intent = new Intent(this, cls);\n                }\n                if (intent != null) {\n                    if (extra != null)\n                        intent.putExtras(extra);\n                    loadDrawerItemInstance(intent, null);\n                    return;\n                }\n            }\n            if (instance instanceof Fragment) {\n                Log.i(TAG, \"Loading fragment: \" + instance.getClass().getCanonicalName());\n                OFragmentUtils.get(this, mSavedInstanceState).startFragment((Fragment) instance, false, extra);\n            }\n        }\n        closeDrawer();\n    }\n\n    public void loadFragment(Fragment fragment, Boolean addToBackState, Bundle extra) {\n        OFragmentUtils.get(this, null).startFragment(fragment, addToBackState, extra);\n    }\n\n    private void setupAccountBox() {\n        mDrawerAccountContainer = (LinearLayout) findViewById(R.id.accountList);\n        View chosenAccountView = findViewById(R.id.drawerAccountView);\n        OUser currentUser = OUser.current(this);\n        if (currentUser == null) {\n            chosenAccountView.setVisibility(View.GONE);\n            mDrawerAccountContainer.setVisibility(View.GONE);\n            return;\n        } else {\n            chosenAccountView.setVisibility(View.VISIBLE);\n            mDrawerAccountContainer.setVisibility(View.INVISIBLE);\n        }\n\n        ImageView avatar = (ImageView) chosenAccountView.findViewById(R.id.profile_image);\n        TextView name = (TextView) chosenAccountView.findViewById(R.id.profile_name_text);\n        TextView url = (TextView) chosenAccountView.findViewById(R.id.profile_url_text);\n\n        name.setText(currentUser.getName());\n        url.setText((currentUser.isOAauthLogin()) ? currentUser.getInstanceUrl() : currentUser.getHost());\n\n        if (!currentUser.getAvatar().equals(\"false\")) {\n            Bitmap bitmap = BitmapUtils.getBitmapImage(this, currentUser.getAvatar());\n            if (bitmap != null)\n                avatar.setImageBitmap(bitmap);\n        }\n\n        // Setting Accounts\n        List<OUser> accounts = OdooAccountManager.getAllAccounts(this);\n        if (accounts.size() > 0) {\n            chosenAccountView.setEnabled(true);\n            ImageView boxIndicator = (ImageView) findViewById(R.id.expand_account_box_indicator);\n            boxIndicator.setVisibility(View.VISIBLE);\n            chosenAccountView.setOnClickListener(new View.OnClickListener() {\n                @Override\n                public void onClick(View v) {\n                    mAccountBoxExpanded = !mAccountBoxExpanded;\n                    accountBoxToggle();\n                }\n            });\n            populateAccountList(currentUser, accounts);\n        }\n    }\n\n    private void accountBoxToggle() {\n        ImageView boxIndicator = (ImageView) findViewById(R.id.expand_account_box_indicator);\n        boxIndicator.setImageResource(mAccountBoxExpanded ? R.drawable.ic_drawer_accounts_collapse\n                : R.drawable.ic_drawer_accounts_expand);\n        int hideTranslateY = -mDrawerAccountContainer.getHeight() / 4;\n        if (mAccountBoxExpanded && mDrawerAccountContainer.getTranslationY() == 0) {\n            // initial setup\n            mDrawerAccountContainer.setAlpha(0);\n            mDrawerAccountContainer.setTranslationY(hideTranslateY);\n        }\n\n        AnimatorSet set = new AnimatorSet();\n        set.addListener(new AnimatorListenerAdapter() {\n            @Override\n            public void onAnimationEnd(Animator animation) {\n                mDrawerItemContainer\n                        .setVisibility(mAccountBoxExpanded ? View.INVISIBLE\n                                : View.VISIBLE);\n                mDrawerAccountContainer\n                        .setVisibility(mAccountBoxExpanded ? View.VISIBLE\n                                : View.INVISIBLE);\n            }\n\n            @Override\n            public void onAnimationCancel(Animator animation) {\n                onAnimationEnd(animation);\n            }\n        });\n\n        if (mAccountBoxExpanded) {\n            mDrawerAccountContainer.setVisibility(View.VISIBLE);\n            AnimatorSet subSet = new AnimatorSet();\n            subSet.playTogether(\n                    ObjectAnimator\n                            .ofFloat(mDrawerAccountContainer, View.ALPHA, 1)\n                            .setDuration(DRAWER_ACCOUNT_BOX_ANIMATION_DURATION),\n                    ObjectAnimator.ofFloat(mDrawerAccountContainer,\n                            View.TRANSLATION_Y, 0).setDuration(\n                            DRAWER_ACCOUNT_BOX_ANIMATION_DURATION));\n            set.playSequentially(\n                    ObjectAnimator.ofFloat(mDrawerItemContainer,\n                            View.ALPHA, 0).setDuration(\n                            DRAWER_ACCOUNT_BOX_ANIMATION_DURATION), subSet);\n            set.start();\n        } else {\n            mDrawerItemContainer.setVisibility(View.VISIBLE);\n            AnimatorSet subSet = new AnimatorSet();\n            subSet.playTogether(\n                    ObjectAnimator\n                            .ofFloat(mDrawerAccountContainer, View.ALPHA, 0)\n                            .setDuration(DRAWER_ACCOUNT_BOX_ANIMATION_DURATION),\n                    ObjectAnimator.ofFloat(mDrawerAccountContainer,\n                            View.TRANSLATION_Y, hideTranslateY).setDuration(\n                            DRAWER_ACCOUNT_BOX_ANIMATION_DURATION));\n            set.playSequentially(\n                    subSet,\n                    ObjectAnimator.ofFloat(mDrawerItemContainer,\n                            View.ALPHA, 1).setDuration(\n                            DRAWER_ACCOUNT_BOX_ANIMATION_DURATION));\n            set.start();\n        }\n\n        set.start();\n\n    }\n\n    private void populateAccountList(OUser me, List<OUser> accounts) {\n        mDrawerAccountContainer.removeAllViews();\n        for (final OUser user : accounts) {\n            if (!user.getAndroidName().equals(me.getAndroidName())) {\n                View view = LayoutInflater.from(this).inflate(R.layout.base_drawer_account_item, mDrawerAccountContainer, false);\n                ImageView avatar = (ImageView) view.findViewById(R.id.profile_image);\n                if (!user.getAvatar().equals(\"false\")) {\n                    Bitmap img = BitmapUtils.getBitmapImage(this, user.getAvatar());\n                    if (img != null)\n                        avatar.setImageBitmap(img);\n                }\n                OControls.setText(view, R.id.profile_name_text, user.getName());\n                OControls.setText(view, R.id.profile_url_text, (user.isOAauthLogin()) ? user.getInstanceUrl() : user.getHost());\n                // Setting login event for other account\n                view.setOnClickListener(new View.OnClickListener() {\n                    @Override\n                    public void onClick(View v) {\n\n                        OdooUserAskPassword.get(OdooActivity.this, user)\n                                .setOnUserPasswordValidateListener(\n                                        new OdooUserAskPassword.OnUserPasswordValidateListener() {\n                                            @Override\n                                            public void onSuccess() {\n                                                // Logging in to other account\n                                                OdooAccountManager.login(OdooActivity.this,\n                                                        user.getAndroidName());\n                                                OModel.sqLite = null;\n\n                                                mAccountBoxExpanded = false;\n                                                accountBoxToggle();\n                                                mDrawerLayout.closeDrawer(Gravity.START);\n                                                // Restarting activity\n                                                restartActivity();\n                                            }\n\n                                            @Override\n                                            public void onCancel() {\n                                            }\n\n                                            @Override\n                                            public void onFail() {\n                                                OAlert.showError(OdooActivity.this,\n                                                        OResource.string(OdooActivity.this,\n                                                                R.string.error_invalid_password));\n                                            }\n                                        }).show();\n\n                    }\n                });\n                mDrawerAccountContainer.addView(view);\n            }\n        }\n        accountListDefaultItems();\n    }\n\n    private void restartActivity() {\n        new Handler().postDelayed(new Runnable() {\n            @Override\n            public void run() {\n                Intent intent = new Intent(OdooActivity.this, OdooActivity.class);\n                finish();\n                startActivity(intent);\n            }\n        }, DRAWER_ITEM_LAUNCH_DELAY);\n    }\n\n    private void accountListDefaultItems() {\n        // Adding add account\n        View view = generateView(OResource.string(this, R.string.label_drawer_account_add_account),\n                R.drawable.ic_action_add);\n        view.setOnClickListener(new View.OnClickListener() {\n            @Override\n            public void onClick(View v) {\n                Intent loginActivity = new Intent(OdooActivity.this, OdooLogin.class);\n                loginActivity.putExtra(OdooAuthenticator.KEY_NEW_ACCOUNT_REQUEST, true);\n                loginActivity.putExtra(KEY_ACCOUNT_REQUEST, true);\n                startActivityForResult(loginActivity, REQUEST_ACCOUNT_CREATE);\n            }\n        });\n        mDrawerAccountContainer.addView(view);\n\n        // Adding add account\n        view = generateView(OResource.string(this, R.string.label_drawer_account_manage_accounts),\n                R.drawable.ic_action_settings);\n        view.setOnClickListener(new View.OnClickListener() {\n            @Override\n            public void onClick(View v) {\n                startActivityForResult(new Intent(OdooActivity.this, ManageAccounts.class),\n                        REQUEST_ACCOUNTS_MANAGE);\n            }\n        });\n        mDrawerAccountContainer.addView(view);\n    }\n\n    private View generateView(String title, int res_id) {\n        View view = LayoutInflater.from(this).inflate(R.layout.base_drawer_account_item,\n                mDrawerAccountContainer, false);\n        OControls.setGone(view, R.id.profile_url_text);\n        ImageView icon = (ImageView) view.findViewById(R.id.profile_image);\n        icon.setImageResource(res_id);\n        icon.setColorFilter(OResource.color(this, R.color.body_text_2));\n        TextView name = (TextView) view.findViewById(R.id.profile_name_text);\n        name.setTypeface(name.getTypeface(), Typeface.BOLD);\n        name.setText(title);\n        return view;\n    }\n\n\n    @Override\n    public void onConfigurationChanged(Configuration newConfig) {\n        super.onConfigurationChanged(newConfig);\n        if (mDrawerToggle != null) {\n            mDrawerToggle.onConfigurationChanged(newConfig);\n        }\n    }\n\n    @Override\n    public boolean onOptionsItemSelected(MenuItem item) {\n        if (mDrawerToggle != null && mDrawerToggle.onOptionsItemSelected(item)) {\n            return true;\n        }\n        return super.onOptionsItemSelected(item);\n    }\n\n    @Override\n    public void onBackPressed() {\n        if (backPressListener != null) {\n            if (backPressListener.onBackPressed()) {\n                super.onBackPressed();\n            }\n        } else\n            super.onBackPressed();\n    }\n\n    @Override\n    protected void onActivityResult(int requestCode, int resultCode, Intent data) {\n        super.onActivityResult(requestCode, resultCode, data);\n        if (mIOnActivityResultListener != null) {\n            mIOnActivityResultListener.onOdooActivityResult(requestCode, resultCode, data);\n        }\n        if (resultCode == RESULT_OK) {\n            if (requestCode == REQUEST_ACCOUNT_CREATE) {\n                if (mDrawerLayout != null) {\n                    mDrawerLayout.closeDrawer(Gravity.START);\n                    accountBoxToggle();\n                }\n                OdooAccountManager.login(this, data.getStringExtra(KEY_NEW_USER_NAME));\n                OModel.sqLite = null;\n                restartActivity();\n            }\n            if (requestCode == REQUEST_ACCOUNTS_MANAGE) {\n                startActivity(new Intent(this, OdooLogin.class));\n                finish();\n            }\n        }\n    }\n\n    /**\n     * Set system back button press listener\n     *\n     * @param listener\n     */\n    public void setOnBackPressListener(IOnBackPressListener listener) {\n        backPressListener = listener;\n    }\n\n    public void setOnActivityResultListener(IOnActivityResultListener listener) {\n        mIOnActivityResultListener = listener;\n    }\n\n    @Override\n    protected void onPostCreate(Bundle savedInstanceState) {\n        super.onPostCreate(savedInstanceState);\n        mSavedInstanceState = savedInstanceState;\n        if (savedInstanceState == null) {\n            // Loading Default Fragment (if any)\n            new Handler().postDelayed(new Runnable() {\n                @Override\n                public void run() {\n                    IBaseFragment fragment = DrawerUtils.getDefaultDrawerFragment();\n                    if (fragment != null) {\n                        ODrawerItem item = DrawerUtils.getStartableObject(OdooActivity.this, fragment);\n                        setTitle(item.getTitle());\n                        loadDrawerItemInstance(item.getInstance(), item.getExtra());\n                        int selected_item = DrawerUtils.findItemIndex(item, mDrawerItemContainer);\n                        if (selected_item > -1) {\n                            focusOnDrawerItem(selected_item);\n                        }\n                    }\n                }\n            }, DRAWER_ITEM_LAUNCH_DELAY);\n        } else {\n            mHasActionBarSpinner = savedInstanceState.getBoolean(KEY_HAS_ACTIONBAR_SPINNER);\n            mDrawerSelectedIndex = savedInstanceState.getInt(KEY_CURRENT_DRAWER_ITEM);\n            setTitle(savedInstanceState.getString(KEY_APP_TITLE));\n            focusOnDrawerItem(mDrawerSelectedIndex);\n        }\n    }\n\n\n    private void focusOnDrawerItem(int index) {\n        mDrawerSelectedIndex = index;\n        for (int i = 0; i < mDrawerItemContainer.getChildCount(); i++) {\n            DrawerUtils.focusOnView(this, mDrawerItemContainer.getChildAt(i), i == index);\n        }\n    }\n\n    @Override\n    protected void onSaveInstanceState(Bundle outState) {\n        outState.putInt(KEY_CURRENT_DRAWER_ITEM, mDrawerSelectedIndex);\n        outState.putString(KEY_APP_TITLE, getTitle().toString());\n        outState.putBoolean(KEY_HAS_ACTIONBAR_SPINNER, mHasActionBarSpinner);\n        super.onSaveInstanceState(outState);\n    }\n\n\n    public SyncUtils sync() {\n        return SyncUtils.get(this);\n    }\n\n    /**\n     * Actionbar Spinner handler\n     */\n\n    public void setHasActionBarSpinner(Boolean hasActionBarSpinner) {\n        ActionBar actionBar = getSupportActionBar();\n        if (actionBar != null) {\n            Spinner spinner = (Spinner) findViewById(R.id.spinner_nav);\n            if (hasActionBarSpinner) {\n                if (spinner != null)\n                    spinner.setVisibility(View.VISIBLE);\n                actionBar.setDisplayShowTitleEnabled(false);\n            } else {\n                if (spinner != null)\n                    spinner.setVisibility(View.GONE);\n                actionBar.setDisplayShowTitleEnabled(true);\n            }\n            mHasActionBarSpinner = hasActionBarSpinner;\n        }\n    }\n\n    public Spinner getActionBarSpinner() {\n        Spinner spinner = null;\n        if (mHasActionBarSpinner) {\n            spinner = (Spinner) findViewById(R.id.spinner_nav);\n            spinner.setAdapter(null);\n        }\n        return spinner;\n    }\n\n    public void refreshDrawer() {\n        setupDrawerBox();\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/SettingsActivity.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 9/1/15 11:32 AM\n */\npackage com.odoo;\n\nimport android.accounts.Account;\nimport android.content.ContentResolver;\nimport android.content.Intent;\nimport android.content.SyncAdapterType;\nimport android.os.Bundle;\nimport android.support.v7.app.ActionBar;\nimport android.support.v7.app.ActionBarActivity;\nimport android.view.MenuItem;\nimport android.widget.Toast;\n\nimport com.odoo.core.account.About;\nimport com.odoo.core.account.OdooLogin;\nimport com.odoo.core.support.OUser;\nimport com.odoo.core.support.sync.SyncUtils;\nimport com.odoo.core.utils.OActionBarUtils;\nimport com.odoo.core.utils.OPreferenceManager;\nimport com.odoo.core.utils.OResource;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class SettingsActivity extends ActionBarActivity {\n    public static final String TAG = SettingsActivity.class.getSimpleName();\n    public static final String ACTION_ABOUT = \"com.odoo.ACTION_ABOUT\";\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.base_setting_activity);\n        OActionBarUtils.setActionBar(this, true);\n        ActionBar actionbar = getSupportActionBar();\n        actionbar.setHomeButtonEnabled(true);\n        actionbar.setDisplayHomeAsUpEnabled(true);\n        actionbar.setTitle(R.string.title_application_settings);\n    }\n\n    @Override\n    public void startActivity(Intent intent) {\n        if (intent.getAction() != null\n                && intent.getAction().equals(ACTION_ABOUT)) {\n            Intent about = new Intent(this, About.class);\n            super.startActivity(about);\n            return;\n        }\n        super.startActivity(intent);\n    }\n\n    @Override\n    public boolean onOptionsItemSelected(MenuItem item) {\n        if (item.getItemId() == android.R.id.home) {\n            finish();\n        }\n        return super.onOptionsItemSelected(item);\n    }\n\n\n    @Override\n    public void onDetachedFromWindow() {\n        super.onDetachedFromWindow();\n        settingUpdated();\n    }\n\n    private void settingUpdated() {\n        OUser user = OUser.current(this);\n        if (user == null) {\n            Intent loginActivity = new Intent(this, OdooLogin.class);\n            loginActivity.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);\n            startActivity(loginActivity);\n            finish();\n        } else {\n            Account mAccount = user.getAccount();\n            OPreferenceManager mPref = new OPreferenceManager(this);\n            int sync_interval = mPref.getInt(\"sync_interval\", 1440);\n            List<String> default_authorities = new ArrayList<>();\n            default_authorities.add(\"com.android.calendar\");\n            default_authorities.add(\"com.android.contacts\");\n            SyncAdapterType[] list = ContentResolver.getSyncAdapterTypes();\n            for (SyncAdapterType lst : list) {\n                if (lst.authority.contains(\"com.odoo\")\n                        && lst.authority.contains(\"providers\")) {\n                    default_authorities.add(lst.authority);\n                }\n            }\n            for (String authority : default_authorities) {\n                boolean isSyncActive = ContentResolver.getSyncAutomatically(\n                        mAccount, authority);\n                if (isSyncActive) {\n                    SyncUtils.get(this).setSyncPeriodic(authority, sync_interval, 60, 1);\n                }\n            }\n            Toast.makeText(this, OResource.string(this, R.string.toast_setting_saved),\n                    Toast.LENGTH_LONG).show();\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/addons/calendar/CalendarDashboard.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 9/1/15 10:34 AM\n */\npackage com.odoo.addons.calendar;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.database.Cursor;\nimport android.graphics.Color;\nimport android.graphics.drawable.GradientDrawable;\nimport android.net.Uri;\nimport android.os.Bundle;\nimport android.os.Handler;\nimport android.support.annotation.Nullable;\nimport android.support.v4.app.LoaderManager;\nimport android.support.v4.content.CursorLoader;\nimport android.support.v4.content.Loader;\nimport android.support.v4.widget.SwipeRefreshLayout;\nimport android.text.TextUtils;\nimport android.view.LayoutInflater;\nimport android.view.Menu;\nimport android.view.MenuInflater;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.AdapterView;\nimport android.widget.ImageView;\nimport android.widget.ListView;\nimport android.widget.Spinner;\nimport android.widget.TextView;\nimport android.widget.Toast;\n\nimport com.odoo.R;\nimport com.odoo.addons.calendar.models.CalendarEvent;\nimport com.odoo.addons.calendar.utils.CalendarUtils;\nimport com.odoo.addons.calendar.utils.TodayIcon;\nimport com.odoo.addons.crm.CRMDetail;\nimport com.odoo.addons.crm.CRMLeads;\nimport com.odoo.addons.crm.ConvertToQuotation;\nimport com.odoo.addons.crm.models.CRMLead;\nimport com.odoo.addons.phonecall.PhoneCallDetail;\nimport com.odoo.addons.phonecall.models.CRMPhoneCalls;\nimport com.odoo.addons.sale.models.SaleOrder;\nimport com.odoo.base.addons.res.ResCurrency;\nimport com.odoo.base.addons.res.ResPartner;\nimport com.odoo.libs.calendar.SysCal;\nimport com.odoo.libs.calendar.view.OdooCalendar;\nimport com.odoo.core.orm.ODataRow;\nimport com.odoo.core.orm.OValues;\nimport com.odoo.core.orm.fields.OColumn;\nimport com.odoo.core.support.addons.fragment.BaseFragment;\nimport com.odoo.core.support.addons.fragment.IOnSearchViewChangeListener;\nimport com.odoo.core.support.addons.fragment.ISyncStatusObserverListener;\nimport com.odoo.core.support.drawer.ODrawerItem;\nimport com.odoo.core.support.list.IOnItemClickListener;\nimport com.odoo.core.support.list.OCursorListAdapter;\nimport com.odoo.core.support.list.OListAdapter;\nimport com.odoo.core.support.sync.SyncUtils;\nimport com.odoo.core.utils.IntentUtils;\nimport com.odoo.core.utils.OControls;\nimport com.odoo.core.utils.OCursorUtils;\nimport com.odoo.core.utils.ODateUtils;\nimport com.odoo.core.utils.OResource;\nimport com.odoo.core.utils.StringUtils;\nimport com.odoo.core.utils.dialog.OChoiceDialog;\nimport com.odoo.core.utils.sys.IOnActivityResultListener;\nimport com.odoo.core.utils.sys.IOnBackPressListener;\nimport com.odoo.widgets.bottomsheet.BottomSheet;\nimport com.odoo.widgets.bottomsheet.BottomSheetListeners;\nimport com.odoo.widgets.snackbar.SnackBar;\nimport com.odoo.widgets.snackbar.SnackbarBuilder;\nimport com.odoo.widgets.snackbar.listeners.EventListener;\n\nimport java.util.ArrayList;\nimport java.util.Date;\nimport java.util.List;\n\npublic class CalendarDashboard extends BaseFragment implements View.OnClickListener,\n        BottomSheetListeners.OnSheetItemClickListener, IOnBackPressListener,\n        OdooCalendar.OdooCalendarDateSelectListener, LoaderManager.LoaderCallbacks<Cursor>,\n        OCursorListAdapter.OnViewBindListener, SwipeRefreshLayout.OnRefreshListener,\n        ISyncStatusObserverListener, BottomSheetListeners.OnSheetActionClickListener,\n        BottomSheetListeners.OnSheetMenuCreateListener, EventListener,\n        IOnSearchViewChangeListener, IOnItemClickListener, OCursorListAdapter.OnViewCreateListener,\n        AdapterView.OnItemSelectedListener, IOnActivityResultListener, OCursorListAdapter.BeforeBindUpdateData {\n    public static final String TAG = CalendarDashboard.class.getSimpleName();\n    public static final String KEY = \"key_calendar_dashboard\";\n    public static final String KEY_DATE = \"key_date\";\n    public static final int REQUEST_CONVERT_TO_QUOTATION_WIZARD = 229;\n    private BottomSheet mSheet = null;\n    private OdooCalendar odooCalendar;\n    private View calendarView = null;\n    private ListView dashboardListView;\n    private View mView;\n    private String mFilterDate;\n    private OCursorListAdapter mAdapter;\n    private boolean syncRequested = false;\n    private String mFilter = null;\n    private String wonLost = \"won\";\n    private CRMLead crmLead;\n    private ODataRow convertRequestRecord;\n    private Spinner navSpinner;\n    private OListAdapter navSpinnerAdapter;\n    private FilterType mFilterType = FilterType.All;\n\n\n    private enum SheetType {\n        Event, PhoneCall, Opportunity\n    }\n\n    private enum FilterType {\n        All(R.string.label_all), Meetings(R.string.label_meetings),\n        Opportunities(R.string.label_opportunity), PhoneCalls(R.string.label_phone_calls);\n        int str_id = 0;\n\n        FilterType(int type) {\n            str_id = type;\n        }\n\n        public String getString(Context context) {\n            return OResource.string(context, str_id);\n        }\n    }\n\n    @Override\n    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,\n                             @Nullable Bundle savedInstanceState) {\n        setHasOptionsMenu(true);\n        return inflater.inflate(R.layout.calendar_dashboard, container, false);\n    }\n\n    @Override\n    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {\n        super.onViewCreated(view, savedInstanceState);\n        mView = view;\n        setHasFloatingButton(view, R.id.fabButton, null, this);\n        parent().setOnBackPressListener(this);\n        parent().setHasActionBarSpinner(true);\n        parent().setOnActivityResultListener(this);\n        navSpinner = parent().getActionBarSpinner();\n        initActionSpinner();\n        odooCalendar = (OdooCalendar) view.findViewById(R.id.dashboard_calendar);\n        crmLead = new CRMLead(getActivity(), null);\n        odooCalendar.setOdooCalendarDateSelectListener(this);\n    }\n\n    private void initActionSpinner() {\n        List<Object> spinnerItems = new ArrayList<>();\n        ODataRow row = new ODataRow();\n        row.put(\"key\", FilterType.All.toString());\n        row.put(\"name\", FilterType.All.getString(getActivity()));\n        spinnerItems.add(row);\n        row = new ODataRow();\n        row.put(\"key\", FilterType.Meetings.toString());\n        row.put(\"name\", FilterType.Meetings.getString(getActivity()));\n        spinnerItems.add(row);\n        row = new ODataRow();\n        row.put(\"key\", FilterType.Opportunities.toString());\n        row.put(\"name\", FilterType.Opportunities.getString(getActivity()));\n        spinnerItems.add(row);\n        row = new ODataRow();\n        row.put(\"key\", FilterType.PhoneCalls.toString());\n        row.put(\"name\", FilterType.PhoneCalls.getString(getActivity()));\n        spinnerItems.add(row);\n        navSpinnerAdapter = new OListAdapter(getActivity(), R.layout.base_simple_list_item_1, spinnerItems) {\n            @Override\n            public View getView(int position, View convertView, ViewGroup parent) {\n                if (convertView == null) {\n                    convertView = LayoutInflater.from(getActivity()).inflate(R.layout.base_simple_list_item_1_selected\n                            , parent, false);\n                }\n                return getSpinnerView(getItem(position), position, convertView, parent);\n            }\n\n            @Override\n            public View getDropDownView(int position, View convertView, ViewGroup parent) {\n                if (convertView == null) {\n                    convertView = LayoutInflater.from(getActivity()).inflate(getResource(), parent, false);\n                }\n                return getSpinnerView(getItem(position), position, convertView, parent);\n            }\n        };\n        navSpinner.setAdapter(navSpinnerAdapter);\n        navSpinner.setOnItemSelectedListener(this);\n    }\n\n    @Override\n    public void onNothingSelected(AdapterView<?> parent) {\n\n    }\n\n    @Override\n    public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {\n        ODataRow row = (ODataRow) navSpinnerAdapter.getItem(position);\n        mFilterType = FilterType.valueOf(row.getString(\"key\"));\n        if (mFilterDate != null && getActivity() != null)\n            getLoaderManager().restartLoader(0, null, this);\n    }\n\n    private View getSpinnerView(Object row, int pos, View view, ViewGroup parent) {\n        ODataRow r = (ODataRow) row;\n        OControls.setText(view, android.R.id.text1, r.getString(\"name\"));\n        return view;\n    }\n\n    @Override\n    public List<OdooCalendar.DateDataObject> weekDataInfo(\n            List<SysCal.DateInfo> week_dates) {\n        List<OdooCalendar.DateDataObject> items = new ArrayList<>();\n        CalendarEvent event = (CalendarEvent) db();\n        CRMPhoneCalls calls = new CRMPhoneCalls(getActivity(), event.getUser());\n        CRMLead lead = new CRMLead(getActivity(), event.getUser());\n        for (SysCal.DateInfo date : week_dates) {\n            String date_str = date.getDateString();\n            int total = 0;\n            switch (mFilterType) {\n                case All:\n                case Meetings:\n                    // Checking for events\n                    total += event.countGroupBy(\"date_start\", \"date(date_start)\"\n                            , \"(date(date_start) <= ? and date(date_end) >= ? )\",\n                            new String[]{date_str, date_str}).getInt(\"total\");\n\n                    if (mFilterType != FilterType.All)\n                        break;\n                case PhoneCalls:\n                    // Checking for phone calls\n                    total += calls.countGroupBy(\"date\", \"date(date)\",\n                            \"date(date) >=  ? and date(date) <= ? and (state = ? or state = ?)\",\n                            new String[]{date_str, date_str, \"open\", \"pending\"})\n                            .getInt(\"total\");\n\n                    if (mFilterType != FilterType.All)\n                        break;\n                case Opportunities:\n                    // Leads\n                    total += lead.countGroupBy(\"date_deadline\", \"date(date_deadline)\",\n                            \"(date(date_deadline) >= ? and date(date_deadline) <= ? or \" +\n                                    \"date(date_action) >= ? and date(date_action) <= ?) and type = ?\",\n                            new String[]{date_str, date_str, date_str, date_str, \"opportunity\"}).getInt(\"total\");\n                    if (mFilterType != FilterType.All)\n                        break;\n            }\n\n            items.add(new OdooCalendar.DateDataObject(date_str, (total > 0)));\n        }\n        return items;\n    }\n\n    @Override\n    public View getEventsView(ViewGroup parent, SysCal.DateInfo date) {\n        calendarView = LayoutInflater.from(getActivity()).inflate(\n                R.layout.calendar_dashboard_items, parent, false);\n        calendarView.findViewById(R.id.dashboard_no_item_view)\n                .setOnClickListener(this);\n        dashboardListView = (ListView) calendarView\n                .findViewById(R.id.items_container);\n        setHasFloatingButton(mView, R.id.fabButton, dashboardListView, this);\n        initAdapter();\n        mFilterDate = date.getDateString();\n        if (getActivity() != null) {\n            getLoaderManager().restartLoader(0, null, CalendarDashboard.this);\n        }\n        return calendarView;\n    }\n\n    private void initAdapter() {\n        mAdapter = new OCursorListAdapter(getActivity(), null,\n                R.layout.calendar_dashboard_item_view);\n        mAdapter.setBeforeBindUpdateData(this);\n        mAdapter.setOnViewBindListener(this);\n        mAdapter.setOnViewCreateListener(this);\n        dashboardListView.setAdapter(mAdapter);\n        mAdapter.changeCursor(null);\n        mAdapter.handleItemClickListener(dashboardListView, this);\n        setHasSyncStatusObserver(KEY, this, db());\n    }\n\n\n    @Override\n    public void onItemDoubleClick(View view, int position) {\n        ODataRow row = OCursorUtils.toDatarow((Cursor) mAdapter.getItem(position));\n        String type = row.getString(\"data_type\");\n        Class<?> cls = EventDetail.class;\n        if (type.equals(\"phone_call\")) {\n            cls = PhoneCallDetail.class;\n        }\n        if (type.equals(\"opportunity\")) {\n            cls = CRMDetail.class;\n        }\n        IntentUtils.startActivity(getActivity(), cls, row.getPrimaryBundleData());\n    }\n\n    @Override\n    public void onItemClick(View view, int position) {\n        Cursor cr = (Cursor) mAdapter.getItem(position);\n        String data_type = cr.getString(cr.getColumnIndex(\"data_type\"));\n        if (data_type.equals(\"event\")) {\n            showSheet(SheetType.Event, cr);\n        }\n        if (data_type.equals(\"phone_call\")) {\n            showSheet(SheetType.PhoneCall, cr);\n        }\n        if (data_type.equals(\"opportunity\")) {\n            showSheet(SheetType.Opportunity, cr);\n        }\n    }\n\n    private void showSheet(SheetType type, Cursor data) {\n        if (mSheet != null) {\n            mSheet.dismiss();\n        }\n        BottomSheet.Builder builder = new BottomSheet.Builder(getActivity());\n        builder.listener(this);\n        builder.setIconColor(_c(R.color.body_text_2));\n        builder.setTextColor(_c(R.color.body_text_1));\n        builder.setData(data);\n        builder.actionListener(this);\n        builder.setActionIcon(R.drawable.ic_action_edit);\n        builder.title(data.getString(data.getColumnIndex(\"name\")));\n        builder.setOnSheetMenuCreateListener(this);\n        switch (type) {\n            case Event:\n                builder.setOnSheetMenuCreateListener(this);\n                builder.menu(R.menu.menu_dashboard_events);\n                break;\n            case PhoneCall:\n                builder.menu(R.menu.menu_dashboard_phonecalls);\n                break;\n            case Opportunity:\n                builder.menu(R.menu.menu_dashboard_opportunity);\n                break;\n        }\n        mSheet = builder.create();\n        mSheet.show();\n    }\n\n    @Override\n    public void onSheetActionClick(BottomSheet sheet, final Object extras) {\n        sheet.dismiss();\n        new Handler().postDelayed(new Runnable() {\n\n            @Override\n            public void run() {\n                Cursor cr = (Cursor) extras;\n                String data_type = cr.getString(cr.getColumnIndex(\"data_type\"));\n                int record_id = cr.getInt(cr.getColumnIndex(OColumn.ROW_ID));\n                if (data_type.equals(\"phone_call\")) {\n                    Bundle extra = new Bundle();\n                    extra.putInt(OColumn.ROW_ID, record_id);\n                    IntentUtils.startActivity(getActivity(), PhoneCallDetail.class, extra);\n                }\n                if (data_type.equals(\"event\")) {\n                    Bundle extra = new Bundle();\n                    extra.putInt(OColumn.ROW_ID, record_id);\n                    IntentUtils.startActivity(getActivity(), EventDetail.class, extra);\n                }\n\n                if (data_type.equals(\"opportunity\")) {\n                    Bundle bundle = new Bundle();\n                    bundle.putInt(OColumn.ROW_ID, record_id);\n                    IntentUtils.startActivity(getActivity(), CRMDetail.class, bundle);\n                }\n            }\n        }, 250);\n\n    }\n\n    @Override\n    public void onSheetMenuCreate(Menu menu, Object extras) {\n        Cursor cr = (Cursor) extras;\n        String type = cr.getString(cr.getColumnIndex(\"data_type\"));\n        String is_done = cr.getString(cr.getColumnIndex(\"is_done\"));\n        if (type.equals(\"event\")) {\n            ODataRow row = OCursorUtils.toDatarow(cr);\n            if (row.getString(\"location\").equals(\"false\")) {\n                menu.findItem(R.id.menu_events_location).setVisible(false);\n            }\n            if (is_done.equals(\"1\")) {\n                menu.findItem(R.id.menu_events_all_done).setVisible(false);\n            }\n        }\n    }\n\n    @Override\n    public View onViewCreated(Context context, ViewGroup view, Cursor cr, int position) {\n        String data_type = cr.getString(cr.getColumnIndex(\"data_type\"));\n        if (data_type.equals(\"separator\")) {\n            return LayoutInflater.from(getActivity()).inflate(\n                    R.layout.calendar_dashboard_item_separator, view, false);\n        }\n        return LayoutInflater.from(getActivity()).inflate(\n                R.layout.calendar_dashboard_item_view, view, false);\n    }\n\n    @Override\n    public ODataRow updateDataRow(Cursor cr) {\n        ODataRow row = OCursorUtils.toDatarow(cr);\n        String type = row.getString(\"data_type\");\n        ODataRow record = new ODataRow();\n        if (type.equals(\"opportunity\")) {\n            record.put(\"stage_id\",\n                    crmLead.browse(new String[]{\"stage_id\"}, row.getInt(OColumn.ROW_ID)).get(\"stage_id\"));\n        }\n        return record;\n    }\n\n    @Override\n    public void onViewBind(View view, Cursor cursor, ODataRow row) {\n        String type = row.getString(\"data_type\");\n        GradientDrawable shape = (GradientDrawable) getActivity().getResources()\n                .getDrawable(R.drawable.circle_mask_secondary);\n        int icon = -1;\n\n        ImageView iconView = (ImageView) view.findViewById(R.id.event_icon);\n        if (type.equals(\"separator\")) {\n            OControls.setText(view, R.id.list_separator, row.getString(\"name\"));\n        } else {\n            String colorCode = CalendarUtils.getColorData(row.getInt(\"color_index\")).\n                    getString(\"code\");\n            shape.setColor(Color.parseColor(colorCode));\n            String date = \"false\";\n            String desc = null;\n\n            if (row.getString(\"description\").equals(\"false\")) {\n                row.put(\"description\", \"\");\n            }\n\n            if (type.equals(\"event\")) {\n                desc = row.getString(\"description\");\n                icon = R.drawable.ic_action_event;\n                if (row.getString(\"allday\").equals(\"false\")) {\n                    date = row.getString(\"date_start\");\n                    view.findViewById(R.id.allDay).setVisibility(View.GONE);\n                } else {\n                    TextView allDayTag = (TextView) view.findViewById(R.id.allDay);\n                    allDayTag.setTextColor(Color.parseColor(colorCode));\n                    allDayTag.setVisibility(View.VISIBLE);\n                }\n            }\n            if (type.equals(\"phone_call\")) {\n                icon = R.drawable.ic_action_phone;\n                date = row.getString(\"date\");\n                desc = row.getString(\"description\");\n            }\n            if (type.equals(\"opportunity\")) {\n                icon = R.drawable.ic_action_opportunities;\n                ODataRow stage_id = row.getM2ORecord(\"stage_id\").browse();\n                float probability = -1;\n                if (stage_id != null && !stage_id.getString(\"probability\").equals(\"false\")\n                        && (stage_id.getString(\"type\").equals(\"opportunity\") ||\n                        stage_id.getString(\"type\").equals(\"both\"))) {\n                    if (!stage_id.getString(\"name\").equals(\"New\"))\n                        probability = stage_id.getFloat(\"probability\");\n                }\n                if (probability == 0) {\n                    // Lost\n                    icon = R.drawable.ic_action_mark_lost;\n                } else if (probability >= 100) {\n                    // Won\n                    icon = R.drawable.ic_action_mark_won;\n                }\n                desc = row.getString(\"planned_revenue\") + \" \"\n                        + ResCurrency.getSymbol(getActivity(), row.getInt(\"company_currency\")) +\n                        \" at \" + row.getString(\"probability\") + \" %\";\n                if (!row.getString(\"title_action\").equals(\"false\")) {\n                    desc += \"\\n\" + row.getString(\"title_action\");\n                }\n                OControls.setText(view, R.id.event_description, desc);\n            }\n\n            if (!date.equals(\"false\")) {\n                Date dateNow = new Date();\n                Date eventDate = ODateUtils.createDateObject(date, ODateUtils.DEFAULT_FORMAT, false);\n                date = ODateUtils.convertToDefault(date, ODateUtils.DEFAULT_FORMAT, \"hh:mm a\");\n                OControls.setText(view, R.id.event_time, date);\n                if (dateNow.after(eventDate) && !row.getBoolean(\"is_done\")) {\n                    colorCode = \"#cc0000\";\n                }\n            }\n            OControls.setText(view, R.id.event_description, desc);\n            Boolean is_done = row.getString(\"is_done\").equals(\"1\");\n            OControls.setImage(view, R.id.event_icon, icon);\n            iconView.setBackgroundDrawable(shape);\n            int title_color = (is_done) ? Color.LTGRAY : Color.parseColor(\"#414141\");\n            int time_color = (is_done) ? Color.LTGRAY : Color.parseColor(colorCode);\n            int desc_color = (is_done) ? Color.LTGRAY : _c(R.color.body_text_2);\n            int allDay_color = (is_done) ? Color.LTGRAY : Color.parseColor(colorCode);\n            OControls.setTextColor(view, R.id.event_name, title_color);\n            OControls.setTextColor(view, R.id.event_time, time_color);\n            OControls.setTextColor(view, R.id.event_description, desc_color);\n            OControls.setTextColor(view, R.id.allDay, allDay_color);\n            if (is_done) {\n                view.findViewById(R.id.event_icon).setBackgroundResource(\n                        R.drawable.circle_mask_gray);\n                OControls.setTextViewStrikeThrough(view, R.id.event_name);\n                OControls.setTextViewStrikeThrough(view, R.id.event_time);\n                OControls.setTextViewStrikeThrough(view, R.id.event_description);\n                OControls.setTextViewStrikeThrough(view, R.id.allDay);\n            }\n            OControls.setText(view, R.id.event_name, row.getString(\"name\"));\n        }\n    }\n\n    @Override\n    public Loader<Cursor> onCreateLoader(int id, Bundle data) {\n        List<String> args = new ArrayList<>();\n        String where = \"\";\n        args.add(mFilterDate);\n        CalendarEvent event = (CalendarEvent) db();\n        Uri uri = event.agendaUri();\n        switch (mFilterType) {\n            case PhoneCalls:\n                CRMPhoneCalls phoneCalls = new CRMPhoneCalls(getActivity(), db().getUser());\n                uri = phoneCalls.uri();\n                where = \"date(date) >=  ? and date(date) <= ? and (state = ? or state = ?)\";\n                args.add(mFilterDate);\n                args.add(\"open\");\n                args.add(\"pending\");\n                if (mFilter != null) {\n                    where += \" and (name like ? or description like ?)\";\n                    args.add(\"%\" + mFilter + \"%\");\n                }\n                break;\n            case Opportunities:\n                CRMLead leads = new CRMLead(getActivity(), db().getUser());\n                uri = leads.uri();\n                where = \"(date(date_deadline) >= ? and date(date_deadline) <= ? or \" +\n                        \"date(date_action) >= ? and date(date_action) <= ?) and type = ?\";\n                args.add(mFilterDate);\n                args.add(mFilterDate);\n                args.add(mFilterDate);\n                args.add(\"opportunity\");\n                if (mFilter != null) {\n                    where += \" and (name like ? or description like ?)\";\n                    args.add(\"%\" + mFilter + \"%\");\n                }\n                break;\n            case Meetings:\n                uri = db().uri();\n                where = \"(date(date_start) <= ? and date(date_end) >= ? )\";\n                args.add(mFilterDate);\n                if (mFilter != null) {\n                    where += \" and name like ?\";\n                }\n                break;\n        }\n        if (mFilter != null) {\n            args.add(\"%\" + mFilter + \"%\");\n        }\n        return new CursorLoader(getActivity(), uri,\n                null, where, args.toArray(new String[args.size()]), null);\n    }\n\n    @Override\n    public void onLoadFinished(Loader<Cursor> loader, final Cursor cr) {\n        mAdapter.changeCursor(cr);\n        if (cr != null) {\n            new Handler().postDelayed(new Runnable() {\n                @Override\n                public void run() {\n                    if (cr.getCount() > 0) {\n                        OControls.setGone(calendarView, R.id.dashboard_progress);\n                        OControls.setVisible(calendarView, R.id.items_container);\n                        OControls.setGone(calendarView, R.id.dashboard_no_items);\n                        setHasSwipeRefreshView(calendarView, R.id.swipe_container,\n                                CalendarDashboard.this);\n                    } else {\n                        setHasSwipeRefreshView(calendarView,\n                                R.id.dashboard_no_items, CalendarDashboard.this);\n                        OControls.setGone(calendarView, R.id.dashboard_progress);\n                        OControls.setVisible(calendarView, R.id.dashboard_no_items);\n                    }\n                }\n            }, 300);\n        }\n        if (db().isEmptyTable() && !syncRequested) {\n            syncRequested = true;\n            parent().sync().requestSync(CalendarEvent.AUTHORITY);\n            setSwipeRefreshing(true);\n        }\n    }\n\n    @Override\n    public void onLoaderReset(Loader<Cursor> loader) {\n        mAdapter.changeCursor(null);\n    }\n\n    @Override\n    public List<ODrawerItem> drawerMenus(Context context) {\n        List<ODrawerItem> menu = new ArrayList<>();\n        menu.add(new ODrawerItem(KEY).setTitle(\"Calendar\")\n                .setInstance(new CalendarDashboard())\n                .setIcon(R.drawable.ic_action_dashboard));\n        return menu;\n    }\n\n    @Override\n    public Class<CalendarEvent> database() {\n        return CalendarEvent.class;\n    }\n\n    @Override\n    public void onClick(View v) {\n        switch (v.getId()) {\n            case R.id.fabButton:\n            case R.id.dashboard_no_item_view:\n                createEvent();\n                break;\n        }\n    }\n\n    @Override\n    public void onItemClick(BottomSheet sheet, MenuItem menu, Object extras) {\n        dismissSheet(sheet);\n        actionEvent(menu, (Cursor) extras);\n    }\n\n    private void actionEvent(MenuItem menu, Cursor cr) {\n        String is_done = cr.getString(cr.getColumnIndex(\"is_done\"));\n        final OValues values = new OValues();\n        values.put(\"_is_dirty\", \"false\"); // to ignore update on server\n        final int row_id = cr.getInt(cr.getColumnIndex(OColumn.ROW_ID));\n        values.put(\"is_done\", (is_done.equals(\"0\")) ? 1 : 0);\n        String done_label = (is_done.equals(\"0\")) ? \"done\" : \"undone\";\n        final ODataRow row = OCursorUtils.toDatarow(cr);\n        convertRequestRecord = row;\n        Bundle data = row.getPrimaryBundleData();\n        switch (menu.getItemId()) {\n            // Event menus\n            case R.id.menu_events_location:\n                String location = cr.getString(cr.getColumnIndex(\"location\"));\n                if (location.equals(\"false\")) {\n                    Toast.makeText(getActivity(), _s(R.string.label_no_location_found),\n                            Toast.LENGTH_LONG).show();\n                } else {\n                    IntentUtils.redirectToMap(getActivity(), location);\n                }\n                break;\n            case R.id.menu_events_reschedule:\n                IntentUtils.startActivity(getActivity(), EventDetail.class, data);\n                break;\n            // Opportunity menus\n            case R.id.menu_opp_customer_location:\n                String address = cr.getString(cr.getColumnIndex(\"street\")) + \" \";\n                address += cr.getString(cr.getColumnIndex(\"street2\")) + \" \";\n                address += cr.getString(cr.getColumnIndex(\"city\")) + \" \";\n                address += cr.getString(cr.getColumnIndex(\"zip\"));\n                address = address.replaceAll(\"false\", \"\");\n                if (TextUtils.isEmpty(address.trim())) {\n                    Toast.makeText(getActivity(), _s(R.string.label_no_location_found),\n                            Toast.LENGTH_LONG).show();\n                } else {\n                    IntentUtils.redirectToMap(getActivity(), address);\n                }\n                break;\n            case R.id.menu_opp_call_customer:\n            case R.id.menu_phonecall_call:\n                int partner_id = cr.getInt(cr.getColumnIndex(\"partner_id\"));\n                if (partner_id != 0) {\n                    String contact = ResPartner.getContact(getActivity(), partner_id);\n                    if (contact != null && !contact.equals(\"false\")) {\n                        IntentUtils.requestCall(getActivity(), contact);\n                    } else {\n                        Toast.makeText(getActivity(), _s(R.string.label_no_contact_found),\n                                Toast.LENGTH_LONG).show();\n                    }\n                } else {\n                    Toast.makeText(getActivity(), _s(R.string.label_no_contact_found),\n                            Toast.LENGTH_LONG).show();\n                }\n                break;\n            case R.id.menu_opp_lost:\n                if (inNetwork()) {\n                    wonLost = \"lost\";\n                    crmLead.markWonLost(wonLost, row, markDoneListener);\n                } else {\n                    Toast.makeText(getActivity(), _s(R.string.toast_network_required),\n                            Toast.LENGTH_LONG).show();\n                }\n                break;\n            case R.id.menu_opp_won:\n                if (inNetwork()) {\n                    wonLost = \"won\";\n                    crmLead.markWonLost(wonLost, row, markDoneListener);\n                } else {\n                    Toast.makeText(getActivity(), _s(R.string.toast_network_required),\n                            Toast.LENGTH_LONG).show();\n                }\n                break;\n            case R.id.menu_opp_reschedule:\n                List<String> choices = new ArrayList<>();\n                choices.add(OResource.string(getActivity(), R.string.label_opt_schedule_log_call));\n                choices.add(OResource.string(getActivity(), R.string.label_opt_schedule_meeting));\n                OChoiceDialog.get(getActivity()).withOptions(choices, -1)\n                        .show(new OChoiceDialog.OnChoiceSelectListener() {\n                            @Override\n                            public void choiceSelected(int position, String value) {\n                                int opp_id = row.getInt(OColumn.ROW_ID);\n                                switch (position) {\n                                    case 0:\n                                        Bundle extra = new Bundle();\n                                        extra.putInt(\"opp_id\", opp_id);\n                                        IntentUtils.startActivity(getActivity(), PhoneCallDetail.class, extra);\n                                        break;\n                                    case 1: // Schedule meeting\n                                        Bundle data = new Bundle();\n                                        data.putString(KEY_DATE, mFilterDate);\n                                        data.putInt(\"opp_id\", opp_id);\n                                        IntentUtils.startActivity(getActivity(), EventDetail.class, data);\n                                        break;\n                                }\n                            }\n                        });\n                break;\n\n            case R.id.menu_phonecall_reschedule:\n                choices = new ArrayList<>();\n                choices.add(\"Re-Schedule call\");\n                choices.add(\"Schedule other call\");\n                OChoiceDialog.get(getActivity()).withOptions(choices, -1)\n                        .show(new OChoiceDialog.OnChoiceSelectListener() {\n                            @Override\n                            public void choiceSelected(int position, String value) {\n                                switch (position) {\n                                    case 0: // Re-Schedule\n                                        IntentUtils.startActivity(getActivity(), PhoneCallDetail.class,\n                                                row.getPrimaryBundleData());\n\n                                        break;\n                                    case 1: // Schedule other call\n                                        Bundle extra = row.getPrimaryBundleData();\n                                        extra.putInt(\"call_id\", row.getInt(OColumn.ROW_ID));\n                                        IntentUtils.startActivity(getActivity(), PhoneCallDetail.class,\n                                                extra);\n                                        break;\n                                }\n                            }\n                        });\n                break;\n            // All done menu\n            case R.id.menu_phonecall_all_done:\n                final CRMPhoneCalls phone_call = new CRMPhoneCalls(getActivity(), null);\n                values.put(\"state\", \"done\");\n                phone_call.update(row_id, values);\n                getLoaderManager().restartLoader(0, null, this);\n                SnackBar.get(getActivity()).text(_s(R.string.toast_phone_call_marked_done) + \" \" + done_label)\n                        .duration(SnackbarBuilder.SnackbarDuration.LENGTH_LONG)\n                        .withEventListener(this).show();\n                break;\n            case R.id.menu_events_all_done:\n                db().update(row_id, values);\n                getLoaderManager().restartLoader(0, null, this);\n                SnackBar.get(getActivity()).text(_s(R.string.label_event_marked) + \" \" + done_label)\n                        .duration(SnackbarBuilder.SnackbarDuration.LENGTH_LONG)\n                        .withEventListener(this).show();\n                break;\n            case R.id.menu_lead_convert_to_quotation:\n                if (inNetwork()) {\n                    Intent intent = new Intent(getActivity(), ConvertToQuotation.class);\n                    intent.putExtras(row.getPrimaryBundleData());\n                    parent().startActivityForResult(intent, REQUEST_CONVERT_TO_QUOTATION_WIZARD);\n                } else {\n                    Toast.makeText(getActivity(), R.string.toast_network_required,\n                            Toast.LENGTH_LONG).show();\n                }\n                break;\n        }\n    }\n\n    CRMLead.OnOperationSuccessListener markDoneListener = new CRMLead.OnOperationSuccessListener() {\n        @Override\n        public void OnSuccess() {\n            Toast.makeText(getActivity(), StringUtils.capitalizeString(convertRequestRecord.getString(\"type\"))\n                    + \" \" + _s(R.string.toast_marked) + \" \" + wonLost, Toast.LENGTH_LONG).show();\n        }\n\n        @Override\n        public void OnCancelled() {\n\n        }\n    };\n\n    private void dismissSheet(final BottomSheet sheet) {\n        new Handler().postDelayed(new Runnable() {\n\n            @Override\n            public void run() {\n                sheet.dismiss();\n            }\n        }, 100);\n    }\n\n    @Override\n    public boolean onBackPressed() {\n        if (mSheet != null && mSheet.isShowing()) {\n            mSheet.dismiss();\n            return false;\n        }\n        return true;\n    }\n\n\n    @Override\n    public void onRefresh() {\n        if (inNetwork()) {\n            parent().sync().requestSync(CalendarEvent.AUTHORITY);\n            // Syncing phone calls and sales order\n            SyncUtils.get(getActivity(), db().getUser()).requestSync(CRMPhoneCalls.AUTHORITY);\n            // Syncing only Opportunity from agenda\n            Bundle syncData = new Bundle();\n            syncData.putBoolean(CRMLeads.KEY_IS_LEAD, false);\n            SyncUtils.get(getActivity(), db().getUser()).requestSync(CRMLead.AUTHORITY, syncData);\n            setSwipeRefreshing(true);\n        } else {\n            hideRefreshingProgress();\n            Toast.makeText(getActivity(),\n                    _s(R.string.toast_network_required), Toast.LENGTH_LONG).show();\n        }\n    }\n\n    @Override\n    public void onStatusChange(Boolean refreshing) {\n        getLoaderManager().restartLoader(0, null, this);\n        setSwipeRefreshing(refreshing);\n    }\n\n    @Override\n    public void onShow(int height) {\n        hideFab();\n    }\n\n    @Override\n    public void onDismiss(int height) {\n        showFab();\n    }\n\n    @Override\n    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {\n        menu.clear();\n        inflater.inflate(R.menu.menu_calendar_dashboard, menu);\n        if (getActivity() != null) {\n            MenuItem today = menu.findItem(R.id.menu_dashboard_goto_today);\n            today.setIcon(TodayIcon.get(getActivity()).getIcon());\n        }\n        setHasSearchView(this, menu, R.id.menu_search);\n    }\n\n    @Override\n    public boolean onOptionsItemSelected(MenuItem item) {\n        switch (item.getItemId()) {\n            case R.id.menu_dashboard_goto_today:\n                odooCalendar.goToToday();\n                break;\n        }\n        return super.onOptionsItemSelected(item);\n    }\n\n    @Override\n    public boolean onSearchViewTextChange(String newFilter) {\n        mFilter = newFilter;\n        getLoaderManager().restartLoader(0, null, this);\n        return true;\n    }\n\n    @Override\n    public void onSearchViewClose() {\n        // Nothing to do\n    }\n\n    private void createEvent() {\n        Bundle data = new Bundle();\n        data.putString(KEY_DATE, mFilterDate);\n        IntentUtils.startActivity(getActivity(), EventDetail.class, data);\n    }\n\n    @Override\n    public void onOdooActivityResult(int requestCode, int resultCode, Intent data) {\n        if (requestCode == REQUEST_CONVERT_TO_QUOTATION_WIZARD &&\n                resultCode == Activity.RESULT_OK) {\n            crmLead.createQuotation(convertRequestRecord, data.getStringExtra(\"partner_id\"),\n                    data.getBooleanExtra(\"mark_won\", false), createQuotationListener);\n        }\n    }\n\n    CRMLead.OnOperationSuccessListener createQuotationListener = new CRMLead.\n            OnOperationSuccessListener() {\n        @Override\n        public void OnSuccess() {\n            Toast.makeText(getActivity(), _s(R.string.label_quotation_created) + \" \" +\n                    convertRequestRecord.getString(\"name\"), Toast.LENGTH_LONG).show();\n            parent().sync().requestSync(SaleOrder.AUTHORITY);\n        }\n\n        @Override\n        public void OnCancelled() {\n\n        }\n    };\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/addons/calendar/EventDetail.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 9/1/15 5:46 PM\n */\npackage com.odoo.addons.calendar;\n\nimport android.graphics.Color;\nimport android.graphics.drawable.ColorDrawable;\nimport android.os.Bundle;\nimport android.support.v7.app.ActionBar;\nimport android.support.v7.app.ActionBarActivity;\nimport android.text.format.DateUtils;\nimport android.util.Log;\nimport android.view.Menu;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.widget.ImageView;\nimport android.widget.Toast;\n\nimport com.odoo.addons.calendar.models.CalendarEvent;\nimport com.odoo.addons.calendar.utils.CalendarUtils;\nimport com.odoo.addons.calendar.utils.EventColorDialog;\nimport com.odoo.addons.calendar.utils.ReminderDialog;\nimport com.odoo.core.orm.ODataRow;\nimport com.odoo.core.orm.OValues;\nimport com.odoo.core.orm.fields.OColumn;\nimport com.odoo.core.utils.OActionBarUtils;\nimport com.odoo.core.utils.OAlert;\nimport com.odoo.core.utils.OControls;\nimport com.odoo.core.utils.ODateUtils;\nimport com.odoo.core.utils.OResource;\nimport com.odoo.core.utils.notification.ONotificationBuilder;\nimport com.odoo.core.utils.reminder.ReminderReceiver;\nimport com.odoo.core.utils.reminder.ReminderUtils;\nimport com.odoo.R;\n\nimport java.util.Date;\n\nimport odoo.controls.OField;\nimport odoo.controls.OForm;\n\npublic class EventDetail extends ActionBarActivity implements View.OnClickListener,\n        EventColorDialog.OnColorSelectListener, OField.IOnFieldValueChangeListener, ReminderDialog.OnReminderValueSelectListener {\n    public static final String TAG = EventDetail.class.getSimpleName();\n    private ActionBar actionBar;\n    public static final String KEY_RESCHEDULE = \"key_reschedule\";\n    private static final String KEY_EXTRA_EVENT_COLOR = \"event_color\";\n    private static final String KEY_COLOR_DATA = \"color_data\";\n    private String mEventColor = CalendarUtils.getBackgroundColors()[0];\n    private OForm eventForm;\n    private Integer mEventColorCode = 0;\n    private ReminderDialog.ReminderItem mReminder;\n    private ODataRow color_data = null;\n    private Boolean mAllDay = false;\n    private View mView = null;\n    private CalendarEvent calendarEvent;\n    private int row_id = -1;\n    private OField event_date_end, event_date_start, event_time_end, event_time_start, allDay;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.calendar_event_detail_form);\n        OActionBarUtils.setActionBar(this, true);\n        calendarEvent = new CalendarEvent(this, null);\n        actionBar = getSupportActionBar();\n        actionBar.setHomeAsUpIndicator(R.drawable.ic_action_mark_undone);\n        actionBar.setTitle(R.string.label_new_meeting);\n        mView = findViewById(R.id.eventForm);\n        event_date_end = (OField) findViewById(R.id.event_date_end);\n        event_time_end = (OField) findViewById(R.id.event_end_time);\n        event_date_start = (OField) findViewById(R.id.event_date_start);\n        event_time_start = (OField) findViewById(R.id.event_start_time);\n        allDay = (OField) findViewById(R.id.fieldAllDay);\n        if (savedInstanceState != null) {\n            mEventColor = savedInstanceState.getString(KEY_EXTRA_EVENT_COLOR);\n            color_data = savedInstanceState.getParcelable(KEY_COLOR_DATA);\n            colorSelected(color_data);\n        } else {\n            setThemeColor(mEventColor);\n        }\n        allDay.setOnValueChangeListener(this);\n        ((OField) findViewById(R.id.event_date_start)).setOnValueChangeListener(this);\n        ((OField) findViewById(R.id.event_start_time)).setOnValueChangeListener(this);\n        // OnClicks\n        findViewById(R.id.event_color).setOnClickListener(this);\n        findViewById(R.id.reminderForEvent).setOnClickListener(this);\n        Bundle extra = getIntent().getExtras();\n        eventForm = (OForm) mView;\n        eventForm.setModel(calendarEvent.getModelName());\n        if (extra != null) {\n            row_id = getIntent().getIntExtra(OColumn.ROW_ID, -1);\n            if (row_id != -1) {\n                findViewById(R.id.meetingDeleteLayout).setVisibility(View.VISIBLE);\n                findViewById(R.id.meetingDeleteLayout).setOnClickListener(this);\n                actionBar.setTitle(R.string.label_edit_meeting);\n                ODataRow record = calendarEvent.browse(row_id);\n                eventForm.initForm(record);\n                allDay.setValue(record.getBoolean(\"allday\"));\n                String dateFormat = (record.getBoolean(\"allday\")) ? ODateUtils.DEFAULT_DATE_FORMAT :\n                        ODateUtils.DEFAULT_FORMAT;\n                event_date_start.setValue(ODateUtils.parseDate(record.getString(\"date_start\"),\n                        dateFormat,\n                        ODateUtils.DEFAULT_DATE_FORMAT));\n                event_date_end.setValue(ODateUtils.parseDate(record.getString(\"date_end\"),\n                        dateFormat,\n                        ODateUtils.DEFAULT_DATE_FORMAT));\n                event_time_start.setValue(ODateUtils.parseDate(record.getString(\"date_start\"),\n                        dateFormat,\n                        ODateUtils.DEFAULT_TIME_FORMAT));\n                event_time_end.setValue(ODateUtils.parseDate(record.getString(\"date_end\"),\n                        dateFormat,\n                        ODateUtils.DEFAULT_TIME_FORMAT));\n                colorSelected(CalendarUtils.getColorData(record.getInt(\"color_index\")));\n            } else {\n                ODataRow opp_data = new ODataRow();\n                if (extra.containsKey(CalendarDashboard.KEY_DATE)) {\n                    event_date_start.setValue(extra.getString(CalendarDashboard.KEY_DATE));\n                    event_date_end.setValue(extra.getString(CalendarDashboard.KEY_DATE));\n                }\n                OField opp_field = (OField) findViewById(R.id.opportunity_id);\n                if (extra.containsKey(\"opp_id\")) {\n                    opp_field.setVisibility(View.VISIBLE);\n                    opp_data.put(\"opportunity_id\", extra.getInt(\"opp_id\"));\n                }\n                eventForm.initForm(opp_data);\n                opp_field.setEditable(false);\n            }\n        } else {\n            eventForm.initForm(null);\n        }\n        String action = getIntent().getAction();\n        if (action != null && (action.equals(ReminderReceiver.ACTION_EVENT_REMINDER_DONE) ||\n                action.equals(ReminderReceiver.ACTION_EVENT_REMINDER_RE_SCHEDULE))) {\n            ONotificationBuilder.cancelNotification(this, getIntent().getExtras().\n                    getInt(OColumn.ROW_ID));\n            if (action.equals(ReminderReceiver.ACTION_EVENT_REMINDER_DONE)) {\n                int row_id = getIntent().getExtras().getInt(OColumn.ROW_ID);\n                OValues values = new OValues();\n                values.put(\"is_done\", 1);\n                calendarEvent.update(row_id, values);\n                Toast.makeText(this, R.string.toast_event_marked_done, Toast.LENGTH_LONG).show();\n                extra.remove(KEY_RESCHEDULE);\n            }\n        }\n    }\n\n    @Override\n    public void onClick(View v) {\n        switch (v.getId()) {\n            case R.id.event_color:\n                CalendarUtils.colorDialog(this, mEventColor, this).show();\n                break;\n            case R.id.reminderForEvent:\n                ReminderDialog dialog = new ReminderDialog(this,\n                        (mAllDay) ? ReminderDialog.ReminderType.FullDayEvent :\n                                ReminderDialog.ReminderType.TimeBasedEvent);\n                dialog.setOnReminderValueSelectListener(this);\n                dialog.show();\n                break;\n            case R.id.meetingDeleteLayout:\n                OAlert.showConfirm(this, \"Are you sure want to delete meeting ?\",\n                        new OAlert.OnAlertConfirmListener() {\n                            @Override\n                            public void onConfirmChoiceSelect(OAlert.ConfirmType type) {\n                                switch (type) {\n                                    case POSITIVE:\n                                        calendarEvent.delete(row_id);\n                                        Toast.makeText(EventDetail.this, \"Meeting deleted\",\n                                                Toast.LENGTH_LONG).show();\n                                        finish();\n                                        break;\n                                    case NEGATIVE:\n                                }\n                            }\n                        });\n                break;\n        }\n    }\n\n    @Override\n    protected void onSaveInstanceState(Bundle outState) {\n        super.onSaveInstanceState(outState);\n        outState.putString(KEY_EXTRA_EVENT_COLOR, mEventColor);\n        outState.putParcelable(KEY_COLOR_DATA, color_data);\n    }\n\n    @Override\n    public void colorSelected(ODataRow color_data) {\n        if (color_data != null) {\n            mEventColor = color_data.getString(\"code\");\n            this.color_data = color_data;\n            ImageView event_color_view = (ImageView) findViewById(R.id.event_color_view);\n            event_color_view.setColorFilter(Color.parseColor(mEventColor));\n            OControls.setText(mView, R.id.event_color_label,\n                    color_data.getString(\"label\"));\n            mEventColorCode = color_data.getInt(\"index\");\n            setThemeColor(mEventColor);\n        }\n    }\n\n    private void setThemeColor(String color_code) {\n        int color = Color.parseColor(color_code);\n        actionBar.setBackgroundDrawable(new ColorDrawable(color));\n    }\n\n\n    @Override\n    public boolean onCreateOptionsMenu(Menu menu) {\n        getMenuInflater().inflate(R.menu.menu_calendar_detail, menu);\n        return true;\n    }\n\n    @Override\n    public boolean onOptionsItemSelected(MenuItem item) {\n        switch (item.getItemId()) {\n            case android.R.id.home:\n                finish();\n                break;\n            case R.id.menu_calendar_detail_save:\n                OValues values = eventForm.getValues();\n                if (values != null) {\n                    createMeeting(values);\n                }\n                break;\n        }\n        return super.onOptionsItemSelected(item);\n    }\n\n    private void createMeeting(OValues values) {\n        OValues meeting = new OValues();\n        meeting.put(\"name\", values.get(\"name\"));\n        meeting.put(\"allday\", values.get(\"allday\"));\n        meeting.put(\"location\", values.get(\"location\"));\n        meeting.put(\"description\", values.get(\"description\"));\n        meeting.put(\"class\", values.get(\"class\"));\n        meeting.put(\"color_index\", mEventColorCode);\n        if (values.contains(\"opportunity_id\")) {\n            meeting.put(\"opportunity_id\", values.get(\"opportunity_id\"));\n        }\n        if (calendarEvent.getColumn(\"date\") == null) {\n            //v7+\n            if (values.getBoolean(\"allday\")) {\n                meeting.put(\"start_date\", values.get(\"event_date_start\"));\n                meeting.put(\"stop_date\", values.get(\"event_date_end\"));\n                meeting.put(\"date_start\", meeting.get(\"start_date\"));\n                meeting.put(\"date_end\", meeting.get(\"stop_date\"));\n            } else {\n                String start_datetime = values.get(\"event_date_start\") + \" \" + values.get(\"event_time_start\");\n                String stop_datetime = values.get(\"event_date_end\") + \" \" + values.get(\"event_time_end\");\n                meeting.put(\"start_datetime\", start_datetime);\n                meeting.put(\"stop_datetime\", stop_datetime);\n                meeting.put(\"date_start\", meeting.get(\"start_datetime\"));\n                meeting.put(\"date_end\", meeting.get(\"stop_datetime\"));\n            }\n        } else {\n            //v7\n            String start_datetime = values.get(\"event_date_start\") + \" \" +\n                    values.get(\"event_time_start\");\n            String stop_datetime = values.get(\"event_date_end\") + \" \" +\n                    values.get(\"event_time_end\");\n            meeting.put(\"date\", start_datetime);\n            meeting.put(\"date_deadline\", stop_datetime);\n            meeting.put(\"date_start\", meeting.get(\"date\"));\n            meeting.put(\"date_end\", meeting.get(\"date_deadline\"));\n        }\n\n        String format = (meeting.getBoolean(\"allday\")) ? ODateUtils.DEFAULT_DATE_FORMAT :\n                ODateUtils.DEFAULT_FORMAT;\n        Date date_start = ODateUtils.createDateObject(meeting.getString(\"date_start\"),\n                format, false);\n        Date date_end = ODateUtils.createDateObject(meeting.getString(\"date_end\"),\n                format, false);\n        if (date_end.compareTo(date_start) < 0) {\n            OAlert.showWarning(this, OResource.string(this,\n                    R.string.error_end_date_small_than_start_date));\n        } else {\n            Date now = new Date();\n            Date reminderDate = null;\n            int diff = 99;\n            if (meeting.getBoolean(\"allday\")) {\n                if (DateUtils.isToday(date_start.getTime())) {\n                    diff = 0;\n                }\n            }\n            if (diff == 0 || now.compareTo(date_start) <= 0) {\n                meeting.put(\"has_reminder\", \"true\");\n                if (mReminder == null) {\n                    mReminder = ReminderDialog.getDefault(this, meeting.getBoolean(\"allday\"));\n                }\n                reminderDate = ReminderDialog.getReminderDateTime(meeting.getString(\"date_start\"),\n                        meeting.getBoolean(\"allday\"), mReminder);\n                if (reminderDate != null) {\n                    meeting.put(\"reminder_datetime\", ODateUtils.getDate(reminderDate,\n                            ODateUtils.DEFAULT_FORMAT));\n                }\n            }\n            if (row_id != -1) {\n                Log.i(TAG, \"Event updated\");\n                calendarEvent.update(row_id, meeting);\n            } else {\n                Log.i(TAG, \"Event created\");\n                row_id = calendarEvent.insert(meeting);\n            }\n            Bundle extra = new Bundle();\n            extra.putInt(OColumn.ROW_ID, row_id);\n            extra.putString(ReminderUtils.KEY_REMINDER_TYPE, \"event\");\n            if (reminderDate != null) {\n                if (ReminderUtils.get(getApplicationContext()).resetReminder(reminderDate, extra)) {\n                    Log.i(TAG, \"Reminder added.\");\n                }\n            }\n            finish();\n        }\n    }\n\n    public void onCheckedChanged(boolean isChecked) {\n        mAllDay = isChecked;\n        if (isChecked) {\n            OControls.setText(mView, R.id.reminderTypeName,\n                    String.format(OResource.string(this, R.string.on_the_day_at), \"9 AM\"));\n            findViewById(R.id.event_start_time).setVisibility(View.GONE);\n            findViewById(R.id.event_end_time).setVisibility(View.GONE);\n        } else {\n            OControls.setText(mView, R.id.reminderTypeName, OResource.string(this,\n                    R.string.at_the_time_of_event));\n            findViewById(R.id.event_start_time).setVisibility(View.VISIBLE);\n            findViewById(R.id.event_end_time).setVisibility(View.VISIBLE);\n        }\n    }\n\n    @Override\n    public void onFieldValueChange(OField field, Object value) {\n        if (field.getFieldName().equals(\"allday\"))\n            onCheckedChanged(Boolean.parseBoolean(value.toString()));\n        if (field.getFieldName().equals(\"event_date_start\")) {\n            event_date_end.setValue(value);\n        }\n        if (field.getFieldName().equals(\"event_time_start\")) {\n            event_time_end.setValue(value);\n        }\n    }\n\n    @Override\n    public void onReminderItemSelect(ReminderDialog.ReminderItem value) {\n        OControls.setText(mView, R.id.reminderTypeName, value.getTitle());\n        mReminder = value;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/addons/calendar/models/CalendarEvent.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 9/1/15 10:26 AM\n */\npackage com.odoo.addons.calendar.models;\n\nimport android.content.Context;\nimport android.net.Uri;\n\nimport com.odoo.addons.crm.models.CRMLead;\nimport com.odoo.addons.phonecall.models.CRMPhoneCalls;\nimport com.odoo.base.addons.res.ResPartner;\nimport com.odoo.base.addons.res.ResUsers;\nimport com.odoo.core.orm.OModel;\nimport com.odoo.core.orm.OValues;\nimport com.odoo.core.orm.annotation.Odoo;\nimport com.odoo.core.orm.fields.OColumn;\nimport com.odoo.core.orm.fields.types.OBoolean;\nimport com.odoo.core.orm.fields.types.ODate;\nimport com.odoo.core.orm.fields.types.ODateTime;\nimport com.odoo.core.orm.fields.types.OInteger;\nimport com.odoo.core.orm.fields.types.OSelection;\nimport com.odoo.core.orm.fields.types.OText;\nimport com.odoo.core.orm.fields.types.OVarchar;\nimport com.odoo.core.support.OUser;\n\nimport org.json.JSONArray;\n\nimport odoo.ODomain;\n\npublic class CalendarEvent extends OModel {\n    public static final String TAG = CalendarEvent.class.getSimpleName();\n    public static final String AUTHORITY = \"com.odoo.core.crm.provider.content.sync.calendar_event\";\n    private Context mContext;\n\n    OColumn name = new OColumn(\"Meeting Name\", OVarchar.class).setSize(64).setRequired();\n    @Odoo.api.v7\n    OColumn date = new OColumn(\"Start Date\", ODateTime.class);\n    @Odoo.api.v8\n    @Odoo.api.v9alpha\n    OColumn start_date = new OColumn(\"Start Date\", ODate.class);\n    @Odoo.api.v8\n    @Odoo.api.v9alpha\n    OColumn start_datetime = new OColumn(\"Start Date\", ODateTime.class);\n    @Odoo.api.v7\n    OColumn date_deadline = new OColumn(\"Dead Line\", ODateTime.class);\n    @Odoo.api.v8\n    @Odoo.api.v9alpha\n    OColumn stop_date = new OColumn(\"Stop Date\", ODate.class);\n    @Odoo.api.v8\n    @Odoo.api.v9alpha\n    OColumn stop_datetime = new OColumn(\"Stop Date\", ODateTime.class);\n    OColumn duration = new OColumn(\"Duration\", OVarchar.class).setSize(32);\n    OColumn allday = new OColumn(\"All Day\", OBoolean.class);\n    OColumn description = new OColumn(\"Description\", OText.class);\n    OColumn location = new OColumn(\"Location\", OText.class);\n\n    OColumn _class = new OColumn(\"Privacy\", OSelection.class)\n            .addSelection(\"public\", \"Public\")\n            .addSelection(\"private\", \"Private\")\n            .addSelection(\"confidential\", \"Public for Employees\")\n            .setDefaultValue(\"public\");\n\n    @Odoo.Functional(store = true, depends = {\"date\", \"start_date\",\n            \"start_datetime\"}, method = \"storeStartDate\")\n    OColumn date_start = new OColumn(\"Start Date\", ODateTime.class)\n            .setLocalColumn();\n\n    @Odoo.Functional(store = true, depends = {\"date_deadline\", \"stop_date\",\n            \"stop_datetime\"}, method = \"storeStopDate\")\n    OColumn date_end = new OColumn(\"Start Date\", ODateTime.class)\n            .setLocalColumn();\n\n    OColumn data_type = new OColumn(\"Data type\", OVarchar.class).setSize(34)\n            .setLocalColumn().setDefaultValue(\"event\");\n\n    OColumn is_done = new OColumn(\"Mark as Done\", OInteger.class)\n            .setLocalColumn().setDefaultValue(\"0\");\n\n    OColumn color_index = new OColumn(\"Color index\", OInteger.class).setSize(5)\n            .setLocalColumn().setDefaultValue(0);\n\n    OColumn has_reminder = new OColumn(\"Has reminder\", OBoolean.class).setLocalColumn()\n            .setDefaultValue(\"false\");\n    OColumn reminder_datetime = new OColumn(\"Reminder type\", ODateTime.class)\n            .setDefaultValue(\"false\").setLocalColumn();\n\n    OColumn user_id = new OColumn(\"Owner\", ResUsers.class, OColumn.RelationType.ManyToOne);\n    OColumn partner_ids = new OColumn(\"Attendees\", ResPartner.class, OColumn.RelationType.ManyToMany);\n\n\n    // PhoneCalls link\n    OColumn phonecall_id = new OColumn(\"Phone calls\", CRMPhoneCalls.class, OColumn.RelationType.ManyToOne);\n    //Opportunities id\n    OColumn opportunity_id = new OColumn(\"Opportunities\", CRMLead.class, OColumn.RelationType.ManyToOne)\n            .addDomain(\"type\", \"=\", \"opportunity\");\n\n    public CalendarEvent(Context context, OUser user) {\n        super(context, \"calendar.event\", user);\n        mContext = context;\n        if (getUser() != null && getUser().getVersion_number() != null) {\n            int version = getUser().getVersion_number();\n            if (version <= 7) {\n                setModelName(\"crm.meeting\");\n            }\n        }\n        // Setting 'class' variable name not allowed in java.\n        _class.setName(\"class\");\n        setHasMailChatter(true);\n    }\n\n    @Override\n    public ODomain defaultDomain() {\n        ODomain domain = new ODomain();\n        if (getOdooVersion().getVersion_number() <= 7) {\n            domain.add(\"|\");\n            domain.add(\"user_id\", \"=\", getUser().getUser_id());\n            domain.add(\"partner_ids\", \"in\", new JSONArray().put(getUser().getPartner_id()));\n        } else {\n            domain.add(\"partner_ids\", \"in\", new JSONArray().put(getUser().getPartner_id()));\n        }\n        domain.add(\"recurrency\", \"=\", false);\n        return domain;\n    }\n\n    @Override\n    public Uri uri() {\n        return buildURI(AUTHORITY);\n    }\n\n    public Uri agendaUri() {\n        return uri().buildUpon().appendPath(\"full_agenda\").build();\n    }\n\n    public String storeStartDate(OValues value) {\n        if (value.contains(\"date\")) {\n            return value.getString(\"date\");\n        }\n        if (!value.getString(\"start_date\").equals(\"false\"))\n            return value.getString(\"start_date\");\n        return value.getString(\"start_datetime\");\n    }\n\n    public String storeStopDate(OValues value) {\n        if (value.contains(\"date_deadline\")) {\n            return value.getString(\"date_deadline\");\n        }\n        if (!value.getString(\"stop_date\").equals(\"false\"))\n            return value.getString(\"stop_date\");\n        return value.getString(\"stop_datetime\");\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/addons/calendar/providers/CalendarSyncProvider.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 9/1/15 10:25 AM\n */\npackage com.odoo.addons.calendar.providers;\n\nimport android.database.Cursor;\nimport android.database.MatrixCursor;\nimport android.database.MergeCursor;\nimport android.net.Uri;\n\nimport com.odoo.addons.calendar.models.CalendarEvent;\nimport com.odoo.addons.crm.models.CRMLead;\nimport com.odoo.addons.phonecall.models.CRMPhoneCalls;\nimport com.odoo.core.orm.fields.OColumn;\nimport com.odoo.core.orm.provider.BaseModelProvider;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Locale;\n\npublic class CalendarSyncProvider extends BaseModelProvider {\n    public static final String TAG = CalendarSyncProvider.class.getSimpleName();\n    public static final int FULL_AGENDA = 114;\n\n    @Override\n    public boolean onCreate() {\n        String path = new CalendarEvent(getContext(), null).getModelName().toLowerCase(Locale.getDefault());\n        matcher.addURI(authority(), path + \"/full_agenda\", FULL_AGENDA);\n        return super.onCreate();\n    }\n\n\n    @Override\n    public void setModel(Uri uri) {\n        super.setModel(uri);\n        mModel = new CalendarEvent(getContext(), getUser(uri));\n    }\n\n    @Override\n    public Cursor query(Uri uri, String[] base_projection, String selection, String[] selectionArgs,\n                        String sortOrder) {\n        int match = matcher.match(uri);\n        CalendarEvent events = new CalendarEvent(getContext(), null);\n        if (match != FULL_AGENDA) {\n            return super.query(uri, base_projection, selection, selectionArgs, sortOrder);\n        }\n        String date_start = selectionArgs[0];\n        String filter = null;\n        if (selectionArgs.length > 1)\n            filter = selectionArgs[1];\n        String where;\n        List<String> args = new ArrayList<>();\n        // Getting events\n        MatrixCursor event_separator = new MatrixCursor(\n                new String[]{OColumn.ROW_ID, \"data_type\", \"name\"});\n\n        // Comparing date_start and date_end\n        where = \"(date(date_start) <= ? and date(date_end) >= ? )\";\n        args.add(date_start);\n        args.add(date_start);\n\n        if (filter != null) {\n            where += \" and name like ?\";\n            args.add(filter);\n        }\n        Cursor eventCR = getContext().getContentResolver().query(events.uri(),\n                base_projection, where, args.toArray(new String[args.size()]), \"is_done, date_start\");\n        if (eventCR.getCount() > 0)\n            event_separator.addRow(new String[]{\"0\", \"separator\", \"Meetings\"});\n\n\n        // Getting phone calls\n        CRMPhoneCalls phoneCalls = new CRMPhoneCalls(getContext(), null);\n        MatrixCursor phone_calls_separator = new MatrixCursor(\n                new String[]{OColumn.ROW_ID, \"data_type\", \"name\"});\n\n        // Comparing date\n        where = \"date(date) >=  ? and date(date) <= ? and (state = ? or state = ?)\";\n        args.clear();\n        args.add(date_start);\n        args.add(date_start);\n        args.add(\"open\");\n        args.add(\"pending\");\n        if (filter != null) {\n            where += \" and (name like ? or description like ?)\";\n            args.add(filter);\n            args.add(filter);\n        }\n        Cursor phoneCallsCR = getContext().getContentResolver().query(phoneCalls.uri(),\n                base_projection, where, args.toArray(new String[args.size()]), \"is_done , date\");\n        if (phoneCallsCR.getCount() > 0)\n            phone_calls_separator.addRow(new String[]{\"0\", \"separator\", \"Phone Calls\"});\n\n        // Getting opportunity\n        CRMLead opportunity = new CRMLead(getContext(), null);\n        MatrixCursor opportunity_separator = new MatrixCursor(\n                new String[]{OColumn.ROW_ID, \"data_type\", \"name\"});\n        // Comparing with create_date and date_action and type\n        where = \"(date(date_deadline) >= ? and date(date_deadline) <= ? or date(date_action) >= ? \" +\n                \"and date(date_action) <= ?) and type = ?\";\n        args.clear();\n        args.add(date_start);\n        args.add(date_start);\n        args.add(date_start);\n        args.add(date_start);\n        args.add(\"opportunity\");\n        if (filter != null) {\n            where += \" and (name like ? or description like ?)\";\n            args.add(filter);\n            args.add(filter);\n        }\n        Cursor opportunityCR = getContext().getContentResolver().query(opportunity.uri(),\n                base_projection, where, args.toArray(new String[args.size()]), sortOrder);\n        if (opportunityCR.getCount() > 0)\n            opportunity_separator.addRow(new String[]{\"0\", \"separator\", \"Opportunities\"});\n        MergeCursor mergedData = new MergeCursor(new Cursor[]{\n                event_separator, eventCR, phone_calls_separator, phoneCallsCR, opportunity_separator,\n                opportunityCR});\n        return mergedData;\n    }\n\n    @Override\n    public String authority() {\n        return CalendarEvent.AUTHORITY;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/addons/calendar/services/CalendarSyncService.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 9/1/15 3:57 PM\n */\npackage com.odoo.addons.calendar.services;\n\nimport android.content.Context;\nimport android.content.SyncResult;\nimport android.os.Bundle;\nimport android.util.Log;\n\nimport com.odoo.addons.calendar.models.CalendarEvent;\nimport com.odoo.core.account.BaseSettings;\nimport com.odoo.core.orm.ODataRow;\nimport com.odoo.core.orm.OValues;\nimport com.odoo.core.orm.fields.OColumn;\nimport com.odoo.core.service.ISyncFinishListener;\nimport com.odoo.core.service.OSyncAdapter;\nimport com.odoo.core.service.OSyncService;\nimport com.odoo.core.support.OUser;\nimport com.odoo.core.utils.ODateUtils;\nimport com.odoo.core.utils.reminder.ReminderUtils;\n\nimport java.util.Date;\nimport java.util.List;\n\npublic class CalendarSyncService extends OSyncService implements ISyncFinishListener {\n    public static final String TAG = CalendarSyncService.class.getSimpleName();\n    public static final int SYNC_SLEEP_DELAY = 2000;\n\n    @Override\n    public OSyncAdapter getSyncAdapter(OSyncService service, Context context) {\n        return new OSyncAdapter(context, CalendarEvent.class, service, true);\n    }\n\n    @Override\n    public void performDataSync(OSyncAdapter adapter, Bundle extras, OUser user) {\n        if (adapter.getModel().getModelName().equals(\"calendar.event\")) {\n            adapter.onSyncFinish(this).syncDataLimit(50);\n        }\n    }\n\n\n    @Override\n    public OSyncAdapter performNextSync(OUser user, SyncResult syncResult) {\n        // Setting reminders to events\n        CalendarEvent event = new CalendarEvent(getApplicationContext(), null);\n        List<ODataRow> rows = event.select();\n        int count = 0;\n        for (ODataRow row : rows) {\n            if (row.getBoolean(\"allday\")) {\n                String defaultTime = BaseSettings.getDayStartTime(getApplicationContext());\n                row.put(\"date_start\", row.getString(\"date_start\") + \" \" + defaultTime);\n            }\n            Date start_date = ODateUtils.createDateObject(row.getString(\"date_start\"),\n                    ODateUtils.DEFAULT_FORMAT, false);\n            Date now = new Date();\n\n            if (now.compareTo(start_date) < 0) {\n                Bundle extra = row.getPrimaryBundleData();\n                extra.putString(ReminderUtils.KEY_REMINDER_TYPE, \"event\");\n                if (ReminderUtils.get(getApplicationContext()).resetReminder(start_date, extra)) {\n                    OValues values = new OValues();\n                    values.put(\"_is_dirty\", \"false\");\n                    values.put(\"has_reminder\", \"true\");\n                    event.update(row.getInt(OColumn.ROW_ID), values);\n                    count++;\n                }\n            }\n        }\n        Log.i(TAG, count + \" reminder updated\");\n        return null;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/addons/calendar/utils/CalendarUtils.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 12/1/15 11:12 AM\n */\npackage com.odoo.addons.calendar.utils;\n\nimport android.app.AlertDialog;\nimport android.content.Context;\nimport android.graphics.Color;\n\nimport com.odoo.core.orm.ODataRow;\n\npublic class CalendarUtils {\n    public static final String TAG = CalendarUtils.class.getSimpleName();\n    private static String[] background_colors = {\"#a24689\", \"#d40000\",\n            \"#f24f1d\", \"#f5be27\", \"#0a7d40\", \"#35b579\", \"#029ce3\", \"#405ea8\",\n            \"#7986c9\", \"#8b23a8\", \"#e37971\", \"#616161\"};\n    private static String[] color_label = {\"Default Color\", \"Tomato\",\n            \"Tangerine\", \"Banana\", \"Basil\", \"Sage\", \"Peacock\", \"Blueberry\",\n            \"Lavender\", \"Grape\", \"Flamingo\", \"Graphite\"};\n\n    public static String[] getBackgroundColors() {\n        return background_colors;\n    }\n\n    public static String[] getColorLabels() {\n        return color_label;\n    }\n\n    public static int getBackgroundColor(int color_number) {\n        if (color_number < background_colors.length) {\n            return Color.parseColor(background_colors[color_number]);\n        }\n        return Color.parseColor(\"#ffffff\");\n    }\n\n    public static String getColorLabel(int color_number) {\n        if (color_number < color_label.length) {\n            return color_label[color_number];\n        }\n        return \"Default Color\";\n    }\n\n    public static ODataRow getColorData(int index) {\n        ODataRow clr = new ODataRow();\n        clr.put(\"index\", index);\n        clr.put(\"code\", background_colors[index]);\n        clr.put(\"label\", color_label[index]);\n        return clr;\n    }\n\n    public static AlertDialog colorDialog(Context context, String selected,\n                                          EventColorDialog.OnColorSelectListener listener) {\n        EventColorDialog dialog = new EventColorDialog(context, selected,\n                listener);\n        return dialog.build();\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/addons/calendar/utils/EventColorDialog.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 12/1/15 11:13 AM\n */\npackage com.odoo.addons.calendar.utils;\n\nimport android.app.AlertDialog;\nimport android.app.AlertDialog.Builder;\nimport android.content.Context;\nimport android.graphics.Color;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.AdapterView;\nimport android.widget.ArrayAdapter;\nimport android.widget.GridView;\nimport android.widget.ImageView;\nimport android.widget.LinearLayout;\nimport android.widget.TextView;\n\nimport com.odoo.core.orm.ODataRow;\nimport com.odoo.R;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class EventColorDialog implements AdapterView.OnItemClickListener {\n    public static final String TAG = EventColorDialog.class.getSimpleName();\n    private Builder builder = null;\n    private Context mContext;\n    private ArrayAdapter<ODataRow> mAdapter;\n    private List<ODataRow> colors = new ArrayList<ODataRow>();\n    private String selectedColor;\n    private OnColorSelectListener mOnColorSelectListener;\n    private AlertDialog alertDialog;\n\n    public EventColorDialog(Context context, String selected_color,\n                            OnColorSelectListener listener) {\n        mContext = context;\n        selectedColor = selected_color;\n        mOnColorSelectListener = listener;\n        String[] bg_colors = CalendarUtils.getBackgroundColors();\n        String[] color_labels = CalendarUtils.getColorLabels();\n        for (int i = 0; i < bg_colors.length; i++) {\n            ODataRow clr = new ODataRow();\n            clr.put(\"index\", i);\n            clr.put(\"code\", bg_colors[i]);\n            clr.put(\"label\", color_labels[i]);\n            colors.add(clr);\n        }\n    }\n\n    public AlertDialog build() {\n        builder = new Builder(mContext);\n        builder.setView(getColorGrid());\n        alertDialog = builder.create();\n        return alertDialog;\n    }\n\n    private View getColorGrid() {\n        LinearLayout layout = (LinearLayout) LayoutInflater.from(mContext)\n                .inflate(R.layout.event_color_grid, null, false);\n        initGrid((GridView) layout.findViewById(R.id.event_grid));\n        return layout;\n    }\n\n    private void initGrid(GridView view) {\n        mAdapter = new ArrayAdapter<ODataRow>(mContext,\n                R.layout.event_color_chooser_item, colors) {\n            @Override\n            public View getView(int position, View convertView, ViewGroup parent) {\n                ODataRow row = colors.get(position);\n                View view = convertView;\n                if (view == null) {\n                    view = LayoutInflater.from(mContext).inflate(\n                            R.layout.event_color_chooser_item, parent, false);\n                }\n\n                TextView color_label = (TextView) view\n                        .findViewById(R.id.color_label);\n                color_label.setText(row.getString(\"label\"));\n                ImageView color_view = (ImageView) view\n                        .findViewById(R.id.color_view);\n                color_view.setColorFilter(Color.parseColor(row\n                        .getString(\"code\")));\n\n                boolean mSelected = (selectedColor.equals(row.getString(\"code\")));\n                if (mSelected) {\n                    color_label.setTextColor(mContext.getResources().getColor(\n                            R.color.theme_secondary_dark));\n                    view.findViewById(R.id.color_view_selected).setVisibility(\n                            View.VISIBLE);\n                } else {\n                    color_label.setTextColor(Color.parseColor(\"#414141\"));\n                    view.findViewById(R.id.color_view_selected).setVisibility(\n                            View.GONE);\n                }\n                return view;\n            }\n        };\n        view.setAdapter(mAdapter);\n        view.setOnItemClickListener(this);\n    }\n\n    public interface OnColorSelectListener {\n        public void colorSelected(ODataRow color_data);\n    }\n\n    @Override\n    public void onItemClick(AdapterView<?> parent, View view, int position,\n                            long id) {\n        if (mOnColorSelectListener != null) {\n            mOnColorSelectListener.colorSelected(colors.get(position));\n        }\n        alertDialog.dismiss();\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/addons/calendar/utils/ReminderDialog.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 12/1/15 3:47 PM\n */\npackage com.odoo.addons.calendar.utils;\n\nimport android.app.AlertDialog;\nimport android.content.Context;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.AbsListView;\nimport android.widget.AdapterView;\nimport android.widget.ListView;\n\nimport com.odoo.core.account.BaseSettings;\nimport com.odoo.core.support.list.OListAdapter;\nimport com.odoo.core.utils.OControls;\nimport com.odoo.core.utils.ODateUtils;\nimport com.odoo.core.utils.OPreferenceManager;\nimport com.odoo.core.utils.OResource;\nimport com.odoo.R;\n\nimport java.util.ArrayList;\nimport java.util.Date;\nimport java.util.List;\n\npublic class ReminderDialog implements AdapterView.OnItemClickListener {\n    public static final String TAG = ReminderDialog.class.getSimpleName();\n\n    private AlertDialog.Builder mBuilder;\n    private AlertDialog mDialog;\n    private Context mContext;\n    private ReminderType mType;\n    private OListAdapter mAdapter;\n    private OnReminderValueSelectListener mOnReminderValueSelectListener = null;\n    private List<Object> reminderTypes = new ArrayList<>();\n    private OPreferenceManager mPref;\n\n    public enum ReminderType {\n        FullDayEvent, TimeBasedEvent\n    }\n\n    public ReminderDialog(Context context, ReminderType type) {\n        mContext = context;\n        reminderTypes.clear();\n        mPref = new OPreferenceManager(mContext);\n        mType = type;\n        List<ReminderItem> reminders = new ArrayList<>();\n        reminders.add(0, new ReminderItem(0, OResource.string(mContext, R.string.no_notification), \"false\"));\n        switch (mType) {\n            case FullDayEvent:\n                // At your working day start time\n                String workingStartTime = ODateUtils.parseDate(mPref.getString(BaseSettings.KEY_LEAD_WORK_DAY_START_TIME,\n                                OResource.string(mContext, R.string.default_day_start_time)), ODateUtils.DEFAULT_TIME_FORMAT,\n                        ODateUtils.DEFAULT_TIME_FORMAT);\n                reminders.add(1, new ReminderItem(1,\n                        OResource.string(mContext, R.string.on_your_working_day_start_time),\n                        workingStartTime));\n                // At 9 AM\n                reminders.add(2, new ReminderItem(2,\n                        String.format(OResource.string(mContext, R.string.on_the_day_at), \"9 AM\"), \"9:00 AM\"));\n                // before day at 11:30 PM\n                reminders.add(3, new ReminderItem(3,\n                        String.format(OResource.string(mContext, R.string.day_before_at), \"11:30 PM\"), \"11:30 PM\"));\n                // before day at 5:00 PM\n                reminders.add(4, new ReminderItem(4,\n                        String.format(OResource.string(mContext, R.string.day_before_at), \"5 PM\"), \"5:00 PM\"));\n                break;\n            case TimeBasedEvent:\n                // At the time of event\n                reminders.add(new ReminderItem(1, OResource.string(mContext, R.string.at_the_time_of_event), 1));\n                // 30 min before\n                reminders.add(new ReminderItem(2,\n                        String.format(OResource.string(mContext, R.string.minutes_before), \"30\"), 30));\n                // 10 min before\n                reminders.add(new ReminderItem(3,\n                        String.format(OResource.string(mContext, R.string.minutes_before), \"10\"), 10));\n                break;\n        }\n        //TODO Custom reminder: reminders.add(new ReminderItem(4, OResource.string(mContext, R.string.custom), -1));\n        reminderTypes.addAll(reminders);\n    }\n\n    public List<Object> getReminderTypes() {\n        return reminderTypes;\n    }\n\n    public void show() {\n        mBuilder = new AlertDialog.Builder(mContext);\n        mBuilder.setView(generateView());\n        mDialog = mBuilder.create();\n        mDialog.show();\n    }\n\n    public static ReminderItem getDefault(Context context, boolean allDay) {\n        ReminderDialog dialog = new ReminderDialog(context,\n                (allDay) ? ReminderType.FullDayEvent : ReminderType.TimeBasedEvent);\n        return (ReminderItem) dialog.getReminderTypes().get(1);\n    }\n\n    private View generateView() {\n        AbsListView.LayoutParams param = new AbsListView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,\n                ViewGroup.LayoutParams.MATCH_PARENT);\n        ListView list = new ListView(mContext);\n        list.setLayoutParams(param);\n        mAdapter = new OListAdapter(mContext, R.layout.reminder_item_view, reminderTypes) {\n            @Override\n            public View getView(int position, View convertView, ViewGroup parent) {\n                if (convertView == null)\n                    convertView = LayoutInflater.from(mContext).inflate(getResource(),\n                            parent, false);\n                ReminderItem item = (ReminderItem) getItem(position);\n                OControls.setText(convertView, R.id.reminderTitle, item.getTitle());\n                return convertView;\n            }\n        };\n        list.setAdapter(mAdapter);\n        list.setOnItemClickListener(this);\n        return list;\n    }\n\n    public static Date getReminderDateTime(String eventDateTime, Boolean allDay, ReminderItem item) {\n        String format = (allDay) ? ODateUtils.DEFAULT_DATE_FORMAT : ODateUtils.DEFAULT_FORMAT;\n        Date eventDate = ODateUtils.createDateObject(eventDateTime, format, false);\n        if (item.getRequest_code() != 0) {\n            Date dayBefore = ODateUtils.getDateDayBefore(eventDate, 1);\n            if (allDay) {\n                switch (item.getRequest_code()) {\n                    case 1:\n                        return ODateUtils.createDateObject(eventDateTime + \" \" + item.getValue(),\n                                ODateUtils.DEFAULT_FORMAT, true);\n                    case 2:\n                        return ODateUtils.setDateTime(eventDate, 9, 0, 0);\n                    case 3:\n                        return ODateUtils.setDateTime(dayBefore, 23, 30, 0);\n                    case 4:\n                        return ODateUtils.setDateTime(dayBefore, 17, 0, 0);\n                }\n            } else {\n                switch (item.getRequest_code()) {\n                    case 1:\n                        return eventDate;\n                    case 2:\n                    case 3:\n                        return ODateUtils.getDateMinuteBefore(eventDate, (Integer) item.getValue());\n                }\n            }\n        }\n        return null;\n    }\n\n    @Override\n    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {\n        ReminderItem item = (ReminderItem) mAdapter.getItem(position);\n        switch (item.getRequest_code()) {\n            case 0:\n            case 1:\n            case 2:\n            case 3:\n                if (mOnReminderValueSelectListener != null) {\n                    mOnReminderValueSelectListener.onReminderItemSelect(item);\n                }\n                mDialog.dismiss();\n                break;\n            case 4:\n                // TODO: Open custom dialog for reminder config\n                break;\n        }\n    }\n\n    public void setOnReminderValueSelectListener(OnReminderValueSelectListener listener) {\n        mOnReminderValueSelectListener = listener;\n    }\n\n    public interface OnReminderValueSelectListener {\n        public void onReminderItemSelect(ReminderItem value);\n    }\n\n    public static class ReminderItem {\n        int request_code;\n        String title;\n        Object value;\n\n        public ReminderItem(int request_code, String title, Object value) {\n            this.request_code = request_code;\n            this.title = title;\n            this.value = value;\n        }\n\n        public int getRequest_code() {\n            return request_code;\n        }\n\n        public void setRequest_code(int request_code) {\n            this.request_code = request_code;\n        }\n\n        public String getTitle() {\n            return title;\n        }\n\n        public void setTitle(String title) {\n            this.title = title;\n        }\n\n        public Object getValue() {\n            return value;\n        }\n\n        public void setValue(Object value) {\n            this.value = value;\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/addons/calendar/utils/TodayIcon.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 9/1/15 5:27 PM\n */\npackage com.odoo.addons.calendar.utils;\n\nimport android.content.Context;\nimport android.content.res.Resources;\nimport android.graphics.Bitmap;\nimport android.graphics.BitmapFactory;\nimport android.graphics.Canvas;\nimport android.graphics.Color;\nimport android.graphics.Paint.Align;\nimport android.graphics.Rect;\nimport android.graphics.Typeface;\nimport android.graphics.drawable.BitmapDrawable;\nimport android.graphics.drawable.Drawable;\nimport android.text.TextPaint;\n\nimport com.odoo.R;\n\nimport java.util.Calendar;\nimport java.util.Locale;\n\npublic class TodayIcon {\n    public static final String TAG = TodayIcon.class.getSimpleName();\n    private Context mContext;\n    private Resources mRes;\n    private TextPaint mPaint = new TextPaint();\n    private Rect mBounds = new Rect();\n    private Canvas mCanvas = new Canvas();\n    private Bitmap mDefaultIcon;\n\n    public TodayIcon(Context context) {\n        mContext = context;\n        mRes = mContext.getResources();\n    }\n\n    private int date() {\n        return Calendar.getInstance(Locale.getDefault()).get(\n                Calendar.DAY_OF_MONTH);\n    }\n\n    public static TodayIcon get(Context context) {\n        return new TodayIcon(context);\n    }\n\n    public Drawable getIcon() {\n        mPaint.setTypeface(Typeface.create(\"sans-serif\", Typeface.BOLD));\n        mPaint.setColor(Color.WHITE);\n        mPaint.setTextAlign(Align.CENTER);\n        mPaint.setAntiAlias(true);\n        mPaint.setTextSize(mRes.getDimension(R.dimen.text_size_xxsmall));\n        mDefaultIcon = BitmapFactory.decodeResource(mRes,\n                R.drawable.ic_action_goto_today);\n        Bitmap bmp = generate(mDefaultIcon.getWidth(), mDefaultIcon.getHeight());\n        return new BitmapDrawable(mRes, bmp);\n    }\n\n    private Bitmap generate(int width, int height) {\n        final String date = (date() < 10) ? \"0\" + date() + \"\" : date() + \"\";\n        final Canvas c = mCanvas;\n        final Bitmap bitmap = Bitmap.createBitmap(width, height,\n                Bitmap.Config.ARGB_8888);\n        c.setBitmap(bitmap);\n        c.drawBitmap(mDefaultIcon, 0, 0, null);\n        c.drawColor(Color.TRANSPARENT);\n        mPaint.getTextBounds(date, 0, 2, mBounds);\n        c.drawText(date, 0, 2, width / 2, 5 + height / 2\n                + (mBounds.bottom - mBounds.top) / 2, mPaint);\n        return bitmap;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/addons/crm/CRMDetail.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 13/1/15 3:40 PM\n */\npackage com.odoo.addons.crm;\n\nimport android.app.Activity;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.support.v7.app.ActionBar;\nimport android.support.v7.app.ActionBarActivity;\nimport android.view.Menu;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.widget.TextView;\nimport android.widget.Toast;\n\nimport com.odoo.App;\nimport com.odoo.addons.crm.models.CRMCaseStage;\nimport com.odoo.addons.crm.models.CRMLead;\nimport com.odoo.addons.customers.Customers;\nimport com.odoo.addons.sale.models.SaleOrder;\nimport com.odoo.base.addons.res.ResCompany;\nimport com.odoo.base.addons.res.ResUsers;\nimport com.odoo.core.orm.ODataRow;\nimport com.odoo.core.orm.OModel;\nimport com.odoo.core.orm.OValues;\nimport com.odoo.core.orm.fields.OColumn;\nimport com.odoo.core.support.sync.SyncUtils;\nimport com.odoo.core.utils.OActionBarUtils;\nimport com.odoo.core.utils.OAlert;\nimport com.odoo.core.utils.ODateUtils;\nimport com.odoo.core.utils.OResource;\nimport com.odoo.core.utils.StringUtils;\nimport com.odoo.R;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport odoo.controls.OForm;\n\npublic class CRMDetail extends ActionBarActivity {\n    public static final String TAG = CRMDetail.class.getSimpleName();\n    public static final int REQUEST_CONVERT_TO_OPPORTUNITY_WIZARD = 1223;\n    public static final int REQUEST_CONVERT_TO_QUOTATION_WIZARD = 1224;\n    private Bundle extra;\n    private OForm mForm;\n    private ODataRow record;\n    private CRMLead crmLead;\n    private ActionBar actionBar;\n    private Menu menu;\n    private String wonLost = \"won\";\n    private String type = \"lead\";\n    private TextView currency_symbol;\n    private int stage_id = -1;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.crm_detail);\n        OActionBarUtils.setActionBar(this, true);\n        actionBar = getSupportActionBar();\n        crmLead = new CRMLead(this, null);\n        extra = getIntent().getExtras();\n        init();\n    }\n\n    private void init() {\n        mForm = (OForm) findViewById(R.id.crmLeadForm);\n        currency_symbol = (TextView) findViewById(R.id.currency_symbol);\n        if (!extra.containsKey(OColumn.ROW_ID)) {\n            if (extra.getString(\"type\").equals(Customers.Type.Opportunities.toString())) {\n                type = \"opportunity\";\n                findViewById(R.id.opportunity_controls).setVisibility(View.VISIBLE);\n            }\n            if (extra.containsKey(\"stage_id\")) {\n                stage_id = extra.getInt(\"stage_id\");\n            }\n            mForm.initForm(null);\n            actionBar.setTitle(R.string.label_tag_new);\n            actionBar.setHomeAsUpIndicator(R.drawable.ic_action_navigation_close);\n            ODataRow currency = ResCompany.getCurrency(this);\n            if (currency != null) {\n                currency_symbol.setText(currency.getString(\"symbol\"));\n            }\n        } else {\n            initFormValues();\n        }\n        mForm.setEditable(true);\n\n    }\n\n    private void initFormValues() {\n        record = crmLead.browse(extra.getInt(OColumn.ROW_ID));\n        if (record == null) {\n            finish();\n        }\n        ODataRow currency = record.getM2ORecord(\"company_currency\").browse();\n        if (currency != null) {\n            currency_symbol.setText(currency.getString(\"symbol\"));\n        }\n        if (!record.getString(\"type\").equals(\"lead\")) {\n            actionBar.setTitle(R.string.label_opportunity);\n            type = \"opportunity\";\n            findViewById(R.id.opportunity_controls).setVisibility(View.VISIBLE);\n        } else {\n            actionBar.setTitle(R.string.label_lead);\n        }\n        mForm.initForm(record);\n    }\n\n    @Override\n    public boolean onCreateOptionsMenu(Menu menu) {\n        getMenuInflater().inflate(R.menu.menu_lead_detail, menu);\n        this.menu = menu;\n        toggleMenu();\n        return true;\n    }\n\n    private void toggleMenu() {\n        if (!extra.containsKey(OColumn.ROW_ID)) {\n            menu.findItem(R.id.menu_lead_detail_more).setVisible(false);\n        } else {\n            initFormValues();\n            menu.findItem(R.id.menu_lead_detail_more).setVisible(true);\n            if (record.getString(\"type\").equals(CRMLead.KEY_LEAD)) {\n                menu.findItem(R.id.menu_lead_convert_to_quotation).setVisible(false);\n                menu.findItem(R.id.menu_mark_won).setVisible(false);\n            } else if (record.getString(\"type\").equals(crmLead.KEY_OPPORTUNITY)) {\n                menu.findItem(R.id.menu_lead_convert_to_opportunity).setVisible(false);\n            }\n        }\n        menu.findItem(R.id.menu_lead_save).setVisible(true);\n        actionBar.setHomeAsUpIndicator(R.drawable.ic_action_navigation_close);\n\n    }\n\n    @Override\n    public boolean onOptionsItemSelected(MenuItem item) {\n        App app = (App) getApplicationContext();\n        switch (item.getItemId()) {\n            case android.R.id.home:\n                finish();\n                break;\n            case R.id.menu_lead_save:\n                OValues values = mForm.getValues();\n                if (stage_id != OModel.INVALID_ROW_ID) {\n                    values.put(\"stage_id\", stage_id);\n                }\n                if (values != null) {\n                    values.put(\"type\", type);\n                    int row_id;\n                    if (record != null) {\n                        crmLead.update(record.getInt(OColumn.ROW_ID), values);\n                        row_id = record.getInt(OColumn.ROW_ID);\n                    } else {\n                        values.put(\"company_id\", ResCompany.myId(this));\n                        values.put(\"company_currency\", ResCompany.myCurrency(this));\n                        values.put(\"create_date\", ODateUtils.getUTCDate());\n                        values.put(\"user_id\", ResUsers.myId(this));\n                        CRMCaseStage stages = new CRMCaseStage(this, null);\n                        ODataRow row;\n                        if (!values.contains(\"stage_id\")) {\n                            row = stages.browse(new String[]{\"name\"}, \"name = ?\", new String[]{\"New\"});\n                        } else {\n                            row = stages.browse(stage_id);\n                        }\n                        if (row != null) {\n                            values.put(\"stage_id\", row.getInt(OColumn.ROW_ID));\n                            values.put(\"stage_name\", row.getString(\"name\"));\n                        }\n\n                        values.put(\"display_name\", values.getString(\"partner_name\"));\n                        values.put(\"assignee_name\", crmLead.getUser().getName());\n                        row_id = crmLead.insert(values);\n                    }\n                    crmLead.setReminder(row_id);\n                    finish();\n\n                }\n                break;\n            case R.id.menu_lead_convert_to_opportunity:\n                if (record.getInt(\"id\") == 0) {\n                    OAlert.showWarning(this, OResource.string(this, R.string.label_sync_warning));\n                } else {\n                    if (app.inNetwork()) {\n                        int count = crmLead.count(\"id != ? and partner_id = ? and \" + OColumn.ROW_ID + \" != ?\"\n                                , new String[]{\n                                \"0\",\n                                record.getInt(\"partner_id\") + \"\",\n                                record.getString(OColumn.ROW_ID)\n                        });\n                        if (count > 0) {\n                            Intent intent = new Intent(this, ConvertToOpportunityWizard.class);\n                            intent.putExtras(record.getPrimaryBundleData());\n                            startActivityForResult(intent, REQUEST_CONVERT_TO_OPPORTUNITY_WIZARD);\n                        } else {\n                            crmLead.convertToOpportunity(record, new ArrayList<Integer>(), convertDoneListener);\n                        }\n                    } else {\n                        Toast.makeText(this, R.string.toast_network_required, Toast.LENGTH_LONG).show();\n                    }\n                }\n                break;\n            case R.id.menu_mark_won:\n                if (app.inNetwork()) {\n                    crmLead.markWonLost(wonLost, record, markDoneListener);\n                } else {\n                    Toast.makeText(this, R.string.toast_network_required, Toast.LENGTH_LONG).show();\n                }\n                break;\n            case R.id.menu_mark_lost:\n                wonLost = \"lost\";\n                if (app.inNetwork()) {\n                    crmLead.markWonLost(wonLost, record, markDoneListener);\n                } else {\n                    Toast.makeText(this, R.string.toast_network_required, Toast.LENGTH_LONG).show();\n                }\n                break;\n            case R.id.menu_lead_convert_to_quotation:\n                if (app.inNetwork()) {\n                    Intent intent = new Intent(this, ConvertToQuotation.class);\n                    intent.putExtras(record.getPrimaryBundleData());\n                    startActivityForResult(intent, REQUEST_CONVERT_TO_QUOTATION_WIZARD);\n                } else {\n                    Toast.makeText(this, R.string.toast_network_required, Toast.LENGTH_LONG).show();\n                }\n                break;\n\n        }\n        return super.onOptionsItemSelected(item);\n    }\n\n    @Override\n    protected void onActivityResult(int requestCode, int resultCode, Intent data) {\n        super.onActivityResult(requestCode, resultCode, data);\n        if (requestCode == REQUEST_CONVERT_TO_OPPORTUNITY_WIZARD && resultCode == RESULT_OK) {\n            List<Integer> ids = data.getIntegerArrayListExtra(ConvertToOpportunityWizard.KEY_LEADS_IDS);\n            crmLead.convertToOpportunity(record, ids, convertDoneListener);\n        }\n        if (requestCode == REQUEST_CONVERT_TO_QUOTATION_WIZARD && resultCode == Activity.RESULT_OK) {\n            crmLead.createQuotation(record, data.getStringExtra(\"partner_id\"), data.getBooleanExtra(\"mark_won\", false), createQuotationListener);\n        }\n    }\n\n    CRMLead.OnOperationSuccessListener createQuotationListener =\n            new CRMLead.OnOperationSuccessListener() {\n                @Override\n                public void OnSuccess() {\n                    Toast.makeText(CRMDetail.this, OResource.string(CRMDetail.this,\n                            R.string.label_quotation_created) + \" \" +\n                            record.getString(\"name\"), Toast.LENGTH_LONG).show();\n                    SyncUtils sync = new SyncUtils(CRMDetail.this, crmLead.getUser());\n                    sync.requestSync(SaleOrder.AUTHORITY);\n                }\n\n\n                @Override\n                public void OnCancelled() {\n\n                }\n            };\n    CRMLead.OnOperationSuccessListener markDoneListener = new CRMLead.OnOperationSuccessListener() {\n        @Override\n        public void OnSuccess() {\n            Toast.makeText(CRMDetail.this, StringUtils.capitalizeString(record.getString(\"type\"))\n                    + \" marked \" + wonLost, Toast.LENGTH_LONG).show();\n            finish();\n        }\n\n        @Override\n        public void OnCancelled() {\n\n        }\n    };\n    CRMLead.OnOperationSuccessListener convertDoneListener = new CRMLead.OnOperationSuccessListener() {\n        @Override\n        public void OnSuccess() {\n            Toast.makeText(CRMDetail.this, R.string.label_convert_to_opportunity, Toast.LENGTH_LONG).show();\n            Intent intent = new Intent(CRMDetail.this, CRMDetail.class);\n            intent.putExtra(OColumn.ROW_ID, record.getInt(OColumn.ROW_ID));\n            startActivity(intent);\n\n            finish();\n        }\n\n        @Override\n        public void OnCancelled() {\n\n        }\n    };\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/addons/crm/CRMLeads.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 13/1/15 10:24 AM\n */\npackage com.odoo.addons.crm;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.database.Cursor;\nimport android.os.Bundle;\nimport android.os.Handler;\nimport android.support.annotation.Nullable;\nimport android.support.v4.app.LoaderManager;\nimport android.support.v4.content.CursorLoader;\nimport android.support.v4.content.Loader;\nimport android.support.v4.widget.SwipeRefreshLayout;\nimport android.text.TextUtils;\nimport android.view.LayoutInflater;\nimport android.view.Menu;\nimport android.view.MenuInflater;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.ListView;\nimport android.widget.Toast;\n\nimport com.odoo.addons.crm.models.CRMLead;\nimport com.odoo.addons.customers.Customers;\nimport com.odoo.base.addons.res.ResPartner;\nimport com.odoo.core.orm.ODataRow;\nimport com.odoo.core.orm.fields.OColumn;\nimport com.odoo.core.support.addons.fragment.BaseFragment;\nimport com.odoo.core.support.addons.fragment.IOnSearchViewChangeListener;\nimport com.odoo.core.support.addons.fragment.ISyncStatusObserverListener;\nimport com.odoo.core.support.drawer.ODrawerItem;\nimport com.odoo.core.support.list.IOnItemClickListener;\nimport com.odoo.core.support.list.OCursorListAdapter;\nimport com.odoo.core.utils.IntentUtils;\nimport com.odoo.core.utils.OAlert;\nimport com.odoo.core.utils.OControls;\nimport com.odoo.core.utils.OCursorUtils;\nimport com.odoo.core.utils.ODateUtils;\nimport com.odoo.core.utils.OResource;\nimport com.odoo.core.utils.StringUtils;\nimport com.odoo.core.utils.sys.IOnActivityResultListener;\nimport com.odoo.core.utils.sys.IOnBackPressListener;\nimport com.odoo.R;\nimport com.odoo.widgets.bottomsheet.BottomSheet;\nimport com.odoo.widgets.bottomsheet.BottomSheetListeners;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class CRMLeads extends BaseFragment implements OCursorListAdapter.OnViewBindListener,\n        LoaderManager.LoaderCallbacks<Cursor>, SwipeRefreshLayout.OnRefreshListener,\n        ISyncStatusObserverListener, OCursorListAdapter.BeforeBindUpdateData,\n        IOnSearchViewChangeListener, View.OnClickListener, IOnItemClickListener,\n        BottomSheetListeners.OnSheetItemClickListener, BottomSheetListeners.OnSheetActionClickListener,\n        IOnBackPressListener, IOnActivityResultListener {\n    public static final String TAG = CRMLeads.class.getSimpleName();\n    public static final String KEY_MENU = \"key_menu_item\";\n    public static final int REQUEST_CONVERT_TO_OPPORTUNITY_WIZARD = 223;\n    public static final int REQUEST_CONVERT_TO_QUOTATION_WIZARD = 224;\n    public static final String KEY_IS_LEAD = \"key_is_lead\";\n    private View mView;\n    private int mLocal_id = 0;\n    private ListView mList;\n    private OCursorListAdapter mAdapter;\n    private BottomSheet mSheet = null;\n    private String mFilter = null;\n    private String wonLost = \"won\";\n    private boolean syncRequested = false;\n    // Customer's data filter\n    private boolean filter_customer_data = false;\n    private int customer_id = -1;\n    private ODataRow convertRequestRecord = null;\n    private Bundle syncBundle = new Bundle();\n\n\n    public enum Type {\n        Leads, Opportunities\n    }\n\n    @Override\n    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,\n                             @Nullable Bundle savedInstanceState) {\n        setHasOptionsMenu(true);\n        return inflater.inflate(R.layout.common_listview, container, false);\n    }\n\n    @Override\n    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {\n        super.onViewCreated(view, savedInstanceState);\n        mView = view;\n        parent().setOnBackPressListener(this);\n        parent().setOnActivityResultListener(this);\n        Bundle extra = getArguments();\n        if (extra != null && extra.containsKey(Customers.KEY_FILTER_REQUEST)) {\n            filter_customer_data = true;\n            customer_id = extra.getInt(Customers.KEY_CUSTOMER_ID);\n            mView.findViewById(R.id.customer_filterContainer).setVisibility(View.VISIBLE);\n            OControls.setText(mView, R.id.customer_name, extra.getString(\"name\"));\n            mView.findViewById(R.id.cancel_filter).setOnClickListener(this);\n        }\n        setHasSyncStatusObserver(TAG, this, db());\n        initAdapter();\n    }\n\n    private void initAdapter() {\n        mList = (ListView) mView.findViewById(R.id.listview);\n        mAdapter = new OCursorListAdapter(getActivity(), null, R.layout.crm_item);\n        mAdapter.setOnViewBindListener(this);\n        mList.setAdapter(mAdapter);\n        setHasFloatingButton(mView, R.id.fabButton, mList, this);\n        mAdapter.handleItemClickListener(mList, this);\n        getLoaderManager().initLoader(0, null, this);\n    }\n\n    @Override\n    public void onClick(View v) {\n\n        switch (v.getId()) {\n            case R.id.cancel_filter:\n                getActivity().getSupportFragmentManager().popBackStack();\n                break;\n            case R.id.fabButton:\n                Bundle type = new Bundle();\n                type.putString(\"type\", Type.Leads.toString());\n                IntentUtils.startActivity(getActivity(), CRMDetail.class, type);\n                break;\n        }\n    }\n\n    @Override\n    public ODataRow updateDataRow(Cursor cr) {\n        return db().browse(new String[]{\"stage_id\"},\n                cr.getInt(cr.getColumnIndex(OColumn.ROW_ID)));\n    }\n\n    @Override\n    public Loader<Cursor> onCreateLoader(int id, Bundle data) {\n        String where = \" type = ?\";\n        String[] whereArgs;\n        List<String> args = new ArrayList<>();\n        args.add(\"lead\");\n        if (mFilter != null) {\n            where += \" and (name like ? or description like ? or display_name like ? \" +\n                    \"or stage_name like ? or title_action like ?)\";\n            args.add(\"%\" + mFilter + \"%\");\n            args.add(\"%\" + mFilter + \"%\");\n            args.add(\"%\" + mFilter + \"%\");\n            args.add(\"%\" + mFilter + \"%\");\n            args.add(\"%\" + mFilter + \"%\");\n        }\n        if (filter_customer_data) {\n            where += \" and partner_id = ?\";\n            args.add(customer_id + \"\");\n        }\n        whereArgs = args.toArray(new String[args.size()]);\n\n        return new CursorLoader(getActivity(), db().uri(), null, where, whereArgs, \"create_date DESC\");\n    }\n\n    @Override\n    public void onLoadFinished(Loader<Cursor> loader, Cursor data) {\n        mAdapter.changeCursor(data);\n        if (data.getCount() > 0) {\n            new Handler().postDelayed(new Runnable() {\n                @Override\n                public void run() {\n                    OControls.setGone(mView, R.id.loadingProgress);\n                    OControls.setVisible(mView, R.id.swipe_container);\n                    OControls.setGone(mView, R.id.customer_no_items);\n                    setHasSwipeRefreshView(mView, R.id.swipe_container, CRMLeads.this);\n                }\n            }, 500);\n        } else {\n            if (db().isEmptyTable() && !syncRequested) {\n                syncRequested = true;\n                onRefresh();\n            }\n            new Handler().postDelayed(new Runnable() {\n                @Override\n                public void run() {\n                    OControls.setGone(mView, R.id.loadingProgress);\n                    OControls.setGone(mView, R.id.swipe_container);\n                    OControls.setVisible(mView, R.id.customer_no_items);\n                    setHasSwipeRefreshView(mView, R.id.customer_no_items, CRMLeads.this);\n                    OControls.setImage(mView, R.id.icon, R.drawable.ic_action_leads\n                    );\n                    OControls.setText(mView, R.id.title, \"No Leads Found\");\n                    OControls.setText(mView, R.id.subTitle, \"\");\n                }\n            }, 500);\n        }\n    }\n\n    @Override\n    public void onLoaderReset(Loader<Cursor> loader) {\n        mAdapter.changeCursor(null);\n    }\n\n    @Override\n    public void onViewBind(View view, Cursor cursor, ODataRow row) {\n        OControls.setText(view, R.id.name, row.getString(\"name\"));\n        OControls.setText(view, R.id.stage, row.getString(\"stage_name\"));\n        OControls.setText(view, R.id.display_name, row.getString(\"display_name\"));\n        OControls.setText(view, R.id.assignee_name, row.getString(\"assignee_name\"));\n        String date = ODateUtils.convertToDefault(row.getString(\"create_date\"),\n                ODateUtils.DEFAULT_FORMAT, \"MMMM, dd\");\n        OControls.setText(view, R.id.create_date, date);\n        syncBundle.putBoolean(KEY_IS_LEAD, true);\n        view.findViewById(R.id.opportunity_controls).setVisibility(View.GONE);\n    }\n\n    @Override\n    public List<ODrawerItem> drawerMenus(Context context) {\n        List<ODrawerItem> menu = new ArrayList<>();\n        menu.add(new ODrawerItem(TAG)\n                .setTitle(OResource.string(context, R.string.label_leads))\n                .setInstance(new CRMLeads())\n                .setIcon(R.drawable.ic_action_leads)\n                .setExtra(data(Type.Leads)));\n        menu.add(new ODrawerItem(TAG)\n                .setTitle(OResource.string(context, R.string.label_opportunities))\n                .setInstance(new CRMOpportunitiesPager())\n                .setIcon(R.drawable.ic_action_opportunities)\n                .setExtra(data(Type.Opportunities)));\n\n        return menu;\n    }\n\n    private Bundle data(Type type) {\n        Bundle extra = new Bundle();\n        extra.putString(KEY_MENU, type.toString());\n        return extra;\n    }\n\n    @Override\n    public Class<CRMLead> database() {\n        return CRMLead.class;\n    }\n\n    @Override\n    public void onRefresh() {\n        if (inNetwork()) {\n            parent().sync().requestSync(CRMLead.AUTHORITY, syncBundle);\n            setSwipeRefreshing(true);\n        } else {\n            hideRefreshingProgress();\n            Toast.makeText(getActivity(), _s(R.string.toast_network_required), Toast.LENGTH_LONG)\n                    .show();\n        }\n    }\n\n    @Override\n    public void onStatusChange(Boolean refreshing) {\n        getLoaderManager().restartLoader(0, null, this);\n    }\n\n    @Override\n    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {\n        super.onCreateOptionsMenu(menu, inflater);\n        menu.clear();\n        inflater.inflate(R.menu.menu_leads, menu);\n        setHasSearchView(this, menu, R.id.menu_lead_search);\n    }\n\n    @Override\n    public boolean onSearchViewTextChange(String newFilter) {\n        mFilter = newFilter;\n        getLoaderManager().restartLoader(0, null, this);\n        return true;\n    }\n\n    @Override\n    public void onSearchViewClose() {\n        // Nothing to do\n    }\n\n    @Override\n    public void onItemDoubleClick(View view, int position) {\n        ODataRow row = OCursorUtils.toDatarow((Cursor) mAdapter.getItem(position));\n        IntentUtils.startActivity(getActivity(), CRMDetail.class, row.getPrimaryBundleData());\n    }\n\n    @Override\n    public void onItemClick(View view, int position) {\n        showSheet((Cursor) mAdapter.getItem(position));\n    }\n\n    private void showSheet(Cursor data) {\n        BottomSheet.Builder builder = new BottomSheet.Builder(getActivity());\n        builder.listener(this);\n        builder.setIconColor(_c(R.color.body_text_2));\n        builder.setTextColor(_c(R.color.body_text_2));\n        builder.setData(data);\n        builder.actionListener(this);\n        builder.setActionIcon(R.drawable.ic_action_edit);\n        builder.title(data.getString(data.getColumnIndex(\"name\")));\n        builder.menu(R.menu.menu_lead_list_sheet);\n        mSheet = builder.create();\n        mSheet.show();\n    }\n\n\n    @Override\n    public void onSheetActionClick(BottomSheet sheet, Object extras) {\n        mSheet.dismiss();\n        ODataRow row = OCursorUtils.toDatarow((Cursor) extras);\n        IntentUtils.startActivity(getActivity(), CRMDetail.class, row.getPrimaryBundleData());\n    }\n\n    @Override\n    public void onItemClick(BottomSheet sheet, MenuItem menu, Object extras) {\n        ODataRow row = OCursorUtils.toDatarow((Cursor) extras);\n        mLocal_id = row.getInt(OColumn.ROW_ID);\n        mSheet.dismiss();\n        convertRequestRecord = row;\n        CRMLead crmLead = (CRMLead) db();\n        ResPartner partner = new ResPartner(getActivity(), null);\n        switch (menu.getItemId()) {\n            case R.id.menu_lead_convert_to_opportunity:\n                if (inNetwork()) {\n                    if (row.getInt(\"id\") == 0) {\n                        OAlert.showWarning(getActivity(), OResource.string(getActivity(), R.string.label_sync_warning));\n                    } else {\n                        int count = crmLead.count(\"id != ? and partner_id = ? and \" + OColumn.ROW_ID + \" != ?\"\n                                , new String[]{\n                                \"0\",\n                                row.getInt(\"partner_id\") + \"\",\n                                row.getString(OColumn.ROW_ID)\n                        });\n                        if (count > 0) {\n                            Intent intent = new Intent(getActivity(), ConvertToOpportunityWizard.class);\n                            intent.putExtras(row.getPrimaryBundleData());\n                            parent().startActivityForResult(intent, REQUEST_CONVERT_TO_OPPORTUNITY_WIZARD);\n                        } else {\n                            crmLead.convertToOpportunity(row, new ArrayList<Integer>(), convertDoneListener);\n                        }\n                    }\n                } else {\n                    Toast.makeText(getActivity(), R.string.toast_network_required, Toast.LENGTH_LONG).show();\n                }\n                break;\n            case R.id.menu_lead_call_customer:\n                String contact = (row.getString(\"phone\").equals(\"false\")) ?\n                        (row.getString(\"mobile\").equals(\"false\")) ? \"false\" : row.getString(\"mobile\") : row.getString(\"phone\");\n                if (contact.equals(\"false\")) {\n                    if (!row.getString(\"partner_id\").equals(\"false\")) {\n                        contact = partner.getContact(getActivity(), row.getInt(OColumn.ROW_ID));\n                        if (!contact.equals(\"false\")) {\n                            IntentUtils.requestCall(getActivity(), contact);\n                        } else {\n                            Toast.makeText(getActivity(), \"No contact found !\", Toast.LENGTH_LONG).show();\n                        }\n                    } else {\n                        Toast.makeText(getActivity(), \"No contact found !\", Toast.LENGTH_LONG).show();\n                    }\n                } else {\n                    IntentUtils.requestCall(getActivity(), contact);\n                }\n                break;\n            case R.id.menu_lead_customer_location:\n                if (!row.getString(\"partner_id\").equals(\"false\")) {\n                    String address = partner.getAddress(partner.browse(row.getInt(\"partner_id\")));\n                    if (!address.equals(\"false\") && !TextUtils.isEmpty(address)) {\n                        IntentUtils.redirectToMap(getActivity(), address);\n                    } else {\n                        Toast.makeText(getActivity(), \"No location found !\", Toast.LENGTH_LONG).show();\n                    }\n                } else {\n                    Toast.makeText(getActivity(), \"No partner found !\", Toast.LENGTH_LONG).show();\n                }\n                break;\n            case R.id.menu_lead_lost:\n                wonLost = \"lost\";\n                if (inNetwork()) {\n                    crmLead.markWonLost(wonLost, row, markDoneListener);\n                } else {\n                    Toast.makeText(getActivity(), R.string.toast_network_required, Toast.LENGTH_LONG).show();\n                }\n                break;\n        }\n    }\n\n    @Override\n    public void onOdooActivityResult(int requestCode, int resultCode, Intent data) {\n        if (requestCode == REQUEST_CONVERT_TO_OPPORTUNITY_WIZARD && resultCode == Activity.RESULT_OK) {\n            CRMLead crmLead = (CRMLead) db();\n            List<Integer> ids = data.getIntegerArrayListExtra(ConvertToOpportunityWizard.KEY_LEADS_IDS);\n            crmLead.convertToOpportunity(convertRequestRecord, ids, convertDoneListener);\n        }\n\n    }\n\n    CRMLead.OnOperationSuccessListener markDoneListener = new CRMLead.OnOperationSuccessListener() {\n        @Override\n        public void OnSuccess() {\n            Toast.makeText(getActivity(), StringUtils.capitalizeString(convertRequestRecord.getString(\"type\"))\n                    + \" marked \" + wonLost, Toast.LENGTH_LONG).show();\n        }\n\n        @Override\n        public void OnCancelled() {\n\n        }\n    };\n    CRMLead.OnOperationSuccessListener convertDoneListener = new CRMLead.OnOperationSuccessListener() {\n        @Override\n        public void OnSuccess() {\n            Toast.makeText(getActivity(), R.string.label_convert_to_opportunity, Toast.LENGTH_LONG).show();\n            Intent intent = new Intent(getActivity(), CRMDetail.class);\n            intent.putExtra(OColumn.ROW_ID, mLocal_id);\n            startActivity(intent);\n        }\n\n        @Override\n        public void OnCancelled() {\n\n        }\n    };\n\n    @Override\n    public boolean onBackPressed() {\n        if (mSheet != null && mSheet.isShowing()) {\n            mSheet.dismiss();\n            return false;\n        }\n        return true;\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/addons/crm/CRMOpportunities.java",
    "content": "package com.odoo.addons.crm;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.database.Cursor;\nimport android.os.Bundle;\nimport android.os.Handler;\nimport android.support.annotation.Nullable;\nimport android.support.v4.app.LoaderManager;\nimport android.support.v4.content.CursorLoader;\nimport android.support.v4.content.Loader;\nimport android.support.v4.widget.SwipeRefreshLayout;\nimport android.text.TextUtils;\nimport android.view.LayoutInflater;\nimport android.view.Menu;\nimport android.view.MenuInflater;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.ListView;\nimport android.widget.Toast;\n\nimport com.odoo.addons.calendar.EventDetail;\nimport com.odoo.addons.crm.models.CRMCaseStage;\nimport com.odoo.addons.crm.models.CRMLead;\nimport com.odoo.addons.customers.Customers;\nimport com.odoo.addons.phonecall.PhoneCallDetail;\nimport com.odoo.addons.sale.models.SaleOrder;\nimport com.odoo.base.addons.res.ResPartner;\nimport com.odoo.core.orm.ODataRow;\nimport com.odoo.core.orm.OValues;\nimport com.odoo.core.orm.fields.OColumn;\nimport com.odoo.core.support.addons.fragment.BaseFragment;\nimport com.odoo.core.support.addons.fragment.IOnSearchViewChangeListener;\nimport com.odoo.core.support.addons.fragment.ISyncStatusObserverListener;\nimport com.odoo.core.support.drawer.ODrawerItem;\nimport com.odoo.core.support.list.IOnItemClickListener;\nimport com.odoo.core.support.list.OCursorListAdapter;\nimport com.odoo.core.utils.IntentUtils;\nimport com.odoo.core.utils.OControls;\nimport com.odoo.core.utils.OCursorUtils;\nimport com.odoo.core.utils.ODateUtils;\nimport com.odoo.core.utils.OResource;\nimport com.odoo.core.utils.StringUtils;\nimport com.odoo.core.utils.dialog.OChoiceDialog;\nimport com.odoo.core.utils.sys.IOnActivityResultListener;\nimport com.odoo.core.utils.sys.IOnBackPressListener;\nimport com.odoo.R;\nimport com.odoo.widgets.bottomsheet.BottomSheet;\nimport com.odoo.widgets.bottomsheet.BottomSheetListeners;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class CRMOpportunities extends BaseFragment implements OCursorListAdapter.OnViewBindListener,\n        LoaderManager.LoaderCallbacks<Cursor>, SwipeRefreshLayout.OnRefreshListener,\n        ISyncStatusObserverListener, OCursorListAdapter.BeforeBindUpdateData,\n        IOnSearchViewChangeListener, View.OnClickListener, IOnItemClickListener,\n        BottomSheetListeners.OnSheetItemClickListener,\n        BottomSheetListeners.OnSheetActionClickListener,\n        IOnBackPressListener, IOnActivityResultListener {\n    public static final String TAG = CRMOpportunities.class.getSimpleName();\n    public static final String KEY_MENU = \"key_menu_item\";\n    public static final int REQUEST_CONVERT_TO_OPPORTUNITY_WIZARD = 223;\n    public static final int REQUEST_CONVERT_TO_QUOTATION_WIZARD = 224;\n    public static final String KEY_IS_LEAD = \"key_is_lead\";\n    //    private Type mType = Type.Opportunities;\n    private View mView;\n    private ListView mList;\n    private OCursorListAdapter mAdapter;\n    private BottomSheet mSheet = null;\n    private String mFilter = null;\n    private String wonLost = \"won\";\n    private int stage_id = -1;\n    private boolean syncRequested = false;\n    // Customer's data filter\n    private boolean filter_customer_data = false;\n    private int customer_id = -1;\n    private ODataRow convertRequestRecord = null;\n    private Bundle syncBundle = new Bundle();\n\n    @Override\n    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,\n                             @Nullable Bundle savedInstanceState) {\n        setHasOptionsMenu(true);\n        return inflater.inflate(R.layout.common_listview, container, false);\n    }\n\n    @Override\n    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {\n        super.onViewCreated(view, savedInstanceState);\n        mView = view;\n        parent().setHasActionBarSpinner(true);\n        parent().setOnActivityResultListener(this);\n        Bundle extra = getArguments();\n        if (extra != null) {\n            if (extra.containsKey(CRMOpportunitiesPager.KEY_STAGE_ID)) {\n                stage_id = extra.getInt(CRMOpportunitiesPager.KEY_STAGE_ID);\n            }\n            if (extra.containsKey(Customers.KEY_FILTER_REQUEST)) {\n                filter_customer_data = true;\n                customer_id = extra.getInt(Customers.KEY_CUSTOMER_ID);\n                mView.findViewById(R.id.customer_filterContainer).setVisibility(View.VISIBLE);\n                OControls.setText(mView, R.id.customer_name, extra.getString(\"name\"));\n                mView.findViewById(R.id.cancel_filter).setOnClickListener(this);\n            }\n        }\n        setHasSyncStatusObserver(TAG, this, db());\n        initAdapter();\n    }\n\n    private void initAdapter() {\n        if (getActivity() != null) {\n            mList = (ListView) mView.findViewById(R.id.listview);\n            mAdapter = new OCursorListAdapter(getActivity(), null, R.layout.crm_item);\n            mAdapter.setOnViewBindListener(this);\n            mList.setAdapter(mAdapter);\n            setHasFloatingButton(mView, R.id.fabButton, mList, this);\n            mAdapter.handleItemClickListener(mList, this);\n            getLoaderManager().initLoader(0, null, this);\n        }\n    }\n\n    @Override\n    public void onClick(View v) {\n\n        switch (v.getId()) {\n            case R.id.cancel_filter:\n                getActivity().getSupportFragmentManager().popBackStack();\n                break;\n            case R.id.fabButton:\n                Bundle types = new Bundle();\n                types.putString(\"type\", CRMLeads.Type.Opportunities.toString());\n                types.putInt(\"stage_id\", stage_id);\n                IntentUtils.startActivity(getActivity(), CRMDetail.class, types);\n                break;\n            case R.id.stage_move:\n                final ODataRow row = (ODataRow) v.getTag();\n                final List<String> stageNames = new ArrayList<>();\n                CRMCaseStage crmStage = new CRMCaseStage(getActivity(), null);\n                final List<ODataRow> stages = crmStage.select(null, \"type != ?\",\n                        new String[]{\"lead\"}, \"sequence\");\n                int defaultSelected = -1;\n                for (ODataRow stage : stages) {\n                    stageNames.add(stage.getString(\"name\"));\n                    if (stage_id == stage.getInt(OColumn.ROW_ID)) {\n                        defaultSelected = stageNames.indexOf(stage.getString(\"name\"));\n                    }\n                }\n                OChoiceDialog.get(getActivity()).withTitle(\"Move to\").withOptions(stageNames, defaultSelected)\n                        .show(new OChoiceDialog.OnChoiceSelectListener() {\n                            @Override\n                            public void choiceSelected(int position, String value) {\n                                OValues stageValue = new OValues();\n                                stageValue.put(\"stage_name\", stages.get(position).\n                                        getString(\"name\"));\n                                stageValue.put(\"stage_id\", stages.get(position)\n                                        .getInt(OColumn.ROW_ID));\n                                stageValue.put(\"probability\", stages.get(position).getFloat(\"probability\"));\n                                new CRMLead(getActivity(), null).update(OColumn.ROW_ID + \"=?\",\n                                        new String[]{row.getString(OColumn.ROW_ID)}, stageValue);\n                                Toast.makeText(getActivity(), row.getString(\"name\") +\n                                        \" moved to stage \" + stages.get(position).\n                                        getString(\"name\"), Toast.LENGTH_SHORT).show();\n                            }\n                        });\n                break;\n        }\n    }\n\n    @Override\n    public ODataRow updateDataRow(Cursor cr) {\n        return db().browse(new String[]{\"stage_id\"},\n                cr.getInt(cr.getColumnIndex(OColumn.ROW_ID)));\n    }\n\n    @Override\n    public Loader<Cursor> onCreateLoader(int id, Bundle data) {\n        String where = \" type = ? and stage_id = ?\";\n        String[] whereArgs;\n        List<String> args = new ArrayList<>();\n        args.add(\"opportunity\");\n        args.add(stage_id + \"\");\n        if (mFilter != null) {\n            where += \" and (name like ? or description like ? or display_name like ? \" +\n                    \"or stage_name like ? or title_action like ?)\";\n            args.add(\"%\" + mFilter + \"%\");\n            args.add(\"%\" + mFilter + \"%\");\n            args.add(\"%\" + mFilter + \"%\");\n            args.add(\"%\" + mFilter + \"%\");\n            args.add(\"%\" + mFilter + \"%\");\n        }\n        if (filter_customer_data) {\n            where += \" and partner_id = ?\";\n            args.add(customer_id + \"\");\n        }\n        whereArgs = args.toArray(new String[args.size()]);\n\n        return new CursorLoader(getActivity(), db().uri(), null, where, whereArgs, \"date_action DESC\");\n    }\n\n    @Override\n    public void onLoadFinished(Loader<Cursor> loader, Cursor data) {\n        mAdapter.changeCursor(data);\n        if (data.getCount() > 0) {\n            new Handler().postDelayed(new Runnable() {\n                @Override\n                public void run() {\n                    OControls.setGone(mView, R.id.loadingProgress);\n                    OControls.setVisible(mView, R.id.swipe_container);\n                    OControls.setGone(mView, R.id.customer_no_items);\n                    setHasSwipeRefreshView(mView, R.id.swipe_container, CRMOpportunities.this);\n                }\n            }, 500);\n        } else {\n            if (db().isEmptyTable() && !syncRequested) {\n                syncRequested = true;\n                onRefresh();\n            }\n            new Handler().postDelayed(new Runnable() {\n                @Override\n                public void run() {\n                    OControls.setGone(mView, R.id.loadingProgress);\n                    OControls.setGone(mView, R.id.swipe_container);\n                    OControls.setVisible(mView, R.id.customer_no_items);\n                    setHasSwipeRefreshView(mView, R.id.customer_no_items, CRMOpportunities.this);\n                    OControls.setImage(mView, R.id.icon, R.drawable.ic_action_opportunities);\n                    if (getActivity() != null)\n                        OControls.setText(mView, R.id.title, OResource.string(getActivity(), R.string.label_no_opportunity_found));\n                    OControls.setText(mView, R.id.subTitle, \"\");\n                }\n            }, 500);\n        }\n    }\n\n    @Override\n    public void onLoaderReset(Loader<Cursor> loader) {\n        mAdapter.changeCursor(null);\n    }\n\n    @Override\n    public void onViewBind(View view, Cursor cursor, ODataRow row) {\n        OControls.setText(view, R.id.name, row.getString(\"name\"));\n        OControls.setGone(view, R.id.stage);\n        OControls.setVisible(view, R.id.stage_move);\n        //OControls.setText(view, R.id.stage, row.getString(\"stage_name\"));\n        OControls.setText(view, R.id.display_name, row.getString(\"display_name\"));\n        OControls.setText(view, R.id.assignee_name, row.getString(\"assignee_name\"));\n        String date = ODateUtils.convertToDefault(row.getString(\"create_date\"),\n                ODateUtils.DEFAULT_FORMAT, \"MMMM, dd\");\n        OControls.setText(view, R.id.create_date, date);\n        // Controls for opportunity\n        syncBundle.putBoolean(KEY_IS_LEAD, false);\n        view.findViewById(R.id.opportunity_controls).setVisibility(View.VISIBLE);\n        if (!row.getString(\"date_action\").equals(\"false\")) {\n            OControls.setVisible(view, R.id.date_action);\n            String date_action = ODateUtils.convertToDefault(row.getString(\"date_action\")\n                    , ODateUtils.DEFAULT_DATE_FORMAT, \"MMMM, dd\");\n            OControls.setText(view, R.id.date_action, date_action + \" : \");\n        } else {\n            OControls.setGone(view, R.id.date_action);\n        }\n        if (!row.getString(\"title_action\").equals(\"false\")) {\n            OControls.setVisible(view, R.id.title_action);\n            OControls.setText(view, R.id.title_action, row.getString(\"title_action\"));\n        } else {\n            OControls.setGone(view, R.id.title_action);\n        }\n//        TextView tv = (TextView) view.findViewById(R.id.stage);\n//        tv.setOnClickListener(this);\n//        tv.setTag(row);\n        view.findViewById(R.id.stage_move).setTag(row);\n        view.findViewById(R.id.stage_move).setOnClickListener(this);\n    }\n\n\n    @Override\n    public List<ODrawerItem> drawerMenus(Context context) {\n        return new ArrayList<>();\n    }\n\n    @Override\n    public Class<CRMLead> database() {\n        return CRMLead.class;\n    }\n\n    @Override\n    public void onRefresh() {\n        if (inNetwork()) {\n            parent().sync().requestSync(CRMLead.AUTHORITY, syncBundle);\n            setSwipeRefreshing(true);\n        } else {\n            hideRefreshingProgress();\n            Toast.makeText(getActivity(), _s(R.string.toast_network_required), Toast.LENGTH_LONG)\n                    .show();\n        }\n    }\n\n    @Override\n    public void onStatusChange(Boolean refreshing) {\n        getLoaderManager().restartLoader(0, null, this);\n    }\n\n    @Override\n    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {\n        super.onCreateOptionsMenu(menu, inflater);\n        menu.clear();\n        inflater.inflate(R.menu.menu_leads, menu);\n        setHasSearchView(this, menu, R.id.menu_lead_search);\n    }\n\n    @Override\n    public boolean onSearchViewTextChange(String newFilter) {\n        mFilter = newFilter;\n        getLoaderManager().restartLoader(0, null, this);\n        return true;\n    }\n\n    @Override\n    public void onSearchViewClose() {\n        // Nothing to do\n    }\n\n    @Override\n    public void onItemDoubleClick(View view, int position) {\n        ODataRow row = OCursorUtils.toDatarow((Cursor) mAdapter.getItem(position));\n        IntentUtils.startActivity(getActivity(), CRMDetail.class, row.getPrimaryBundleData());\n    }\n\n\n    @Override\n    public void onItemClick(View view, int position) {\n        showSheet((Cursor) mAdapter.getItem(position));\n    }\n\n    private void showSheet(Cursor data) {\n        BottomSheet.Builder builder = new BottomSheet.Builder(getActivity());\n        builder.listener(this);\n        builder.setIconColor(_c(R.color.body_text_2));\n        builder.setTextColor(_c(R.color.body_text_2));\n        builder.setData(data);\n        builder.actionListener(this);\n        builder.setActionIcon(R.drawable.ic_action_edit);\n        builder.title(data.getString(data.getColumnIndex(\"name\")));\n        builder.menu(R.menu.menu_opp_list_sheet);\n        mSheet = builder.create();\n        mSheet.show();\n    }\n\n    @Override\n    public void onSheetActionClick(BottomSheet sheet, Object extras) {\n        mSheet.dismiss();\n        ODataRow row = OCursorUtils.toDatarow((Cursor) extras);\n        IntentUtils.startActivity(getActivity(), CRMDetail.class, row.getPrimaryBundleData());\n    }\n\n    @Override\n    public void onItemClick(BottomSheet sheet, MenuItem menu, Object extras) {\n        final ODataRow row = OCursorUtils.toDatarow((Cursor) extras);\n        mSheet.dismiss();\n        CRMLead crmLead = (CRMLead) db();\n        ResPartner partner = new ResPartner(getActivity(), null);\n        switch (menu.getItemId()) {\n            case R.id.menu_lead_convert_to_quotation:\n                if (inNetwork()) {\n                    Intent intent = new Intent(getActivity(), ConvertToQuotation.class);\n                    intent.putExtras(row.getPrimaryBundleData());\n                    parent().startActivityForResult(intent, REQUEST_CONVERT_TO_QUOTATION_WIZARD);\n                } else {\n                    Toast.makeText(getActivity(), R.string.toast_network_required,\n                            Toast.LENGTH_LONG).show();\n                }\n                break;\n            case R.id.menu_lead_call_customer:\n                String contact = (row.getString(\"phone\").equals(\"false\")) ?\n                        (row.getString(\"mobile\").equals(\"false\")) ? \"false\" : row.getString(\"mobile\") : row.getString(\"phone\");\n                if (contact.equals(\"false\")) {\n                    if (!row.getString(\"partner_id\").equals(\"false\")) {\n                        contact = partner.getContact(getActivity(), row.getInt(OColumn.ROW_ID));\n                        if (!contact.equals(\"false\")) {\n                            IntentUtils.requestCall(getActivity(), contact);\n                        } else {\n                            Toast.makeText(getActivity(), \"No contact found !\", Toast.LENGTH_LONG).show();\n                        }\n                    } else {\n                        Toast.makeText(getActivity(), \"No contact found !\", Toast.LENGTH_LONG).\n                                show();\n                    }\n                } else {\n                    IntentUtils.requestCall(getActivity(), contact);\n                }\n                break;\n            case R.id.menu_lead_customer_location:\n                if (!row.getString(\"partner_id\").equals(\"false\")) {\n                    String address = partner.getAddress(partner.browse(row.getInt(\"partner_id\")));\n                    if (!address.equals(\"false\") && !TextUtils.isEmpty(address)) {\n                        IntentUtils.redirectToMap(getActivity(), address);\n                    } else {\n                        Toast.makeText(getActivity(), _s(R.string.label_no_location_found), Toast.LENGTH_LONG).\n                                show();\n                    }\n                } else {\n                    Toast.makeText(getActivity(), _s(R.string.label_no_contact_found), Toast.LENGTH_LONG).show();\n                }\n                break;\n            case R.id.menu_lead_reschedule:\n                List<String> choices = new ArrayList<>();\n                choices.add(OResource.string(getActivity(), R.string.label_opt_schedule_log_call));\n                choices.add(OResource.string(getActivity(), R.string.label_opt_schedule_meeting));\n                OChoiceDialog.get(getActivity()).withOptions(choices, -1)\n                        .show(new OChoiceDialog.OnChoiceSelectListener() {\n                            @Override\n                            public void choiceSelected(int position, String value) {\n                                int opp_id = row.getInt(OColumn.ROW_ID);\n                                switch (position) {\n                                    case 0:\n                                        Bundle extra = new Bundle();\n                                        extra.putInt(\"opp_id\", opp_id);\n                                        IntentUtils.startActivity(getActivity(),\n                                                PhoneCallDetail.class, extra);\n                                        break;\n                                    case 1: // Schedule meeting\n                                        Bundle data = new Bundle();\n//                                        data.putString(KEY_DATE, mFilterDate);\n                                        data.putInt(\"opp_id\", opp_id);\n                                        IntentUtils.startActivity(getActivity(),\n                                                EventDetail.class, data);\n                                        break;\n                                }\n                            }\n                        });\n                break;\n            case R.id.menu_lead_won:\n                wonLost = \"won\";\n                if (inNetwork()) {\n                    crmLead.markWonLost(wonLost, row, markDoneListener);\n                } else {\n                    Toast.makeText(getActivity(), R.string.toast_network_required, Toast.LENGTH_LONG).show();\n                }\n                break;\n            case R.id.menu_lead_lost:\n                wonLost = \"lost\";\n                if (inNetwork()) {\n                    crmLead.markWonLost(wonLost, row, markDoneListener);\n                } else {\n                    Toast.makeText(getActivity(), R.string.toast_network_required, Toast.LENGTH_LONG).show();\n                }\n                break;\n        }\n    }\n\n    @Override\n    public void onOdooActivityResult(int requestCode, int resultCode, Intent data) {\n        if (requestCode == REQUEST_CONVERT_TO_QUOTATION_WIZARD && resultCode ==\n                Activity.RESULT_OK) {\n            CRMLead crmLead = (CRMLead) db();\n            convertRequestRecord = crmLead.browse(data.getIntExtra(OColumn.ROW_ID, 0));\n            crmLead.createQuotation(convertRequestRecord, data.getStringExtra(\"partner_id\"),\n                    data.getBooleanExtra(\"mark_won\", false), createQuotationListener);\n        }\n    }\n\n    CRMLead.OnOperationSuccessListener createQuotationListener = new CRMLead.\n            OnOperationSuccessListener() {\n        @Override\n        public void OnSuccess() {\n            Toast.makeText(getActivity(), OResource.string(getActivity(),\n                    R.string.label_quotation_created) + \" \" +\n                    convertRequestRecord.getString(\"name\"), Toast.LENGTH_LONG).show();\n            parent().sync().requestSync(SaleOrder.AUTHORITY);\n        }\n\n        @Override\n        public void OnCancelled() {\n\n        }\n    };\n    CRMLead.OnOperationSuccessListener markDoneListener = new CRMLead.OnOperationSuccessListener() {\n        @Override\n        public void OnSuccess() {\n            Toast.makeText(getActivity(), StringUtils.capitalizeString(convertRequestRecord.getString(\"type\"))\n                    + \" marked \" + wonLost, Toast.LENGTH_LONG).show();\n        }\n\n        @Override\n        public void OnCancelled() {\n\n        }\n    };\n\n    @Override\n    public boolean onBackPressed() {\n        if (mSheet != null && mSheet.isShowing()) {\n            mSheet.dismiss();\n            return false;\n        }\n        return true;\n    }\n\n    @Override\n    protected void onNavSpinnerDestroy() {\n\n    }\n\n    @Override\n    public void onDestroy() {\n        super.onDestroy();\n        getLoaderManager().destroyLoader(0);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/addons/crm/CRMOpportunitiesPager.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 13/2/15 11:56 AM\n */\npackage com.odoo.addons.crm;\n\nimport android.annotation.SuppressLint;\nimport android.content.Context;\nimport android.database.ContentObserver;\nimport android.database.Cursor;\nimport android.graphics.Color;\nimport android.net.Uri;\nimport android.os.Bundle;\nimport android.os.Handler;\nimport android.os.Parcelable;\nimport android.support.v4.app.Fragment;\nimport android.support.v4.app.FragmentManager;\nimport android.support.v4.app.FragmentStatePagerAdapter;\nimport android.support.v4.view.PagerTabStrip;\nimport android.support.v4.view.ViewPager;\nimport android.support.v4.widget.SwipeRefreshLayout;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.AdapterView;\nimport android.widget.Spinner;\nimport android.widget.TextView;\nimport android.widget.Toast;\n\nimport com.odoo.R;\nimport com.odoo.addons.crm.models.CRMCaseStage;\nimport com.odoo.addons.crm.models.CRMLead;\nimport com.odoo.addons.customers.Customers;\nimport com.odoo.core.orm.ODataRow;\nimport com.odoo.core.orm.fields.OColumn;\nimport com.odoo.core.support.addons.fragment.BaseFragment;\nimport com.odoo.core.support.drawer.ODrawerItem;\nimport com.odoo.core.support.list.OListAdapter;\nimport com.odoo.core.utils.OControls;\nimport com.odoo.core.utils.OResource;\nimport com.odoo.core.utils.sys.IOnBackPressListener;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\n\nimport odoo.controls.OControlHelper;\n\npublic class CRMOpportunitiesPager extends BaseFragment implements ViewPager.OnPageChangeListener, AdapterView.OnItemSelectedListener, IOnBackPressListener, SwipeRefreshLayout.OnRefreshListener {\n    public static final String TAG = CRMOpportunitiesPager.class.getSimpleName();\n    public static final String KEY_MENU = \"key_menu_item\";\n    private CRMLeads.Type mType = CRMLeads.Type.Opportunities;\n    private Context mContext;\n    private Handler handler;\n    private DataObserver observer;\n    private Cursor cursor = null;\n    private String[] projection = new String[]{\"name\"};\n    private CRMCaseStage crmStage;\n    public static final String KEY_STAGE_ID = \"stage_id\";\n    public static final String KEY_FILTER = \"key_filter\";\n    private ViewPager mPager;\n    private PagerTabStrip mTabStrip;\n    private HashMap<String, Fragment> mFragments = new HashMap<>();\n    private StagePagerAdapter mAdapter;\n    private Boolean filterCustomerOpp = false;\n    private int customer_id = -1;\n    private Spinner mNavSpinner = null;\n    private OListAdapter mNavSpinnerAdapter = null;\n    private List<Object> spinnerItems = new ArrayList<>();\n    private int selectedPagerPosition = 0;\n    private View mView;\n\n    @Override\n    public View onCreateView(LayoutInflater inflater, ViewGroup container,\n                             Bundle savedInstanceState) {\n        return inflater.inflate(R.layout.crm_opportunity_pagger, container, false);\n    }\n\n    @Override\n    public void onViewCreated(View view, Bundle savedInstanceState) {\n        super.onViewCreated(view, savedInstanceState);\n        mView = view;\n        mContext = getActivity();\n        parent().setOnBackPressListener(this);\n        Bundle extra = getArguments();\n        if (extra.containsKey(Customers.KEY_FILTER_REQUEST)) {\n            filterCustomerOpp = true;\n            customer_id = extra.getInt(Customers.KEY_CUSTOMER_ID);\n        }\n\n        crmStage = new CRMCaseStage(getActivity(), null);\n        handler = new Handler();\n        observer = new DataObserver(handler);\n        parent().setHasActionBarSpinner(true);\n        mNavSpinner = parent().getActionBarSpinner();\n        initPager(view);\n        initSpinner();\n    }\n\n    private void initSpinner() {\n        if (getActivity() == null) {\n            return;\n        }\n        spinnerItems.clear();\n        spinnerItems.addAll(crmStage.select(null, \"type!=?\", new String[]{\"lead\"}, \"sequence\"));\n        if (spinnerItems.isEmpty()) {\n            parent().setHasActionBarSpinner(false);\n            mPager.setVisibility(View.GONE);\n            setHasSwipeRefreshView(mView, R.id.no_items_found, this);\n            OControls.setVisible(mView, R.id.no_items_found);\n            OControls.setVisible(mView, R.id.dashboard_no_item_view);\n            OControls.setText(mView, R.id.title, OResource.string(getActivity(),\n                    R.string.label_no_opportunity_found));\n            OControls.setText(mView, R.id.subTitle, \"\");\n            OControls.setImage(mView, R.id.icon, R.drawable.ic_action_opportunities);\n            return;\n        } else {\n            mPager.setVisibility(View.VISIBLE);\n            OControls.setGone(mView, R.id.no_items_found);\n            OControls.setGone(mView, R.id.dashboard_no_item_view);\n        }\n        mNavSpinnerAdapter = new OListAdapter(getActivity(), R.layout.base_simple_list_item_1, spinnerItems) {\n            @Override\n            public View getView(int position, View convertView, ViewGroup parent) {\n                if (convertView == null) {\n                    convertView = LayoutInflater.from(getActivity()).inflate(R.layout.base_simple_list_item_1_selected\n                            , parent, false);\n                }\n                return getSpinnerView(getItem(position), position, convertView, parent);\n            }\n\n            @Override\n            public View getDropDownView(int position, View convertView, ViewGroup parent) {\n                if (convertView == null) {\n                    convertView = LayoutInflater.from(getActivity()).inflate(getResource(), parent, false);\n                }\n                return getSpinnerView(getItem(position), position, convertView, parent);\n            }\n        };\n        mNavSpinner.setAdapter(mNavSpinnerAdapter);\n        mNavSpinner.setOnItemSelectedListener(this);\n    }\n\n    private View getSpinnerView(Object row, int pos, View view, ViewGroup parent) {\n        ODataRow r = (ODataRow) row;\n        OControls.setText(view, android.R.id.text1, r.getString(\"name\"));\n        return view;\n    }\n\n    private void initPager(View view) {\n        getActivity().getContentResolver().registerContentObserver(\n                crmStage.uri(), true, observer);\n        initCR();\n        mPager = (ViewPager) view.findViewById(R.id.pager);\n        mPager.setOnPageChangeListener(this);\n        mTabStrip = (PagerTabStrip) view.findViewById(R.id.pager_title_strip);\n        mTabStrip.setTabIndicatorColor(Color.WHITE);\n        mPager.setOffscreenPageLimit(2);\n        mAdapter = new StagePagerAdapter(cursor, getChildFragmentManager());\n        mPager.setAdapter(mAdapter);\n        for (int i = 0; i < mTabStrip.getChildCount(); ++i) {\n            View nextChild = mTabStrip.getChildAt(i);\n            if (nextChild instanceof TextView) {\n                TextView textViewToConvert = (TextView) nextChild;\n                textViewToConvert.setAllCaps(true);\n                textViewToConvert.setTextColor(Color.WHITE);\n                textViewToConvert.setTypeface(OControlHelper.boldFont());\n            }\n        }\n    }\n\n    private void initCR() {\n        cursor = mContext.getContentResolver().query(crmStage.uri(),\n                projection, \"type != ?\", new String[]{\"lead\"}, \"sequence\");\n    }\n\n    @Override\n    public void onPageScrolled(int i, float v, int i2) {\n\n    }\n\n    @Override\n    public void onPageSelected(int position) {\n        mNavSpinner.setSelection(position);\n        selectedPagerPosition = position;\n    }\n\n    @Override\n    public void onPageScrollStateChanged(int i) {\n\n    }\n\n    @Override\n    public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {\n        mPager.setCurrentItem(position, true);\n    }\n\n    @Override\n    public void onNothingSelected(AdapterView<?> parent) {\n\n    }\n\n    @Override\n    public boolean onBackPressed() {\n        if (mFragments.size() > 0) {\n            return ((IOnBackPressListener) mFragments.get(\"index_\" + mNavSpinner.getSelectedItemPosition())\n            ).onBackPressed();\n        }\n        return true;\n    }\n\n    @Override\n    public void onRefresh() {\n        if (inNetwork()) {\n            Bundle syncBundle = new Bundle();\n            syncBundle.putBoolean(CRMOpportunities.KEY_IS_LEAD, false);\n            parent().sync().requestSync(CRMLead.AUTHORITY, syncBundle);\n            setSwipeRefreshing(true);\n        } else {\n            hideRefreshingProgress();\n            Toast.makeText(getActivity(), _s(R.string.toast_network_required), Toast.LENGTH_LONG)\n                    .show();\n        }\n    }\n\n    private class StagePagerAdapter extends FragmentStatePagerAdapter {\n\n        private String key_filter;\n\n        public StagePagerAdapter(Cursor cursor, FragmentManager fm) {\n            super(fm);\n            key_filter = \"opportunity\";\n        }\n\n        @Override\n        public CharSequence getPageTitle(int position) {\n            cursor.moveToPosition(position);\n            String name = cursor.getString(cursor.getColumnIndex(\"name\"));\n            int row_id = cursor.getInt(cursor.getColumnIndex(OColumn.ROW_ID));\n            String where = \"stage_id = ? and type != ?\";\n            List<String> args = new ArrayList<>();\n            args.add(row_id + \"\");\n            args.add(\"lead\");\n            if (filterCustomerOpp) {\n                where += \" and partner_id = ?\";\n                args.add(customer_id + \"\");\n            }\n            int count = db().count(where, args.toArray(new String[args.size()]));\n            if (count > 0)\n                name += \" (\" + count + \")\";\n            return name;\n        }\n\n        @Override\n        public Fragment getItem(int index) {\n            CRMOpportunities crm = new CRMOpportunities();\n            cursor.moveToPosition(index);\n            int stage_id = cursor.getInt(cursor.getColumnIndex(OColumn.ROW_ID));\n            Bundle bundle = new Bundle();\n            bundle.putInt(KEY_STAGE_ID, stage_id);\n            bundle.putString(KEY_FILTER, key_filter);\n            bundle.putInt(\"index\", index);\n            if (filterCustomerOpp) {\n                bundle.putBoolean(Customers.KEY_FILTER_REQUEST, true);\n                bundle.putInt(Customers.KEY_CUSTOMER_ID, customer_id);\n                bundle.putString(\"name\", getArguments().getString(\"name\"));\n            }\n            crm.setArguments(bundle);\n            mFragments.put(\"index_\" + index, crm);\n            return crm;\n        }\n\n        @Override\n        public void restoreState(Parcelable state, ClassLoader loader) {\n            super.restoreState(null, loader);\n        }\n\n        @Override\n        public int getCount() {\n            return cursor.getCount();\n        }\n\n    }\n\n    @Override\n    public List<ODrawerItem> drawerMenus(Context context) {\n        return new ArrayList<>();\n    }\n\n    @Override\n    public Class<CRMLead> database() {\n        return CRMLead.class;\n    }\n\n    private class DataObserver extends ContentObserver {\n\n        public DataObserver(Handler handler) {\n            super(handler);\n        }\n\n        @SuppressLint(\"NewApi\")\n        @Override\n        public void onChange(boolean selfChange) {\n            super.onChange(selfChange);\n        }\n\n        @SuppressLint(\"NewApi\")\n        @Override\n        public void onChange(boolean selfChange, Uri uri) {\n            super.onChange(selfChange, uri);\n            updatePager();\n        }\n    }\n\n    public void updatePager() {\n        initCR();\n        initSpinner();\n        mAdapter.notifyDataSetChanged();\n        mPager.setCurrentItem(selectedPagerPosition);\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/addons/crm/ConvertToOpportunityWizard.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 27/1/15 3:07 PM\n */\npackage com.odoo.addons.crm;\n\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.support.v7.app.ActionBarActivity;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\n\nimport com.odoo.addons.crm.models.CRMLead;\nimport com.odoo.core.orm.ODataRow;\nimport com.odoo.core.orm.fields.OColumn;\nimport com.odoo.core.support.list.OListAdapter;\nimport com.odoo.core.utils.OControls;\nimport com.odoo.core.utils.ODateUtils;\nimport com.odoo.core.utils.StringUtils;\nimport com.odoo.core.utils.controls.ExpandableHeightGridView;\nimport com.odoo.R;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport odoo.controls.OField;\nimport odoo.controls.OForm;\n\npublic class ConvertToOpportunityWizard extends ActionBarActivity implements View.OnClickListener, OField.IOnFieldValueChangeListener {\n    public static final String TAG = ConvertToOpportunityWizard.class.getSimpleName();\n    public static final String KEY_LEADS_IDS = \"key_leads_ids\";\n    private Bundle extra;\n    private OForm convert_form;\n    private CRMLead crmLead = null;\n    private OListAdapter mAdapter;\n    private List<Object> items = new ArrayList<>();\n    private ExpandableHeightGridView mOpportunityList;\n    private OField conversation_action;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.crm_convert_to_opportunity);\n        getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);\n        getSupportActionBar().hide();\n        setResult(RESULT_CANCELED);\n        extra = getIntent().getExtras();\n        convert_form = (OForm) findViewById(R.id.convert_form);\n        convert_form.setEditable(true);\n        convert_form.initForm(null);\n        findViewById(R.id.create_opportunity).setOnClickListener(this);\n        findViewById(R.id.cancel).setOnClickListener(this);\n\n        conversation_action = (OField) findViewById(R.id.conversation_action);\n        conversation_action.setOnValueChangeListener(this);\n        init();\n    }\n\n    private void init() {\n        items.clear();\n        mOpportunityList = (ExpandableHeightGridView) findViewById(R.id.opportunities);\n        mOpportunityList.setExpanded(true);\n        crmLead = new CRMLead(this, null);\n        ODataRow lead = crmLead.browse(extra.getInt(OColumn.ROW_ID));\n        items.addAll(crmLead.select(null,\n                \"partner_id = ? and id != ? and \" + OColumn.ROW_ID + \" != ?\",\n                new String[]{\n                        lead.getString(\"partner_id\"),\n                        \"0\",\n                        lead.getString(OColumn.ROW_ID)\n                }));\n        mAdapter = new OListAdapter(this, R.layout.crm_convert_to_opportunity_item, items) {\n            @Override\n            public View getView(int position, View convertView, ViewGroup parent) {\n                if (convertView == null) {\n                    convertView = LayoutInflater.from(ConvertToOpportunityWizard.this)\n                            .inflate(getResource(), parent, false);\n                }\n                ODataRow row = (ODataRow) getItem(position);\n                OControls.setText(convertView, R.id.name, row.getString(\"name\"));\n                OControls.setText(convertView, R.id.stage, row.getString(\"stage_name\"));\n                OControls.setText(convertView, R.id.type, StringUtils.capitalizeString(row.getString(\"type\")));\n                String date = ODateUtils.convertToDefault(row.getString(\"create_date\"),\n                        ODateUtils.DEFAULT_FORMAT, \"MMMM, dd\");\n                OControls.setText(convertView, R.id.create_date, date);\n                convertView.findViewById(R.id.remove_lead).setTag(position);\n                convertView.findViewById(R.id.remove_lead).setOnClickListener(ConvertToOpportunityWizard.this);\n                return convertView;\n            }\n        };\n        mOpportunityList.setAdapter(mAdapter);\n    }\n\n    @Override\n    public void onClick(View v) {\n        switch (v.getId()) {\n            case R.id.create_opportunity:\n                ArrayList<Integer> ids = new ArrayList<>();\n                for (Object data : items) {\n                    ODataRow row = (ODataRow) data;\n                    ids.add(row.getInt(\"id\"));\n                }\n                Intent result = new Intent();\n                result.putIntegerArrayListExtra(KEY_LEADS_IDS, ids);\n                setResult(RESULT_OK, result);\n                finish();\n                break;\n            case R.id.remove_lead:\n                int pos = (int) v.getTag();\n                items.remove(pos);\n                mAdapter.notifiyDataChange(items);\n                if (items.size() == 0) {\n                    conversation_action.setValue(1);\n                }\n                break;\n            case R.id.cancel:\n                finish();\n                break;\n        }\n    }\n\n    @Override\n    public void onFieldValueChange(OField field, Object value) {\n        ODataRow record = (ODataRow) value;\n        int index = record.getInt(OColumn.ROW_ID);\n        switch (index) {\n            case -1:\n            case 0:\n                findViewById(R.id.opportunity_container).setVisibility(View.GONE);\n                break;\n            case 1:\n                findViewById(R.id.opportunity_container).setVisibility(View.VISIBLE);\n                init();\n                break;\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/addons/crm/ConvertToQuotation.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 28/1/15 10:57 AM\n */\npackage com.odoo.addons.crm;\n\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.support.v7.app.ActionBarActivity;\nimport android.view.View;\nimport android.view.ViewGroup;\n\nimport com.odoo.addons.crm.models.CRMLead;\nimport com.odoo.core.orm.ODataRow;\nimport com.odoo.core.orm.fields.OColumn;\nimport com.odoo.R;\n\nimport odoo.controls.OField;\nimport odoo.controls.OForm;\n\n\npublic class ConvertToQuotation extends ActionBarActivity implements View.OnClickListener {\n    public static final String TAG = ConvertToQuotation.class.getSimpleName();\n    private Bundle extra;\n    private OForm convert_form;\n    private CRMLead crmLead = null;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.crm_convert_to_quotation);\n        getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT,\n                ViewGroup.LayoutParams.WRAP_CONTENT);\n        getSupportActionBar().hide();\n        setResult(RESULT_CANCELED);\n        extra = getIntent().getExtras();\n        crmLead = new CRMLead(this, null);\n        ODataRow lead = crmLead.browse(extra.getInt(OColumn.ROW_ID));\n        ODataRow customer = new ODataRow();\n        customer.put(\"partner_id\", lead.getInt(\"partner_id\"));\n        convert_form = (OForm) findViewById(R.id.convert_form);\n        convert_form.setEditable(true);\n        convert_form.initForm(customer);\n        findViewById(R.id.create_quotation).setOnClickListener(this);\n        findViewById(R.id.cancel).setOnClickListener(this);\n\n    }\n\n    @Override\n    public void onClick(View v) {\n        switch (v.getId()) {\n            case R.id.create_quotation:\n                if (convert_form.getValues().getInt(\"partner_id\") <= 0) {\n                    OField partner = (OField) convert_form.findViewById(R.id.partner);\n                    partner.setError(\"Select Partner\");\n                    partner.requestFocus();\n                } else {\n                    boolean mark_won = convert_form.getValues().getBoolean(\"mark_won\");\n                    String partner_id = convert_form.getValues().getString(\"partner_id\");\n                    Intent data = new Intent();\n                    data.putExtra(OColumn.ROW_ID, extra.getInt(OColumn.ROW_ID));\n                    data.putExtra(\"partner_id\", partner_id);\n                    data.putExtra(\"mark_won\", mark_won);\n                    setResult(RESULT_OK, data);\n                    finish();\n                }\n                break;\n            case R.id.cancel:\n                finish();\n                break;\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/addons/crm/models/CRMCaseCateg.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 13/1/15 10:15 AM\n */\npackage com.odoo.addons.crm.models;\n\nimport android.content.Context;\n\nimport com.odoo.core.orm.OModel;\nimport com.odoo.core.orm.fields.OColumn;\nimport com.odoo.core.orm.fields.types.OVarchar;\nimport com.odoo.core.support.OUser;\n\npublic class CRMCaseCateg extends OModel {\n    public static final String TAG = CRMCaseCateg.class.getSimpleName();\n    OColumn name = new OColumn(\"Name\", OVarchar.class);\n\n    public CRMCaseCateg(Context context, OUser user) {\n        super(context, \"crm.case.categ\", user);\n        if (getOdooVersion() != null) {\n            int version = getOdooVersion().getVersion_number();\n            String serie = getOdooVersion().getServer_serie();\n            if (version >= 9 || serie.equals(\"8.saas~6\")) {\n                setModelName(\"crm.lead.tag\");\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/addons/crm/models/CRMCaseStage.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 13/1/15 10:12 AM\n */\npackage com.odoo.addons.crm.models;\n\nimport android.content.Context;\n\nimport com.odoo.core.orm.OModel;\nimport com.odoo.core.orm.fields.OColumn;\nimport com.odoo.core.orm.fields.types.OBoolean;\nimport com.odoo.core.orm.fields.types.OFloat;\nimport com.odoo.core.orm.fields.types.OInteger;\nimport com.odoo.core.orm.fields.types.OVarchar;\nimport com.odoo.core.support.OUser;\n\npublic class CRMCaseStage extends OModel {\n    public static final String TAG = CRMCaseStage.class.getSimpleName();\n    OColumn name = new OColumn(\"Name\", OVarchar.class);\n    OColumn sequence = new OColumn(\"Sequence\", OInteger.class);\n    OColumn probability = new OColumn(\"Probability (%)\", OFloat.class).setSize(20);\n    OColumn case_default = new OColumn(\"Default to New Sales Team\",\n            OBoolean.class);\n    OColumn type = new OColumn(\"Type\", OVarchar.class);\n\n    public CRMCaseStage(Context context, OUser user) {\n        super(context, \"crm.case.stage\", user);\n        if (getOdooVersion() != null) {\n            int version = getOdooVersion().getVersion_number();\n            String serieVersion = getOdooVersion().getServer_serie();\n            if (serieVersion.equals(\"8.saas~6\") || version >= 9) {\n                setModelName(\"crm.stage\");\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/addons/crm/models/CRMLead.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 13/1/15 10:07 AM\n */\npackage com.odoo.addons.crm.models;\n\nimport android.app.ProgressDialog;\nimport android.content.Context;\nimport android.net.Uri;\nimport android.os.AsyncTask;\nimport android.os.Bundle;\nimport android.text.TextUtils;\n\nimport com.odoo.R;\nimport com.odoo.base.addons.res.ResCompany;\nimport com.odoo.base.addons.res.ResCountry;\nimport com.odoo.base.addons.res.ResCurrency;\nimport com.odoo.base.addons.res.ResPartner;\nimport com.odoo.base.addons.res.ResUsers;\nimport com.odoo.core.account.BaseSettings;\nimport com.odoo.core.orm.ODataRow;\nimport com.odoo.core.orm.OModel;\nimport com.odoo.core.orm.OValues;\nimport com.odoo.core.orm.annotation.Odoo;\nimport com.odoo.core.orm.fields.OColumn;\nimport com.odoo.core.orm.fields.types.OBoolean;\nimport com.odoo.core.orm.fields.types.ODate;\nimport com.odoo.core.orm.fields.types.ODateTime;\nimport com.odoo.core.orm.fields.types.OFloat;\nimport com.odoo.core.orm.fields.types.OInteger;\nimport com.odoo.core.orm.fields.types.OText;\nimport com.odoo.core.orm.fields.types.OVarchar;\nimport com.odoo.core.support.OUser;\nimport com.odoo.core.utils.JSONUtils;\nimport com.odoo.core.utils.ODateUtils;\nimport com.odoo.core.utils.OResource;\nimport com.odoo.core.utils.reminder.ReminderUtils;\n\nimport org.json.JSONArray;\nimport org.json.JSONObject;\n\nimport java.util.Date;\nimport java.util.List;\n\nimport odoo.OArguments;\nimport odoo.ODomain;\n\npublic class CRMLead extends OModel {\n    public static final String TAG = CRMLead.class.getSimpleName();\n    public static final String AUTHORITY = \"com.odoo.core.crm.provider.content.sync.crm_lead\";\n    public static final String KEY_LEAD = \"lead\";\n    public static final String KEY_OPPORTUNITY = \"opportunity\";\n    private Context mContext;\n\n    @Odoo.onChange(method = \"partnerIdOnChange\")\n    OColumn partner_id = new OColumn(\"Customer\", ResPartner.class,\n            OColumn.RelationType.ManyToOne).addDomain(\"customer\", \"=\", \"true\");\n    OColumn name = new OColumn(\"Name\", OVarchar.class).setSize(64)\n            .setRequired();\n    OColumn email_from = new OColumn(\"Email\", OVarchar.class).setSize(128);\n    OColumn street = new OColumn(\"Street\", OText.class);\n    OColumn street2 = new OColumn(\"Street2\", OText.class);\n    OColumn city = new OColumn(\"City\", OVarchar.class).setSize(100);\n    OColumn zip = new OColumn(\"Zip\", OVarchar.class).setSize(20);\n    OColumn mobile = new OColumn(\"Mobile\", OVarchar.class).setSize(20);\n    OColumn phone = new OColumn(\"Phone\", OVarchar.class).setSize(20);\n    OColumn create_date = new OColumn(\"Creation Date\", ODateTime.class);\n    OColumn description = new OColumn(\"Internal Notes\", OText.class);\n    @Odoo.api.v7\n    @Odoo.api.v8\n    OColumn categ_ids = new OColumn(\"Tags\", CRMCaseCateg.class,\n            OColumn.RelationType.ManyToMany);\n    @Odoo.api.v9alpha\n    OColumn tag_ids = new OColumn(\"Tags\", CRMCaseCateg.class,\n            OColumn.RelationType.ManyToMany);\n    OColumn contact_name = new OColumn(\"Contact Name\", OVarchar.class);\n    OColumn partner_name = new OColumn(\"Company Name\", OVarchar.class);\n    OColumn opt_out = new OColumn(\"Opt-Out\", OBoolean.class);\n    OColumn type = new OColumn(\"Type\", OVarchar.class).setDefaultValue(\"lead\");\n    OColumn priority = new OColumn(\"Priority\", OVarchar.class).setSize(10);\n    OColumn date_open = new OColumn(\"Assigned\", ODateTime.class);\n    OColumn date_closed = new OColumn(\"Closed\", ODateTime.class);\n    OColumn stage_id = new OColumn(\"Stage\", CRMCaseStage.class,\n            OColumn.RelationType.ManyToOne);\n    OColumn user_id = new OColumn(\"Salesperson\", ResUsers.class,\n            OColumn.RelationType.ManyToOne);\n    OColumn referred = new OColumn(\"Referred By\", OVarchar.class);\n    OColumn company_id = new OColumn(\"Company\", ResCompany.class,\n            OColumn.RelationType.ManyToOne);\n    OColumn country_id = new OColumn(\"Country\", ResCountry.class,\n            OColumn.RelationType.ManyToOne);\n    OColumn company_currency = new OColumn(\"Company Currency\",\n            ResCurrency.class, OColumn.RelationType.ManyToOne);\n\n    /**\n     * Only used for type opportunity\n     */\n\n    OColumn probability = new OColumn(\"Success Rate (%)\", OFloat.class).setSize(20).setDefaultValue(\"0.0\");\n    OColumn planned_revenue = new OColumn(\"Expected Revenue\", OFloat.class).setSize(20).setDefaultValue(\"0.0\");\n    OColumn ref = new OColumn(\"Reference\", OVarchar.class);\n    OColumn ref2 = new OColumn(\"Reference 2\", OVarchar.class);\n    OColumn date_deadline = new OColumn(\"Expected Closing\", ODate.class);\n    OColumn date_action = new OColumn(\"Next Action\", ODate.class);\n    OColumn title_action = new OColumn(\"Next Action\", OVarchar.class);\n    OColumn planned_cost = new OColumn(\"Planned Cost\", OFloat.class).setSize(20);\n\n    /**\n     * Extra functional fields\n     */\n    @Odoo.Functional(method = \"getDisplayName\", store = true, depends = {\n            \"partner_id\", \"contact_name\", \"partner_name\"})\n    OColumn display_name = new OColumn(\"Display Name\", OVarchar.class)\n            .setLocalColumn();\n    @Odoo.Functional(method = \"storeAssigneeName\", store = true, depends = {\"user_id\"})\n    OColumn assignee_name = new OColumn(\"Assignee\", OVarchar.class).setSize(100)\n            .setLocalColumn();\n    @Odoo.Functional(method = \"storeStageName\", store = true, depends = {\"stage_id\"})\n    OColumn stage_name = new OColumn(\"Stage name\", OVarchar.class).setLocalColumn();\n    OColumn data_type = new OColumn(\"Data type\", OVarchar.class).setSize(34)\n            .setLocalColumn().setDefaultValue(\"opportunity\");\n    OColumn is_done = new OColumn(\"Mark as Done\", OInteger.class)\n            .setLocalColumn().setDefaultValue(\"0\");\n\n    OColumn color_index = new OColumn(\"Color index\", OInteger.class).setSize(5)\n            .setLocalColumn().setDefaultValue(7);\n\n    public CRMLead(Context context, OUser user) {\n        super(context, \"crm.lead\", user);\n        mContext = context;\n        setHasMailChatter(true);\n        String serie = getOdooVersion().getServer_serie();\n        if (serie.equals(\"8.saas~6\")) {\n            categ_ids.setName(\"tag_ids\");\n        }\n    }\n\n    @Override\n    public Uri uri() {\n        return buildURI(AUTHORITY);\n    }\n\n    public ODataRow partnerIdOnChange(ODataRow row) {\n        ODataRow rec = new ODataRow();\n        String display_name = \"\";\n        String contact_name = \"\";\n        ResCountry country = new ResCountry(mContext, null);\n        try {\n            rec.put(\"partner_name\", row.getString(\"name\"));\n            rec.put(\"partner_name\", rec.getString(\"partner_name\"));\n            if (!row.getString(\"parent_id\").equals(\"false\")) {\n                if (row.get(\"parent_id\") instanceof JSONArray) {\n                    JSONArray parent_id = new JSONArray(\n                            row.getString(\"parent_id\"));\n                    rec.put(\"partner_name\", parent_id.get(1));\n                    display_name = parent_id.getString(1);\n                    contact_name = parent_id.getString(1);\n                } else {\n                    ODataRow parent_id = row.getM2ORecord(\"parent_id\").browse();\n                    if (parent_id != null) {\n                        rec.put(\"partner_name\", parent_id.getString(\"name\"));\n                        display_name = parent_id.getString(\"name\");\n                        contact_name = parent_id.getString(\"name\");\n                    }\n\n                }\n                if (!TextUtils.isEmpty(display_name)) {\n                    display_name += \" (\" + row.getString(\"name\") + \")\";\n                    contact_name = row.getString(\"name\");\n                } else {\n                    display_name += row.getString(\"name\");\n                }\n            } else {\n                display_name = row.getString(\"name\");\n\n            }\n            Integer country_id = 0;\n            if (!row.getString(\"country_id\").equals(\"false\")) {\n                if (row.get(\"country_id\") instanceof JSONArray) {\n                    JSONArray country_data = new JSONArray(\n                            row.getString(\"country_id\"));\n                    country_id = country.selectRowId(country_data.getInt(0));\n                    if (country_id == null) {\n                        country_id = 0;\n                    }\n                } else {\n                    ODataRow country_data = row.getM2ORecord(\"country_id\")\n                            .browse();\n                    if (country_data != null) {\n                        country_id = country_data.getInt(OColumn.ROW_ID);\n                    }\n                }\n                if (country_id != 0)\n                    rec.put(\"country_id\", country_id);\n            }\n            rec.put(\"display_name\", display_name);\n            rec.put(\"contact_name\", contact_name);\n            rec.put(\"street\", row.getString(\"street\"));\n            rec.put(\"street2\", row.getString(\"street2\"));\n            rec.put(\"city\", row.getString(\"city\"));\n            rec.put(\"zip\", row.getString(\"zip\"));\n            rec.put(\"email_from\", row.getString(\"email\"));\n            rec.put(\"phone\", row.getString(\"phone\"));\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return rec;\n    }\n\n    public String getDisplayName(OValues row) {\n        String name = \"\";\n        try {\n            if (!row.getString(\"partner_id\").equals(\"false\")) {\n                JSONArray partner_id = new JSONArray(\n                        row.getString(\"partner_id\"));\n                name = partner_id.getString(1);\n            } else if (!row.getString(\"partner_name\").equals(\"false\")) {\n                name = row.getString(\"partner_name\");\n            }\n            if (!row.getString(\"contact_name\").equals(\"false\")) {\n                name += (TextUtils.isEmpty(name)) ? row\n                        .getString(\"contact_name\") : \" (\"\n                        + row.getString(\"contact_name\") + \")\";\n            }\n            if (TextUtils.isEmpty(name)) {\n                name = \"No Partner\";\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return name;\n    }\n\n    public String storeAssigneeName(OValues vals) {\n        try {\n            if (!vals.getString(\"user_id\").equals(\"false\")) {\n                JSONArray user_id = new JSONArray(vals.getString(\"user_id\"));\n                return user_id.getString(1);\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return \"Unassigned\";\n    }\n\n    public String storeStageName(OValues values) {\n        try {\n            JSONArray stage_id = new JSONArray(values.getString(\"stage_id\"));\n            return stage_id.getString(1);\n        } catch (Exception e) {\n\n        }\n        return \"false\";\n    }\n\n\n    public void convertToOpportunity(final ODataRow lead, final List<Integer> other_lead_ids,\n                                     final OnOperationSuccessListener listener) {\n        new AsyncTask<Void, Void, Void>() {\n            private ProgressDialog dialog;\n\n            @Override\n            protected void onPreExecute() {\n                super.onPreExecute();\n                dialog = new ProgressDialog(mContext);\n                dialog.setTitle(R.string.title_please_wait);\n                dialog.setMessage(OResource.string(mContext, R.string.title_working));\n                dialog.setCancelable(false);\n                dialog.show();\n            }\n\n            @Override\n            protected Void doInBackground(Void... params) {\n                try {\n                    odoo.Odoo odoo = getServerDataHelper().getOdoo();\n                    // Creating wizard record\n                    JSONObject values = new JSONObject();\n                    values.put(\"name\", (other_lead_ids.size() > 0) ? \"merge\" : \"convert\");\n                    Object partner_id = false;\n                    ODataRow partner = null;\n                    if (!lead.getString(\"partner_id\").equals(\"false\")) {\n                        ResPartner resPartner = new ResPartner(mContext, getUser());\n                        partner = resPartner.browse(lead.getInt(\"partner_id\"));\n                        partner_id = partner.getInt(\"id\");\n                    }\n                    values.put(\"action\", (partner == null) ? \"create\" : \"exist\");\n                    values.put(\"partner_id\", partner_id);\n\n                    JSONObject context = new JSONObject();\n                    context.put(\"stage_type\", \"lead\");\n                    context.put(\"active_id\", lead.getInt(\"id\"));\n                    other_lead_ids.add(lead.getInt(\"id\"));\n                    context.put(\"active_ids\", JSONUtils.<Integer>toArray(other_lead_ids));\n                    context.put(\"active_model\", \"crm.lead\");\n                    odoo.updateContext(context);\n                    JSONObject result = odoo.createNew(\"crm.lead2opportunity.partner\", values);\n                    int lead_to_opp_partner_id = result.getInt(\"result\");\n\n                    // Converting lead to opportunity\n                    OArguments arg = new OArguments();\n                    arg.add(lead_to_opp_partner_id);\n                    arg.add(context);\n                    odoo.call_kw(\"crm.lead2opportunity.partner\", \"action_apply\", arg.get());\n                    OValues val = new OValues();\n                    val.put(\"type\", \"opportunity\");\n                    for (int id : other_lead_ids) {\n                        update(selectRowId(id), val);\n                    }\n                } catch (Exception e) {\n                    e.printStackTrace();\n                }\n                return null;\n            }\n\n            @Override\n            protected void onPostExecute(Void aVoid) {\n                super.onPostExecute(aVoid);\n                dialog.dismiss();\n                if (listener != null) {\n                    listener.OnSuccess();\n                }\n            }\n\n            @Override\n            protected void onCancelled() {\n                super.onCancelled();\n                dialog.dismiss();\n                if (listener != null) {\n                    listener.OnCancelled();\n                }\n            }\n        }.execute();\n    }\n\n    private void _markWonLost(String type, ODataRow record) {\n        OArguments oArguments = new OArguments();\n        oArguments.add(new JSONArray().put(record.getInt(\"id\")));\n        getServerDataHelper().callMethod(\"case_mark_\" + type, oArguments, new JSONObject());\n        CRMCaseStage stage = new CRMCaseStage(mContext, getUser());\n        String key = (type.equals(\"won\")) ? \"Won\" : (record.getString(\"type\").equals(\"lead\")) ? \"Dead\" : \"Lost\";\n        ODataRow row = stage.browse(null, \"name = ?\", new String[]{key});\n        if (row != null) {\n            OValues values = new OValues();\n            values.put(\"stage_id\", row.getInt(OColumn.ROW_ID));\n            values.put(\"stage_name\", row.getString(\"name\"));\n            values.put(\"probability\", row.getFloat(\"probability\"));\n            update(record.getInt(OColumn.ROW_ID), values);\n        }\n    }\n\n    /**\n     * Setting reminder for lead/opportunity\n     *\n     * @param row_id\n     */\n    public void setReminder(int row_id) {\n        ODataRow row = browse(row_id);\n        String time = \" \" + BaseSettings.getDayStartTime(mContext);\n        Date now = new Date();\n        Bundle extra = row.getPrimaryBundleData();\n        extra.putString(ReminderUtils.KEY_REMINDER_TYPE, \"opportunity\");\n        if (!row.getString(\"date_deadline\").equals(\"false\")) {\n            row.put(\"date_deadline\", row.getString(\"date_deadline\") + time);\n            Date date_deadline = ODateUtils.createDateObject(row.getString(\"date_deadline\"),\n                    ODateUtils.DEFAULT_FORMAT, false);\n            if (now.compareTo(date_deadline) < 0) {\n                extra.putBoolean(\"expiry_date\", true);\n                if (ReminderUtils.get(mContext).resetReminder(date_deadline, extra)) {\n                    // Nothing to do. Reminder set for expiry date\n                }\n            }\n        }\n\n        if (!row.getString(\"date_action\").equals(\"false\")) {\n            row.put(\"date_action\", row.getString(\"date_action\") + time);\n            Date date_action = ODateUtils.createDateObject(row.getString(\"date_action\"),\n                    ODateUtils.DEFAULT_FORMAT, false);\n            if (now.compareTo(date_action) < 0) {\n                extra.putBoolean(\"expiry_date\", false);\n                if (ReminderUtils.get(mContext).resetReminder(date_action, extra)) {\n                    // Nothing to do. Reminder set for next date action\n                }\n            }\n\n        }\n    }\n\n    public void markWonLost(final String type, final ODataRow record, final OnOperationSuccessListener listener) {\n        new AsyncTask<Void, Void, Void>() {\n            private ProgressDialog dialog;\n\n            @Override\n            protected void onPreExecute() {\n                super.onPreExecute();\n                dialog = new ProgressDialog(mContext);\n                dialog.setTitle(R.string.title_please_wait);\n                dialog.setMessage(OResource.string(mContext, R.string.title_working));\n                dialog.setCancelable(false);\n                dialog.show();\n            }\n\n            @Override\n            protected Void doInBackground(Void... params) {\n                _markWonLost(type, record);\n                return null;\n            }\n\n            @Override\n            protected void onPostExecute(Void aVoid) {\n                super.onPostExecute(aVoid);\n                dialog.dismiss();\n                if (listener != null) {\n                    listener.OnSuccess();\n                }\n            }\n\n            @Override\n            protected void onCancelled() {\n                super.onCancelled();\n                dialog.dismiss();\n                if (listener != null) {\n                    listener.OnCancelled();\n                }\n            }\n        }.execute();\n\n    }\n\n\n    public void createQuotation(final ODataRow lead, final String partnerId, final boolean close, final OnOperationSuccessListener listener) {\n        new AsyncTask<Void, Void, Void>() {\n            private ProgressDialog dialog;\n\n            @Override\n            protected void onPreExecute() {\n                super.onPreExecute();\n                dialog = new ProgressDialog(mContext);\n                dialog.setTitle(R.string.title_please_wait);\n                dialog.setMessage(OResource.string(mContext, R.string.title_working));\n                dialog.setCancelable(false);\n                dialog.show();\n            }\n\n            @Override\n            protected Void doInBackground(Void... params) {\n                try {\n                    odoo.Odoo odoo = getServerDataHelper().getOdoo();\n                    // Creating wizard record\n                    JSONObject values = new JSONObject();\n                    ResPartner resPartner = new ResPartner(mContext, getUser());\n                    ODataRow partner = resPartner.browse(new String[]{}, Integer.parseInt(partnerId));\n                    values.put(\"partner_id\", partner.getInt(\"id\"));\n                    values.put(\"close\", close);\n                    JSONObject context = new JSONObject();\n                    context.put(\"stage_type\", lead.getString(\"type\"));\n                    context.put(\"active_id\", lead.getInt(\"id\"));\n                    context.put(\"active_ids\", new JSONArray().put(lead.getInt(\"id\")));\n                    context.put(\"active_model\", \"crm.lead\");\n                    odoo.updateContext(context);\n                    JSONObject result = odoo.createNew(\"crm.make.sale\", values);\n                    int quotation_wizard_id = result.getInt(\"result\");\n\n                    // Creating quotation\n                    OArguments arg = new OArguments();\n                    arg.add(quotation_wizard_id);\n                    arg.add(context);\n                    odoo.call_kw(\"crm.make.sale\", \"makeOrder\", arg.get());\n                    Thread.sleep(500);\n                    // if close = true\n                    if (close)\n                        _markWonLost(\"won\", lead);\n                } catch (Exception e) {\n                    e.printStackTrace();\n                }\n                return null;\n            }\n\n            @Override\n            protected void onPostExecute(Void aVoid) {\n                super.onPostExecute(aVoid);\n\n                dialog.dismiss();\n                if (listener != null) {\n                    listener.OnSuccess();\n                }\n            }\n\n            @Override\n            protected void onCancelled() {\n                super.onCancelled();\n                dialog.dismiss();\n                if (listener != null) {\n                    listener.OnCancelled();\n                }\n            }\n        }.execute();\n    }\n\n\n    @Override\n    public ODomain defaultDomain() {\n        ODomain domain = new ODomain();\n        domain.add(\"|\");\n        domain.add(\"user_id\", \"=\", getUser().getUser_id());\n        domain.add(\"user_id\", \"=\", false);\n        return domain;\n    }\n\n    public static interface OnOperationSuccessListener {\n        public void OnSuccess();\n\n        public void OnCancelled();\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/addons/crm/providers/CRMLeadProvider.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 13/1/15 11:28 AM\n */\npackage com.odoo.addons.crm.providers;\n\nimport android.net.Uri;\n\nimport com.odoo.addons.crm.models.CRMLead;\nimport com.odoo.core.orm.provider.BaseModelProvider;\n\npublic class CRMLeadProvider extends BaseModelProvider {\n    public static final String TAG = CRMLeadProvider.class.getSimpleName();\n\n    @Override\n    public void setModel(Uri uri) {\n        super.setModel(uri);\n        mModel = new CRMLead(getContext(), getUser(uri));\n    }\n\n    @Override\n    public String authority() {\n        return CRMLead.AUTHORITY;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/addons/crm/services/CRMLeadSyncService.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 13/1/15 11:31 AM\n */\npackage com.odoo.addons.crm.services;\n\nimport android.content.Context;\nimport android.content.SyncResult;\nimport android.os.Bundle;\nimport android.util.Log;\n\nimport com.odoo.addons.crm.CRMLeads;\nimport com.odoo.addons.crm.models.CRMCaseStage;\nimport com.odoo.addons.crm.models.CRMLead;\nimport com.odoo.core.orm.ODataRow;\nimport com.odoo.core.orm.fields.OColumn;\nimport com.odoo.core.service.ISyncFinishListener;\nimport com.odoo.core.service.OSyncAdapter;\nimport com.odoo.core.service.OSyncService;\nimport com.odoo.core.support.OUser;\n\nimport odoo.ODomain;\n\npublic class CRMLeadSyncService extends OSyncService implements ISyncFinishListener {\n    public static final String TAG = CRMLeadSyncService.class.getSimpleName();\n    private Context mContext;\n    private OSyncService service;\n\n    @Override\n    public OSyncAdapter getSyncAdapter(OSyncService service, Context context) {\n        mContext = context;\n        this.service = service;\n        return new OSyncAdapter(context, CRMLead.class, service, true);\n    }\n\n    @Override\n    public void performDataSync(OSyncAdapter adapter, Bundle extras, OUser user) {\n        if (adapter.getModel().getModelName().equals(\"crm.lead\")) {\n            ODomain domain = new ODomain();\n            if (extras.containsKey(CRMLeads.KEY_IS_LEAD)) {\n                domain.add(\"type\", \"=\",\n                        (extras.getBoolean(CRMLeads.KEY_IS_LEAD)) ? \"lead\" : \"opportunity\");\n                adapter.setDomain(domain);\n                Log.d(TAG, \"Setting lead filter type\");\n            }\n            adapter.onSyncFinish(this).syncDataLimit(50);\n        }\n    }\n\n    @Override\n    public OSyncAdapter performNextSync(OUser user, SyncResult syncResult) {\n        CRMLead crmLead = new CRMLead(mContext, user);\n        for (ODataRow row : crmLead.select(new String[]{})) {\n            crmLead.setReminder(row.getInt(OColumn.ROW_ID));\n        }\n        return new OSyncAdapter(mContext, CRMCaseStage.class, service, true);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/addons/customers/CustomerDetails.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 8/1/15 5:47 PM\n */\npackage com.odoo.addons.customers;\n\nimport android.content.Intent;\nimport android.graphics.Color;\nimport android.graphics.drawable.ColorDrawable;\nimport android.graphics.drawable.GradientDrawable;\nimport android.os.AsyncTask;\nimport android.os.Bundle;\nimport android.support.v7.app.ActionBar;\nimport android.support.v7.app.ActionBarActivity;\nimport android.view.Menu;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.widget.FrameLayout;\nimport android.widget.ImageView;\nimport android.widget.TextView;\nimport android.widget.Toast;\n\nimport com.odoo.App;\nimport com.odoo.addons.customers.utils.ShareUtil;\nimport com.odoo.base.addons.ir.feature.OFileManager;\nimport com.odoo.base.addons.res.ResPartner;\nimport com.odoo.core.orm.ODataRow;\nimport com.odoo.core.orm.OModel;\nimport com.odoo.core.orm.OValues;\nimport com.odoo.core.orm.fields.OColumn;\nimport com.odoo.core.service.OSyncAdapter;\nimport com.odoo.core.support.OdooFields;\nimport com.odoo.core.utils.BitmapUtils;\nimport com.odoo.core.utils.IntentUtils;\nimport com.odoo.core.utils.OActionBarUtils;\nimport com.odoo.core.utils.OStringColorUtil;\nimport com.odoo.R;\nimport com.odoo.widgets.parallax.ParallaxScrollView;\n\nimport org.json.JSONObject;\n\nimport odoo.ODomain;\nimport odoo.Odoo;\nimport odoo.controls.OField;\nimport odoo.controls.OForm;\n\npublic class CustomerDetails extends ActionBarActivity implements View.OnClickListener, OField.IOnFieldValueChangeListener {\n    public static final String TAG = CustomerDetails.class.getSimpleName();\n    private final String KEY_MODE = \"key_edit_mode\";\n    private final String KEY_NEW_IMAGE = \"key_new_image\";\n    private ActionBar actionBar;\n    private Bundle extras;\n    private ResPartner resPartner;\n    private ODataRow record = null;\n    private ParallaxScrollView parallaxScrollView;\n    private ImageView userImage = null, captureImage = null;\n    private TextView mTitleView = null;\n    private OForm mForm;\n    private App app;\n    private Boolean mEditMode = false;\n    private Menu mMenu;\n    private OFileManager fileManager;\n    private String newImage = null;\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.customer_detail);\n        OActionBarUtils.setActionBar(this, false);\n        fileManager = new OFileManager(this);\n        actionBar = getSupportActionBar();\n        actionBar.setTitle(\"\");\n        if (savedInstanceState != null) {\n            mEditMode = savedInstanceState.getBoolean(KEY_MODE);\n            newImage = savedInstanceState.getString(KEY_NEW_IMAGE);\n        }\n        app = (App) getApplicationContext();\n        parallaxScrollView = (ParallaxScrollView) findViewById(R.id.parallaxScrollView);\n        parallaxScrollView.setActionBar(actionBar);\n        userImage = (ImageView) findViewById(android.R.id.icon);\n        mTitleView = (TextView) findViewById(android.R.id.title);\n        resPartner = new ResPartner(this, null);\n        extras = getIntent().getExtras();\n        if (extras == null)\n            mEditMode = true;\n        setupActionBar();\n    }\n\n    private void setMode(Boolean edit) {\n        if (mMenu != null) {\n            mMenu.findItem(R.id.menu_customer_detail_more).setVisible(!edit);\n            mMenu.findItem(R.id.menu_customer_edit).setVisible(!edit);\n            mMenu.findItem(R.id.menu_customer_save).setVisible(edit);\n            mMenu.findItem(R.id.menu_customer_cancel).setVisible(edit);\n        }\n        int color = Color.DKGRAY;\n        if (record != null) {\n            color = OStringColorUtil.getStringColor(this, record.getString(\"name\"));\n        }\n        if (edit) {\n            if (extras != null)\n                actionBar.setTitle(R.string.label_edit);\n            else\n                actionBar.setTitle(R.string.label_new);\n            actionBar.setBackgroundDrawable(new ColorDrawable(color));\n            mForm = (OForm) findViewById(R.id.customerFormEdit);\n            captureImage = (ImageView) findViewById(R.id.captureImage);\n            captureImage.setOnClickListener(this);\n            userImage = (ImageView) findViewById(android.R.id.icon1);\n            findViewById(R.id.parallaxScrollView).setVisibility(View.GONE);\n            findViewById(R.id.customerScrollViewEdit).setVisibility(View.VISIBLE);\n            OField is_company = (OField) findViewById(R.id.is_company_edit);\n            is_company.setOnValueChangeListener(this);\n        } else {\n            actionBar.setBackgroundDrawable(getResources().getDrawable(R.drawable.action_bar_shade));\n            userImage = (ImageView) findViewById(android.R.id.icon);\n            mForm = (OForm) findViewById(R.id.customerForm);\n            findViewById(R.id.customerScrollViewEdit).setVisibility(View.GONE);\n            findViewById(R.id.parallaxScrollView).setVisibility(View.VISIBLE);\n        }\n        setColor(color);\n    }\n\n    private void setupActionBar() {\n        if (extras == null) {\n            setMode(mEditMode);\n            userImage.setColorFilter(Color.parseColor(\"#ffffff\"));\n            mForm.setEditable(mEditMode);\n            mForm.initForm(null);\n        } else {\n            int rowId = extras.getInt(OColumn.ROW_ID);\n            record = resPartner.browse(rowId);\n            record.put(\"full_address\", resPartner.getAddress(record));\n            checkControls();\n            setMode(mEditMode);\n            mForm.setEditable(mEditMode);\n            mForm.initForm(record);\n            mTitleView.setText(record.getString(\"name\"));\n            setCustomerImage();\n            if (record.getInt(\"id\") != 0 && record.getString(\"large_image\").equals(\"false\")) {\n                BigImageLoader bigImageLoader = new BigImageLoader();\n                bigImageLoader.execute(record.getInt(\"id\"));\n            }\n        }\n    }\n\n    @Override\n    public void onClick(View v) {\n        switch (v.getId()) {\n            case R.id.full_address:\n                IntentUtils.redirectToMap(this, record.getString(\"full_address\"));\n                break;\n            case R.id.website:\n                IntentUtils.openURLInBrowser(this, record.getString(\"website\"));\n                break;\n            case R.id.email:\n                IntentUtils.requestMessage(this, record.getString(\"email\"));\n                break;\n            case R.id.phone_number:\n                IntentUtils.requestCall(this, record.getString(\"phone\"));\n                break;\n            case R.id.mobile_number:\n                IntentUtils.requestCall(this, record.getString(\"mobile\"));\n                break;\n            case R.id.captureImage:\n                fileManager.requestForFile(OFileManager.RequestType.IMAGE_OR_CAPTURE_IMAGE);\n                break;\n        }\n    }\n\n    private void checkControls() {\n        findViewById(R.id.full_address).setOnClickListener(this);\n        findViewById(R.id.website).setOnClickListener(this);\n        findViewById(R.id.email).setOnClickListener(this);\n        findViewById(R.id.phone_number).setOnClickListener(this);\n        findViewById(R.id.mobile_number).setOnClickListener(this);\n    }\n\n    private void setCustomerImage() {\n        if (!record.getString(\"image_small\").equals(\"false\")) {\n            userImage.setScaleType(ImageView.ScaleType.CENTER_CROP);\n            userImage.setColorFilter(null);\n            String base64 = newImage;\n            if (newImage == null) {\n                if (!record.getString(\"large_image\").equals(\"false\")) {\n                    base64 = record.getString(\"large_image\");\n                } else {\n                    base64 = record.getString(\"image_small\");\n                }\n            }\n            userImage.setImageBitmap(BitmapUtils.getBitmapImage(this, base64));\n        } else {\n            userImage.setColorFilter(Color.parseColor(\"#ffffff\"));\n        }\n    }\n\n    private void setColor(int color) {\n        FrameLayout frameLayout = (FrameLayout) findViewById(R.id.parallax_view);\n        frameLayout.setBackgroundColor(color);\n        parallaxScrollView.setParallaxOverLayColor(color);\n        parallaxScrollView.setBackgroundColor(color);\n        mForm.setIconTintColor(color);\n        findViewById(R.id.parallax_view).setBackgroundColor(color);\n        findViewById(R.id.parallax_view_edit).setBackgroundColor(color);\n        findViewById(R.id.customerScrollViewEdit).setBackgroundColor(color);\n        if (captureImage != null) {\n            GradientDrawable shapeDrawable =\n                    (GradientDrawable) getResources().getDrawable(R.drawable.circle_mask_primary);\n            shapeDrawable.setColor(color);\n            captureImage.setBackgroundDrawable(shapeDrawable);\n        }\n    }\n\n    @Override\n    public boolean onOptionsItemSelected(MenuItem item) {\n        switch (item.getItemId()) {\n            case R.id.menu_customer_save:\n                OValues values = mForm.getValues();\n                if (values != null) {\n                    if (newImage != null) {\n                        values.put(\"image_small\", newImage);\n                        values.put(\"large_image\", newImage);\n                    }\n                    if (record != null) {\n                        resPartner.update(record.getInt(OColumn.ROW_ID), values);\n                        Toast.makeText(this, R.string.toast_information_saved, Toast.LENGTH_LONG).show();\n                        mEditMode = !mEditMode;\n                        setupActionBar();\n                    } else {\n                        final int row_id = resPartner.insert(values);\n                        if (row_id != OModel.INVALID_ROW_ID) {\n                            finish();\n                        }\n                    }\n                }\n                break;\n            case R.id.menu_customer_cancel:\n                if (record == null) {\n                    finish();\n                    return true;\n                }\n            case R.id.menu_customer_edit:\n                mEditMode = !mEditMode;\n                setMode(mEditMode);\n                mForm.setEditable(mEditMode);\n                mForm.initForm(record);\n                setCustomerImage();\n                break;\n            case R.id.menu_customer_share:\n                ShareUtil.shareContact(this, record, true);\n                break;\n            case R.id.menu_customer_import:\n                ShareUtil.shareContact(this, record, false);\n                break;\n        }\n        return super.onOptionsItemSelected(item);\n    }\n\n    @Override\n    public boolean onCreateOptionsMenu(Menu menu) {\n        getMenuInflater().inflate(R.menu.menu_customer_detail, menu);\n        mMenu = menu;\n        setMode(mEditMode);\n        return true;\n    }\n\n    @Override\n    public void onFieldValueChange(OField field, Object value) {\n        if (field.getFieldName().equals(\"is_company\")) {\n            Boolean checked = Boolean.parseBoolean(value.toString());\n            int view = (checked) ? View.GONE : View.VISIBLE;\n            findViewById(R.id.parent_id).setVisibility(view);\n        }\n    }\n\n\n    private class BigImageLoader extends AsyncTask<Integer, Void, String> {\n\n        @Override\n        protected String doInBackground(Integer... params) {\n            String image = null;\n            try {\n                Thread.sleep(300);\n                Odoo odoo = app.getOdoo(resPartner.getUser());\n                if (odoo == null) {\n                    odoo = OSyncAdapter.createOdooInstance(CustomerDetails.this, resPartner.getUser());\n                }\n                ODomain domain = new ODomain();\n                domain.add(\"id\", \"=\", params[0]);\n                JSONObject result = odoo.search_read(resPartner.getModelName(),\n                        new OdooFields(new String[]{\"image_medium\"}).get(),\n                        domain.get());\n                JSONObject records = result.getJSONArray(\"records\")\n                        .getJSONObject(0);\n                if (!records.getString(\"image_medium\").equals(\"false\")) {\n                    image = records.getString(\"image_medium\");\n                }\n            } catch (Exception e) {\n                e.printStackTrace();\n            }\n            return image;\n        }\n\n        @Override\n        protected void onPostExecute(String result) {\n            super.onPostExecute(result);\n            if (result != null) {\n                if (!result.equals(\"false\")) {\n                    OValues values = new OValues();\n                    values.put(\"large_image\", result);\n                    resPartner.update(record.getInt(OColumn.ROW_ID), values);\n                    record.put(\"large_image\", result);\n                    setCustomerImage();\n                }\n            }\n        }\n    }\n\n    @Override\n    protected void onSaveInstanceState(Bundle outState) {\n        super.onSaveInstanceState(outState);\n        outState.putBoolean(KEY_MODE, mEditMode);\n        outState.putString(KEY_NEW_IMAGE, newImage);\n    }\n\n    @Override\n    protected void onActivityResult(int requestCode, int resultCode, Intent data) {\n        super.onActivityResult(requestCode, resultCode, data);\n        OValues values = fileManager.handleResult(requestCode, resultCode, data);\n        if (values != null && !values.contains(\"size_limit_exceed\")) {\n            newImage = values.getString(\"datas\");\n            userImage.setScaleType(ImageView.ScaleType.CENTER_CROP);\n            userImage.setColorFilter(null);\n            userImage.setImageBitmap(BitmapUtils.getBitmapImage(this, newImage));\n        } else if (values != null) {\n            Toast.makeText(this, R.string.toast_image_size_too_large, Toast.LENGTH_LONG).show();\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/addons/customers/Customers.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 30/12/14 3:28 PM\n */\npackage com.odoo.addons.customers;\n\nimport android.app.ProgressDialog;\nimport android.content.Context;\nimport android.database.Cursor;\nimport android.graphics.Bitmap;\nimport android.os.AsyncTask;\nimport android.os.Bundle;\nimport android.os.Handler;\nimport android.support.v4.app.LoaderManager;\nimport android.support.v4.content.CursorLoader;\nimport android.support.v4.content.Loader;\nimport android.support.v4.widget.SwipeRefreshLayout;\nimport android.text.TextUtils;\nimport android.view.LayoutInflater;\nimport android.view.Menu;\nimport android.view.MenuInflater;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.ListView;\nimport android.widget.Toast;\n\nimport com.odoo.addons.crm.CRMLeads;\nimport com.odoo.addons.crm.CRMOpportunitiesPager;\nimport com.odoo.addons.phonecall.PhoneCallDetail;\nimport com.odoo.base.addons.res.ResPartner;\nimport com.odoo.core.orm.ODataRow;\nimport com.odoo.core.orm.fields.OColumn;\nimport com.odoo.core.support.addons.fragment.BaseFragment;\nimport com.odoo.core.support.addons.fragment.IOnSearchViewChangeListener;\nimport com.odoo.core.support.addons.fragment.ISyncStatusObserverListener;\nimport com.odoo.core.support.drawer.ODrawerItem;\nimport com.odoo.core.support.list.IOnItemClickListener;\nimport com.odoo.core.support.list.OCursorListAdapter;\nimport com.odoo.core.utils.BitmapUtils;\nimport com.odoo.core.utils.IntentUtils;\nimport com.odoo.core.utils.OControls;\nimport com.odoo.core.utils.OCursorUtils;\nimport com.odoo.core.utils.sys.IOnBackPressListener;\nimport com.odoo.R;\nimport com.odoo.widgets.bottomsheet.BottomSheet;\nimport com.odoo.widgets.bottomsheet.BottomSheetListeners;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class Customers extends BaseFragment implements ISyncStatusObserverListener,\n        LoaderManager.LoaderCallbacks<Cursor>, SwipeRefreshLayout.OnRefreshListener,\n        OCursorListAdapter.OnViewBindListener, IOnSearchViewChangeListener, View.OnClickListener,\n        BottomSheetListeners.OnSheetItemClickListener, BottomSheetListeners.OnSheetActionClickListener,\n        IOnBackPressListener, IOnItemClickListener, BottomSheetListeners.OnSheetMenuCreateListener {\n\n    public static final String KEY = Customers.class.getSimpleName();\n    public static final String KEY_FILTER_REQUEST = \"key_filter_request\";\n    public static final String KEY_CUSTOMER_ID = \"key_customer_id\";\n    public static final String KEY_FILTER_TYPE = CRMLeads.KEY_MENU;\n    private View mView;\n    private String mCurFilter = null;\n    private ListView mPartnersList = null;\n    private OCursorListAdapter mAdapter = null;\n    private BottomSheet mSheet = null;\n    private boolean syncRequested = false;\n\n    public enum Type {\n        Leads, Opportunities\n    }\n\n    @Override\n    public View onCreateView(LayoutInflater inflater,\n                             ViewGroup container, Bundle savedInstanceState) {\n        setHasOptionsMenu(true);\n        setHasSyncStatusObserver(KEY, this, db());\n        return inflater.inflate(R.layout.common_listview, container, false);\n    }\n\n    @Override\n    public void onViewCreated(View view, Bundle savedInstanceState) {\n        super.onViewCreated(view, savedInstanceState);\n        setHasSwipeRefreshView(view, R.id.swipe_container, this);\n        parent().setOnBackPressListener(this);\n        mView = view;\n        mPartnersList = (ListView) view.findViewById(R.id.listview);\n        mPartnersList.setFastScrollEnabled(true);\n        mPartnersList.setFastScrollAlwaysVisible(true);\n        mAdapter = new OCursorListAdapter(getActivity(), null, R.layout.customer_row_item);\n        mAdapter.setHasSectionIndexers(true, \"name\");\n        mAdapter.setOnViewBindListener(this);\n        mPartnersList.setAdapter(mAdapter);\n        mAdapter.handleItemClickListener(mPartnersList, this);\n        setHasFloatingButton(view, R.id.fabButton, mPartnersList, this);\n        getLoaderManager().initLoader(0, null, this);\n    }\n\n    @Override\n    public void onViewBind(View view, Cursor cursor, ODataRow row) {\n        Bitmap img;\n        if (row.getString(\"image_small\").equals(\"false\")) {\n            img = BitmapUtils.getAlphabetImage(getActivity(), row.getString(\"name\"));\n        } else {\n            img = BitmapUtils.getBitmapImage(getActivity(), row.getString(\"image_small\"));\n        }\n        OControls.setImage(view, R.id.image_small, img);\n        OControls.setText(view, R.id.name, row.getString(\"name\"));\n        OControls.setText(view, R.id.company_name, (row.getString(\"company_name\").equals(\"false\"))\n                ? \"\" : row.getString(\"company_name\"));\n        OControls.setText(view, R.id.email, (row.getString(\"email\").equals(\"false\") ? \" \"\n                : row.getString(\"email\")));\n    }\n\n    @Override\n    public Loader<Cursor> onCreateLoader(int id, Bundle data) {\n        String where = \"\";\n        List<String> args = new ArrayList<>();\n        if (mCurFilter != null) {\n            where = \" name like ? \";\n            args.add(mCurFilter + \"%\");\n        }\n        String selection = (args.size() > 0) ? where : null;\n        String[] selectionArgs = (args.size() > 0) ? args.toArray(new String[args.size()]) : null;\n        return new CursorLoader(getActivity(), ((ResPartner) db()).liveSearchURI(),\n                null, selection, selectionArgs, \"name\");\n    }\n\n    @Override\n    public void onLoadFinished(Loader<Cursor> loader, Cursor data) {\n        mAdapter.changeCursor(data);\n        if (data.getCount() > 0) {\n            new Handler().postDelayed(new Runnable() {\n                @Override\n                public void run() {\n                    OControls.setGone(mView, R.id.loadingProgress);\n                    OControls.setVisible(mView, R.id.swipe_container);\n                    OControls.setGone(mView, R.id.customer_no_items);\n                    setHasSwipeRefreshView(mView, R.id.swipe_container, Customers.this);\n                }\n            }, 500);\n        } else {\n            new Handler().postDelayed(new Runnable() {\n                @Override\n                public void run() {\n                    OControls.setGone(mView, R.id.loadingProgress);\n                    OControls.setGone(mView, R.id.swipe_container);\n                    OControls.setVisible(mView, R.id.customer_no_items);\n                    setHasSwipeRefreshView(mView, R.id.customer_no_items, Customers.this);\n                    OControls.setImage(mView, R.id.icon, R.drawable.ic_action_customers);\n                    OControls.setText(mView, R.id.title, _s(R.string.label_no_customer_found));\n                    OControls.setText(mView, R.id.subTitle, \"\");\n                }\n            }, 500);\n            if (db().isEmptyTable() && !syncRequested) {\n                syncRequested = true;\n                onRefresh();\n            }\n        }\n    }\n\n    @Override\n    public void onLoaderReset(Loader<Cursor> loader) {\n        mAdapter.changeCursor(null);\n    }\n\n    @Override\n    public void onItemClick(View view, final int position) {\n        ODataRow row = OCursorUtils.toDatarow((Cursor) mAdapter.getItem(position));\n        if (row.getInt(OColumn.ROW_ID) == 0) {\n            CustomerQuickCreater customerQuickCreater =\n                    new CustomerQuickCreater(new OnLiveSearchRecordCreateListener() {\n                        @Override\n                        public void recordCreated(ODataRow row) {\n                            Cursor cr = getActivity().getContentResolver()\n                                    .query(db().uri(), null, \"id = ?\", new String[]{row.getString(\"id\")}\n                                            , null);\n                            cr.moveToFirst();\n                            showSheet(cr);\n                        }\n                    });\n            customerQuickCreater.execute(row);\n        } else\n            showSheet((Cursor) mAdapter.getItem(position));\n    }\n\n    private void showSheet(Cursor data) {\n        if (mSheet != null) {\n            mSheet.dismiss();\n        }\n        BottomSheet.Builder builder = new BottomSheet.Builder(getActivity());\n        builder.listener(this);\n        builder.setIconColor(_c(R.color.body_text_2));\n        builder.setTextColor(_c(R.color.body_text_2));\n        builder.setData(data);\n        builder.actionListener(this);\n        builder.setOnSheetMenuCreateListener(this);\n        builder.setActionIcon(R.drawable.ic_action_edit);\n        builder.title(data.getString(data.getColumnIndex(\"name\")));\n        builder.menu(R.menu.menu_sheet_customer);\n        mSheet = builder.create();\n        mSheet.show();\n    }\n\n    @Override\n    public void onSheetMenuCreate(Menu menu, Object o) {\n        ODataRow row = OCursorUtils.toDatarow((Cursor) o);\n        String address = ((ResPartner) db()).getAddress(row);\n        if (address.equals(\"false\") || TextUtils.isEmpty(address)) {\n            menu.findItem(R.id.menu_customer_location).setVisible(false);\n        }\n        String contact = ResPartner.getContact(getActivity(), row.getInt(OColumn.ROW_ID));\n        if (contact.equals(\"false\")) {\n            menu.findItem(R.id.menu_customer_call).setVisible(false);\n        }\n        if (row.getString(\"email\").equals(\"false\")) {\n            menu.findItem(R.id.menu_customer_send_message).setVisible(false);\n        }\n    }\n\n    @Override\n    public Class<ResPartner> database() {\n        return ResPartner.class;\n    }\n\n    @Override\n    public List<ODrawerItem> drawerMenus(Context context) {\n        List<ODrawerItem> items = new ArrayList<ODrawerItem>();\n        items.add(new ODrawerItem(KEY).setTitle(\"Customers\")\n                .setIcon(R.drawable.ic_action_customers)\n                .setInstance(new Customers()));\n        return items;\n    }\n\n\n    @Override\n    public void onStatusChange(Boolean refreshing) {\n        // Sync Status\n        getLoaderManager().restartLoader(0, null, this);\n    }\n\n\n    @Override\n    public void onRefresh() {\n        if (inNetwork()) {\n            parent().sync().requestSync(ResPartner.AUTHORITY);\n            setSwipeRefreshing(true);\n        } else {\n            hideRefreshingProgress();\n            Toast.makeText(getActivity(), _s(R.string.toast_network_required), Toast.LENGTH_LONG)\n                    .show();\n        }\n    }\n\n    @Override\n    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {\n        super.onCreateOptionsMenu(menu, inflater);\n        menu.clear();\n        inflater.inflate(R.menu.menu_partners, menu);\n        setHasSearchView(this, menu, R.id.menu_partner_search);\n    }\n\n    @Override\n    public boolean onOptionsItemSelected(MenuItem item) {\n        switch (item.getItemId()) {\n        }\n        return super.onOptionsItemSelected(item);\n    }\n\n    @Override\n    public boolean onSearchViewTextChange(String newFilter) {\n        mCurFilter = newFilter;\n        getLoaderManager().restartLoader(0, null, this);\n        return true;\n    }\n\n    @Override\n    public void onSearchViewClose() {\n        // nothing to do\n    }\n\n    @Override\n    public void onClick(View v) {\n        switch (v.getId()) {\n            case R.id.fabButton:\n                loadActivity(null);\n                break;\n        }\n    }\n\n    @Override\n    public void onItemClick(BottomSheet sheet, final MenuItem menu, final Object extras) {\n        sheet.dismiss();\n        ODataRow row = OCursorUtils.toDatarow((Cursor) extras);\n        switch (menu.getItemId()) {\n            case R.id.menu_customer_opportunity:\n                requestOpportunity(row.getInt(OColumn.ROW_ID), row.getString(\"name\"));\n                break;\n            case R.id.menu_customer_leads:\n                requestLeads(Type.Leads, row.getInt(OColumn.ROW_ID), row.getString(\"name\"));\n                break;\n            case R.id.menu_customer_location:\n                String address = ((ResPartner) db()).getAddress(OCursorUtils.toDatarow((Cursor) extras));\n                if (!address.equals(\"false\") && !TextUtils.isEmpty(address))\n                    IntentUtils.redirectToMap(getActivity(), address);\n                else\n                    Toast.makeText(getActivity(), _s(R.string.label_no_location_found), Toast.LENGTH_LONG).show();\n                break;\n            case R.id.menu_customer_call:\n                String contact = ResPartner.getContact(getActivity(), row.getInt(OColumn.ROW_ID));\n                if (!contact.equals(\"false\"))\n                    IntentUtils.requestCall(getActivity(), contact);\n                else\n                    Toast.makeText(getActivity(), _s(R.string.label_no_contact_found), Toast.LENGTH_LONG).show();\n                break;\n            case R.id.menu_customer_send_message:\n                if (!row.getString(\"email\").equals(\"false\"))\n                    IntentUtils.requestMessage(getActivity(), row.getString(\"email\"));\n                else\n                    Toast.makeText(getActivity(), _s(R.string.label_no_email_found), Toast.LENGTH_LONG).show();\n                break;\n            case R.id.menu_customer_schedule_call:\n                Bundle extra = row.getPrimaryBundleData();\n                extra.putInt(PhoneCallDetail.KEY_OPPORTUNITY_ID, -1);\n                extra.putBoolean(PhoneCallDetail.KEY_LOG_CALL_REQUEST, true);\n                IntentUtils.startActivity(getActivity(), PhoneCallDetail.class, extra);\n                break;\n        }\n\n    }\n\n    private void requestOpportunity(int row_id, String name) {\n        Bundle extra = new Bundle();\n        extra.putBoolean(KEY_FILTER_REQUEST, true);\n        extra.putInt(KEY_CUSTOMER_ID, row_id);\n        extra.putString(\"name\", name);\n        startFragment(new CRMOpportunitiesPager(), true, extra);\n    }\n\n    private void requestLeads(Type type, int row_id, String name) {\n        Bundle extra = new Bundle();\n        extra.putBoolean(KEY_FILTER_REQUEST, true);\n        extra.putInt(KEY_CUSTOMER_ID, row_id);\n        extra.putString(KEY_FILTER_TYPE, type.toString());\n        extra.putString(\"name\", name);\n        startFragment(new CRMLeads(), true, extra);\n    }\n\n    @Override\n    public void onItemDoubleClick(View view, int position) {\n        final ODataRow row = OCursorUtils.toDatarow((Cursor) mAdapter.getItem(position));\n        if (row.getInt(OColumn.ROW_ID) == 0) {\n            CustomerQuickCreater customerQuickCreater =\n                    new CustomerQuickCreater(new OnLiveSearchRecordCreateListener() {\n                        @Override\n                        public void recordCreated(ODataRow row) {\n                            loadActivity(row);\n                        }\n                    });\n            customerQuickCreater.execute(row);\n        } else\n            loadActivity(row);\n    }\n\n    @Override\n    public void onSheetActionClick(BottomSheet sheet, Object extras) {\n        if (extras instanceof Cursor) {\n            loadActivity(OCursorUtils.toDatarow((Cursor) extras));\n        }\n    }\n\n    private void loadActivity(ODataRow row) {\n        Bundle data = null;\n        if (row != null) {\n            data = row.getPrimaryBundleData();\n        }\n        IntentUtils.startActivity(getActivity(), CustomerDetails.class, data);\n    }\n\n    @Override\n    public boolean onBackPressed() {\n        if (mSheet != null && mSheet.isShowing()) {\n            mSheet.dismiss();\n            return false;\n        }\n        return true;\n    }\n\n\n    private class CustomerQuickCreater extends AsyncTask<ODataRow, Void, ODataRow> {\n        private ProgressDialog progressDialog;\n        private OnLiveSearchRecordCreateListener mOnLiveSearchRecordCreateListener;\n\n        public CustomerQuickCreater(OnLiveSearchRecordCreateListener listener) {\n            mOnLiveSearchRecordCreateListener = listener;\n        }\n\n        @Override\n        protected void onPreExecute() {\n            super.onPreExecute();\n            progressDialog = new ProgressDialog(getActivity());\n            progressDialog.setTitle(R.string.title_working);\n            progressDialog.setMessage(_s(R.string.title_please_wait));\n            progressDialog.setCancelable(false);\n            progressDialog.show();\n        }\n\n        @Override\n        protected ODataRow doInBackground(ODataRow... params) {\n            try {\n                Thread.sleep(500);\n                return db().quickCreateRecord(params[0]);\n            } catch (Exception e) {\n\n            }\n            return null;\n        }\n\n        @Override\n        protected void onPostExecute(ODataRow row) {\n            super.onPostExecute(row);\n            progressDialog.dismiss();\n            getLoaderManager().restartLoader(0, null, Customers.this);\n            if (mOnLiveSearchRecordCreateListener != null && row != null) {\n                mOnLiveSearchRecordCreateListener.recordCreated(row);\n            }\n        }\n    }\n\n\n    public interface OnLiveSearchRecordCreateListener {\n        public void recordCreated(ODataRow row);\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/addons/customers/providers/CustomersSyncProvider.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 2/1/15 2:25 PM\n */\npackage com.odoo.addons.customers.providers;\n\nimport android.database.Cursor;\nimport android.database.MatrixCursor;\nimport android.net.Uri;\n\nimport com.odoo.base.addons.res.ResPartner;\nimport com.odoo.core.orm.ODataRow;\nimport com.odoo.core.orm.OModel;\nimport com.odoo.core.orm.fields.OColumn;\nimport com.odoo.core.orm.provider.BaseModelProvider;\nimport com.odoo.core.support.OdooFields;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Locale;\n\nimport odoo.ODomain;\n\npublic class CustomersSyncProvider extends BaseModelProvider {\n    public static final String TAG = CustomersSyncProvider.class.getSimpleName();\n    public static final int LIVE_SEARCHABLE_CUSTOMER = 116;\n\n    @Override\n    public boolean onCreate() {\n        String path = new ResPartner(getContext(), null).getModelName().toLowerCase(Locale.getDefault());\n        matcher.addURI(authority(), path + \"/live_searchable_customer\", LIVE_SEARCHABLE_CUSTOMER);\n        return super.onCreate();\n    }\n\n    @Override\n    public void setModel(Uri uri) {\n        super.setModel(uri);\n        mModel = new ResPartner(getContext(), getUser(uri));\n    }\n\n    @Override\n    public Cursor query(Uri uri, String[] base_projection, String selection, String[] selectionArgs, String sortOrder) {\n        int match = matcher.match(uri);\n        if (match != LIVE_SEARCHABLE_CUSTOMER) {\n            return super.query(uri, base_projection, selection, selectionArgs, sortOrder);\n        }\n        ResPartner partner = new ResPartner(getContext(), null);\n        Cursor cr = super.query(partner.uri(), base_projection, selection, selectionArgs, sortOrder);\n        if (cr.getCount() <= 0) {\n            String searchName = null;\n            if (selectionArgs != null && selectionArgs.length > 0) {\n                searchName = selectionArgs[selectionArgs.length - 1];\n            }\n            if (searchName != null) {\n                List<ODataRow> records = getRecords(searchName, partner);\n                if (records.size() > 0) {\n                    List<String> keys = new ArrayList<>();\n                    keys.addAll(records.get(0).keys());\n                    keys.add(OColumn.ROW_ID);\n                    MatrixCursor cursor = new MatrixCursor(keys.toArray(new String[keys.size()]));\n                    for (ODataRow row : records) {\n                        List<Object> values = row.values();\n                        values.add(0);\n                        cursor.addRow(values);\n                    }\n                    return cursor;\n                }\n            }\n        }\n        return cr;\n    }\n\n    @Override\n    public String authority() {\n        return ResPartner.AUTHORITY;\n    }\n\n\n    public List<ODataRow> getRecords(String searchName, OModel model) {\n        List<ODataRow> items = new ArrayList<>();\n        try {\n            OdooFields fields = new OdooFields(new String[]{\"name\", \"image_small\", \"email\"});\n            ODomain domain = new ODomain();\n            domain.add(\"name\", \"=ilike\", \"%\" + searchName);\n            List<ODataRow> records = model.getServerDataHelper().searchRecords(fields, domain, 10);\n            items.addAll(records);\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return items;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/addons/customers/services/CustomerSyncService.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 2/1/15 11:07 AM\n */\npackage com.odoo.addons.customers.services;\n\nimport android.content.Context;\nimport android.os.Bundle;\n\nimport com.odoo.base.addons.res.ResPartner;\nimport com.odoo.core.service.OSyncAdapter;\nimport com.odoo.core.service.OSyncService;\nimport com.odoo.core.support.OUser;\n\nimport odoo.ODomain;\n\npublic class CustomerSyncService extends OSyncService {\n    public static final String TAG = CustomerSyncService.class.getSimpleName();\n\n    @Override\n    public OSyncAdapter getSyncAdapter(OSyncService service, Context context) {\n        return new OSyncAdapter(context, ResPartner.class, service, true);\n    }\n\n    @Override\n    public void performDataSync(OSyncAdapter adapter, Bundle extras, OUser user) {\n        if (adapter.getModel().getModelName().equals(\"res.partner\")) {\n            ODomain domain = new ODomain();\n            domain.add(\"|\");\n            domain.add(\"|\");\n            domain.add(\"opportunity_ids.user_id\", \"=\", user.getUser_id());\n            domain.add(\"sale_order_ids.user_id\", \"=\", user.getUser_id());\n            domain.add(\"id\", \"in\", adapter.getModel().getServerIds());\n            adapter.setDomain(domain);\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/addons/customers/utils/ShareUtil.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 15/1/15 4:52 PM\n */\npackage com.odoo.addons.customers.utils;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.net.Uri;\n\nimport com.odoo.core.orm.ODataRow;\nimport com.odoo.core.utils.OStorageUtils;\n\nimport java.io.File;\nimport java.io.FileWriter;\n\npublic class ShareUtil {\n    public static final String TAG = ShareUtil.class.getSimpleName();\n\n    public static void shareContact(Context context, ODataRow row, Boolean view) {\n        try {\n            File vcfFile = new File(OStorageUtils.getDirectoryPath(\"file\"), row.getString(\"name\") + \".vcf\");\n            FileWriter fw = new FileWriter(vcfFile);\n            fw.write(\"BEGIN:VCARD\\r\\n\");\n            fw.write(\"VERSION:3.0\\r\\n\");\n            fw.write(\"N:\" + row.getString(\"name\") + \";\\r\\n\");\n            fw.write(\"FN:\" + row.getString(\"name\") + \"\\r\\n\");\n            if (row.get(\"parent_id\") instanceof Integer) {\n                fw.write(\"ORG:\" + row.getM2ORecord(\"parent_id\").browse().getString(\"name\") + \"\\r\\n\");\n            }\n            if (!row.getString(\"phone\").equals(\"false\"))\n                fw.write(\"TEL;TYPE=WORK,VOICE:\" + row.getString(\"phone\") + \"\\r\\n\");\n            if (!row.getString(\"mobile\").equals(\"false\"))\n                fw.write(\"TEL;TYPE=HOME,VOICE:\" + row.getString(\"mobile\") + \"\\r\\n\");\n            String country = \"\";\n            if (row.get(\"country_id\") instanceof Integer) {\n                country = row.getM2ORecord(\"country_id\").browse().getString(\"name\");\n            }\n//            if (!row.getString(\"street\").equals(\"false\") && !row.getString(\"street\").equals(\"\")) {\n//            fw.write(\"ADR;TYPE=WORK:;;\" + row.getString(\"street\"));\n            fw.write(\"ADR;TYPE=WORK:;;\" + row.getString(\"street\") + \" \" + row.getString(\"street2\") + \";\" +\n                    row.getString(\"city\") + \";\" + row.getString(\"zip\") + \";\" + country + \"\\r\\n\");\n//            }\n//            if (!row.getString(\"street2\").equals(\"false\") && !row.getString(\"street2\").equals(\"\"))\n//                fw.write(\"ADR;TYPE=WORK:;;\" + \" \" + row.getString(\"street2\"));\n//            if (!row.getString(\"city\").equals(\"false\") && !row.getString(\"city\").equals(\"\"))\n//                fw.write(\"ADR;TYPE=WORK:;;\" + \" \" + row.getString(\"city\"));\n//            if (!row.getString(\"zip\").equals(\"false\") && !row.getString(\"zip\").equals(\"\"))\n//                fw.write(\"ADR;TYPE=WORK:;;\" + \" \" + row.getString(\"zip\") + \";\" + country);\n\n//            if (!row.getString(\"email\").equals(\"false\") && !row.getString(\"email\").equals(\"\"))\n            fw.write(\"EMAIL;TYPE=PREF,INTERNET:\" + row.getString(\"email\") + \"\\r\\n\");\n            fw.write(\"END:VCARD\\r\\n\");\n            fw.close();\n\n            Intent i = new Intent();\n            if (view) {\n                i.setAction(Intent.ACTION_SEND);\n                i.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(vcfFile));\n                i.setType(\"text/x-vcard\");\n            } else {\n                i.setAction(Intent.ACTION_VIEW);\n                i.setDataAndType(Uri.fromFile(vcfFile), \"text/x-vcard\");\n            }\n            context.startActivity(i);\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/addons/phonecall/PhoneCallDetail.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 13/1/15 4:55 PM\n */\npackage com.odoo.addons.phonecall;\n\nimport android.os.Bundle;\nimport android.os.Handler;\nimport android.support.v7.app.ActionBar;\nimport android.support.v7.app.ActionBarActivity;\nimport android.util.Log;\nimport android.view.Menu;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.widget.TextView;\nimport android.widget.Toast;\n\nimport com.odoo.addons.calendar.utils.ReminderDialog;\nimport com.odoo.addons.crm.models.CRMLead;\nimport com.odoo.addons.phonecall.features.receivers.PhoneStateReceiver;\nimport com.odoo.addons.phonecall.models.CRMPhoneCalls;\nimport com.odoo.addons.phonecall.models.CRMPhoneCallsCategory;\nimport com.odoo.base.addons.res.ResPartner;\nimport com.odoo.base.addons.res.ResUsers;\nimport com.odoo.core.orm.ODataRow;\nimport com.odoo.core.orm.OValues;\nimport com.odoo.core.orm.fields.OColumn;\nimport com.odoo.core.utils.IntentUtils;\nimport com.odoo.core.utils.OActionBarUtils;\nimport com.odoo.core.utils.ODateUtils;\nimport com.odoo.core.utils.OResource;\nimport com.odoo.core.utils.notification.ONotificationBuilder;\nimport com.odoo.core.utils.reminder.ReminderReceiver;\nimport com.odoo.core.utils.reminder.ReminderUtils;\nimport com.odoo.R;\n\nimport java.util.Date;\n\nimport odoo.controls.OField;\nimport odoo.controls.OForm;\n\npublic class PhoneCallDetail extends ActionBarActivity implements OField.\n        IOnFieldValueChangeListener, ReminderDialog.OnReminderValueSelectListener,\n        View.OnClickListener {\n    public static final String TAG = PhoneCallDetail.class.getSimpleName();\n    public static final String KEY_LOG_CALL_REQUEST = \"key_log_call_request\";\n    public static final String KEY_PHONE_NUMBER = \"key_phone_number\";\n    public static final String KEY_OPPORTUNITY_ID = \"key_opportunity_id\";\n    private ActionBar actionBar;\n    private Bundle extra;\n    private OForm mForm;\n    private ODataRow record;\n    private CRMPhoneCalls crmPhoneCalls;\n    private OField phoneCallDate, opportunity_id;\n    private String logType = \"done\", type = null;\n    private Boolean updateOpportunity = false;\n    private CRMLead crmLead = null;\n    private OForm opportunity_action_form;\n    private ReminderDialog.ReminderItem mReminder;\n    OValues values = null;\n    public static final String KEY_RESCHEDULE = \"key_reschedule\";\n\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.crm_phonecall_detail);\n        crmPhoneCalls = new CRMPhoneCalls(this, null);\n        OActionBarUtils.setActionBar(this, true);\n        actionBar = getSupportActionBar();\n        actionBar.setTitle(R.string.label_log_call);\n        extra = getIntent().getExtras();\n        crmLead = new CRMLead(this, null);\n        mReminder = ReminderDialog.getDefault(this, false);\n        init();\n    }\n\n    private void init() {\n        mForm = (OForm) findViewById(R.id.phoneLogForm);\n        opportunity_action_form = (OForm) findViewById(R.id.opportunity_action_form);\n        phoneCallDate = (OField) findViewById(R.id.phoneCallDate);\n        opportunity_id = (OField) findViewById(R.id.opportunity_id);\n        opportunity_id.setOnValueChangeListener(this);\n        phoneCallDate.setOnValueChangeListener(this);\n        findViewById(R.id.reminderForPhoneCall).setOnClickListener(this);\n        mForm.setEditable(true);\n        if (extra != null) {\n            String action = getIntent().getAction();\n            if (!extra.containsKey(KEY_LOG_CALL_REQUEST)) {\n\n                if (extra.containsKey(\"opp_id\")) {\n                    ODataRow opp_rec = new ODataRow();\n                    opp_rec.put(\"opportunity_id\", extra.getInt(\"opp_id\"));\n                    boolean partner_edit = true;\n                    if (!crmLead.browse(extra.getInt(\"opp_id\")).getString(\"partner_id\").\n                            equals(\"false\")) {\n                        opp_rec.put(\"partner_id\", crmLead.browse(extra.getInt(\"opp_id\")).\n                                getInt(\"partner_id\"));\n                        partner_edit = false;\n                    }\n                    mForm.initForm(opp_rec);\n                    ((OField) mForm.findViewById(R.id.partner_id)).setEditable(partner_edit);\n                    ((OField) mForm.findViewById(R.id.opportunity_id)).setEditable(false);\n                    return;\n                }\n\n                if (action != null) {\n                    if (action.equals(ReminderReceiver.ACTION_PHONE_CALL_REMINDER_CALLBACK)) {\n                        String contact = extra.getString(\"contact\");\n                        if (!contact.equals(\"false\")) {\n                            IntentUtils.requestCall(this, contact);\n                        } else {\n                            Toast.makeText(this, R.string.label_no_contact_found, Toast.LENGTH_LONG).show();\n                        }\n                        finish();\n                    }\n                    if (action.equals(ReminderReceiver.ACTION_PHONE_CALL_REMINDER_DONE)) {\n                        OValues values = new OValues();\n                        values.put(\"is_done\", \"1\");\n                        values.put(\"state\", \"done\");\n                        crmPhoneCalls.update(extra.getInt(OColumn.ROW_ID), values);\n                        crmPhoneCalls.setReminder(extra.getInt(OColumn.ROW_ID));\n                        Toast.makeText(this, R.string.toast_phone_call_marked_done, Toast.LENGTH_LONG).show();\n                    }\n                    ONotificationBuilder.cancelNotification(this, extra.getInt(OColumn.ROW_ID));\n                }\n                // Record request\n                record = crmPhoneCalls.browse(extra.getInt(OColumn.ROW_ID));\n                mForm.initForm(record);\n            } else {\n                // Logging new call\n                if (action != null) {\n                    ONotificationBuilder.cancelNotification(this, extra.getInt(\"notification_id\"));\n                    if (action.equals(PhoneStateReceiver.ACTION_CALL_BACK)) {\n                        String contactNumber = extra.getString(KEY_PHONE_NUMBER);\n                        IntentUtils.requestCall(this, contactNumber);\n                        finish();\n                    }\n                }\n                ODataRow data_record = new ODataRow();\n                data_record.put(\"partner_id\", extra.getInt(OColumn.ROW_ID));\n                data_record.put(\"partner_phone\", extra.getString(KEY_PHONE_NUMBER));\n                int opp_id = extra.getInt(KEY_OPPORTUNITY_ID);\n                data_record.put(\"opportunity_id\", opp_id);\n                data_record.put(\"date\", ODateUtils.getCurrentDateWithHour(1));\n                if (extra.containsKey(PhoneStateReceiver.KEY_DURATION_START)) {\n                    long start_time = Long.parseLong(extra.getString(\n                            PhoneStateReceiver.KEY_DURATION_START));\n                    long end_time = Long.parseLong(extra.getString(\n                            PhoneStateReceiver.KEY_DURATION_END));\n                    long duration = (end_time - start_time);\n                    data_record.put(\"duration\", ODateUtils.durationToFloat(duration));\n                }\n                CRMPhoneCallsCategory.Type bound = CRMPhoneCallsCategory.Type.Inbound;\n                if (!extra.getBoolean(\"in_bound\", false)) {\n                    bound = CRMPhoneCallsCategory.Type.OutBound;\n                }\n                data_record.put(\"categ_id\", CRMPhoneCallsCategory.getId(this, bound));\n                mForm.initForm(data_record);\n            }\n        } else {\n            mForm.initForm(null);\n        }\n        String action = getIntent().getAction();\n        if (action != null && (action.equals(ReminderReceiver.ACTION_EVENT_REMINDER_DONE) ||\n                action.equals(ReminderReceiver.ACTION_EVENT_REMINDER_RE_SCHEDULE))) {\n            ONotificationBuilder.cancelNotification(this, getIntent().getExtras().\n                    getInt(OColumn.ROW_ID));\n            if (action.equals(ReminderReceiver.ACTION_EVENT_REMINDER_DONE)) {\n                int row_id = getIntent().getExtras().getInt(OColumn.ROW_ID);\n                OValues values = new OValues();\n                values.put(\"is_done\", 1);\n                crmPhoneCalls.update(row_id, values);\n                Toast.makeText(this, R.string.toast_event_marked_done, Toast.LENGTH_LONG).show();\n                extra.remove(KEY_RESCHEDULE);\n            }\n        }\n\n        if (extra != null && extra.containsKey(KEY_RESCHEDULE)) {\n            new Handler().postDelayed(new Runnable() {\n                @Override\n                public void run() {\n                    onClick(findViewById(R.id.reminderForEvent));\n                }\n            }, 500);\n        }\n    }\n\n    @Override\n    public boolean onCreateOptionsMenu(Menu menu) {\n        getMenuInflater().inflate(R.menu.menu_phonecall_detail, menu);\n        return true;\n    }\n\n    @Override\n    public boolean onOptionsItemSelected(MenuItem item) {\n        switch (item.getItemId()) {\n            case android.R.id.home:\n                finish();\n                break;\n            case R.id.menu_phonecall_save:\n                values = mForm.getValues();\n                if (values != null) {\n                    values.put(\"user_id\", ResUsers.myId(this));\n                    ResPartner partner = new ResPartner(this, null);\n                    ODataRow row = partner.browse(values.getInt(\"partner_id\"));\n                    values.put(\"customer_name\", row.getString(\"name\"));\n                    ODataRow lead = crmLead.browse(values.getInt(\"opportunity_id\"));\n                    values.put(\"lead_name\", \"\");\n                    if (lead != null) {\n                        values.put(\"lead_name\", lead.getString(\"name\"));\n                    }\n                    if (updateOpportunity) {\n                        OValues opp_values = opportunity_action_form.getValues();\n                        if (opp_values != null) {\n                            crmLead.update(lead.getInt(OColumn.ROW_ID), opp_values);\n                            crmLead.setReminder(lead.getInt(OColumn.ROW_ID));\n                        }\n                    }\n                    values.put(\"call_type\", \"false\");\n                    CRMPhoneCallsCategory category = new CRMPhoneCallsCategory(this, null);\n                    ODataRow categ_id = category.browse(values.getInt(\"categ_id\"));\n                    if (categ_id != null) {\n                        values.put(\"call_type\", categ_id.getString(\"name\"));\n                    }\n                    values.put(\"state\", logType);\n                    if (extra == null || extra.containsKey(\"opp_id\")\n                            || extra.containsKey(KEY_LOG_CALL_REQUEST) ||\n                            extra.containsKey(\"call_id\")) {\n                        int row_id = crmPhoneCalls.insert(values);\n                        extra = new Bundle();\n                        extra.putInt(OColumn.ROW_ID, row_id);\n                        Toast.makeText(this, type + \" \" + values.getString(\"name\"),\n                                Toast.LENGTH_LONG).show();\n                    } else {\n                        crmPhoneCalls.update(extra.getInt(OColumn.ROW_ID), values);\n                        crmPhoneCalls.setReminder(extra.getInt(OColumn.ROW_ID));\n                        Toast.makeText(this, \"Updated \" + type + \" \" + values.getString(\"name\"),\n                                Toast.LENGTH_LONG).show();\n                    }\n                    if (type.equals(OResource.string(this, R.string.label_scheduled_call))) {\n                        setTimer();\n                    }\n                    finish();\n                }\n                break;\n        }\n        return super.onOptionsItemSelected(item);\n    }\n\n    private void setTimer() {\n        Date now = new Date();\n        String format = ODateUtils.DEFAULT_FORMAT;\n        Date date_start = ODateUtils.createDateObject(values.getString(\"date\"),\n                format, false);\n        Date reminderDate = null;\n        int row_id = extra.getInt(OColumn.ROW_ID);\n        if (now.compareTo(date_start) < 0) {\n            values.put(\"has_reminder\", \"true\");\n            reminderDate = ReminderDialog.getReminderDateTime(values.getString(\"date\"),\n                    false, mReminder);\n            if (reminderDate != null) {\n                values.put(\"reminder_datetime\", ODateUtils.getDate(reminderDate,\n                        ODateUtils.DEFAULT_FORMAT));\n            }\n        }\n        Bundle extra = new Bundle();\n        extra.putInt(OColumn.ROW_ID, row_id);\n        extra.putString(ReminderUtils.KEY_REMINDER_TYPE, \"phonecall\");\n        if (reminderDate != null) {\n            if (ReminderUtils.get(getApplicationContext()).resetReminder(reminderDate, extra)) {\n                Log.i(TAG, \"Reminder added.\");\n            }\n        }\n    }\n\n    @Override\n    public void onFieldValueChange(OField field, Object value) {\n        if (field.getFieldName().equals(\"opportunity_id\")) {\n            ODataRow lead = (ODataRow) value;\n            updateOpportunity = false;\n            if (!lead.getString(\"type\").equals(\"lead\")) {\n                updateOpportunity = true;\n                opportunity_action_form.loadChatter(false);\n                \n                opportunity_action_form.setEditable(true);\n                opportunity_action_form.initForm(lead);\n            }\n            findViewById(R.id.opportunity_action_container).setVisibility(\n                    (updateOpportunity) ? View.VISIBLE : View.GONE);\n        } else {\n            if (!value.toString().equals(\"now()\")) {\n                Date selectedDate = ODateUtils.createDateObject(value.toString(),\n                        ODateUtils.DEFAULT_FORMAT, false);\n                Date now = new Date();\n                if (now.compareTo(selectedDate) >= 0) {\n                    actionBar.setTitle(R.string.label_log_call);\n                    type = OResource.string(this, R.string.label_logged_call);\n                    logType = \"done\";\n                    findViewById(R.id.reminderForPhoneCall).setVisibility(View.GONE);\n                } else {\n                    findViewById(R.id.reminderForPhoneCall).setVisibility(View.VISIBLE);\n                    logType = \"open\";\n                    type = OResource.string(this, R.string.label_scheduled_call);\n                    actionBar.setTitle(R.string.label_schedule_call);\n                }\n            }\n        }\n    }\n\n    @Override\n    public void onClick(View v) {\n        switch (v.getId()) {\n            case R.id.reminderForPhoneCall:\n                ReminderDialog dialog = new ReminderDialog(this, ReminderDialog.ReminderType.TimeBasedEvent);\n                dialog.setOnReminderValueSelectListener(this);\n                dialog.show();\n                break;\n        }\n\n    }\n\n    @Override\n    public void onReminderItemSelect(ReminderDialog.ReminderItem value) {\n        ((TextView) findViewById(R.id.reminderTypeName)).setText(value.getTitle());\n        mReminder = value;\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/addons/phonecall/PhoneCalls.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 13/1/15 11:19 AM\n */\npackage com.odoo.addons.phonecall;\n\nimport android.content.Context;\nimport android.database.Cursor;\nimport android.os.Bundle;\nimport android.os.Handler;\nimport android.support.annotation.Nullable;\nimport android.support.v4.app.LoaderManager;\nimport android.support.v4.content.CursorLoader;\nimport android.support.v4.content.Loader;\nimport android.support.v4.widget.SwipeRefreshLayout;\nimport android.view.LayoutInflater;\nimport android.view.Menu;\nimport android.view.MenuInflater;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.ListView;\nimport android.widget.Toast;\n\nimport com.odoo.R;\nimport com.odoo.addons.phonecall.models.CRMPhoneCalls;\nimport com.odoo.base.addons.res.ResPartner;\nimport com.odoo.core.orm.ODataRow;\nimport com.odoo.core.orm.OValues;\nimport com.odoo.core.orm.fields.OColumn;\nimport com.odoo.core.support.addons.fragment.BaseFragment;\nimport com.odoo.core.support.addons.fragment.IOnSearchViewChangeListener;\nimport com.odoo.core.support.addons.fragment.ISyncStatusObserverListener;\nimport com.odoo.core.support.drawer.ODrawerItem;\nimport com.odoo.core.support.list.IOnItemClickListener;\nimport com.odoo.core.support.list.OCursorListAdapter;\nimport com.odoo.core.utils.IntentUtils;\nimport com.odoo.core.utils.OControls;\nimport com.odoo.core.utils.OCursorUtils;\nimport com.odoo.core.utils.ODateUtils;\nimport com.odoo.core.utils.OResource;\nimport com.odoo.core.utils.dialog.OChoiceDialog;\nimport com.odoo.core.utils.sys.IOnBackPressListener;\nimport com.odoo.widgets.bottomsheet.BottomSheet;\nimport com.odoo.widgets.bottomsheet.BottomSheetListeners;\nimport com.odoo.widgets.snackbar.SnackBar;\nimport com.odoo.widgets.snackbar.SnackbarBuilder;\nimport com.odoo.widgets.snackbar.listeners.EventListener;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n\npublic class PhoneCalls extends BaseFragment implements\n        OCursorListAdapter.OnViewBindListener, LoaderManager.LoaderCallbacks<Cursor>,\n        SwipeRefreshLayout.OnRefreshListener, IOnSearchViewChangeListener,\n        View.OnClickListener, ISyncStatusObserverListener,\n        BottomSheetListeners.OnSheetItemClickListener, BottomSheetListeners.\n        OnSheetActionClickListener,\n        BottomSheetListeners.OnSheetMenuCreateListener, IOnItemClickListener, IOnBackPressListener, EventListener {\n    public static final String TAG = PhoneCalls.class.getSimpleName();\n\n    private View mView;\n    private ListView mList;\n    private OCursorListAdapter mAdapter;\n    private String mFilter = null;\n    private boolean syncRequested = false;\n    private BottomSheet mSheet = null;\n\n\n    public enum Type {\n        Logged, Scheduled\n    }\n\n    private Type mType = Type.Logged;\n\n    @Override\n    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,\n                             @Nullable Bundle savedInstanceState) {\n        setHasOptionsMenu(true);\n        return inflater.inflate(R.layout.common_listview, container, false);\n    }\n\n    @Override\n    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {\n        super.onViewCreated(view, savedInstanceState);\n        mView = view;\n        mType = Type.valueOf(getArguments().getString(\"type\"));\n        setHasSwipeRefreshView(mView, R.id.swipe_container, this);\n        initAdapter();\n    }\n\n    private void initAdapter() {\n        mList = (ListView) mView.findViewById(R.id.listview);\n        mAdapter = new OCursorListAdapter(getActivity(), null, R.layout.phonecall_item);\n        mAdapter.setOnViewBindListener(this);\n        mList.setAdapter(mAdapter);\n        parent().setOnBackPressListener(this);\n        setHasFloatingButton(mView, R.id.fabButton, mList, this);\n        setHasSyncStatusObserver(TAG, this, db());\n        mAdapter.handleItemClickListener(mList, this);\n        getLoaderManager().initLoader(0, null, this);\n    }\n\n    @Override\n    public void onViewBind(View view, Cursor cursor, ODataRow row) {\n        OControls.setText(view, R.id.name, row.getString(\"name\"));\n        String date = ODateUtils.convertToDefault(row.getString(\"date\"),\n                ODateUtils.DEFAULT_FORMAT, \"MMM, dd hh:mm a\");\n        OControls.setText(view, R.id.date, date);\n        OControls.setText(view, R.id.state, db().getLabel(\"state\", row.getString(\"state\")));\n        if (!row.getString(\"description\").equals(\"false\")) {\n            OControls.setVisible(view, R.id.description);\n            OControls.setText(view, R.id.description, row.getString(\"description\"));\n        } else {\n            OControls.setGone(view, R.id.description);\n        }\n        if (!row.getString(\"customer_name\").equals(\"\")) {\n            OControls.setVisible(view, R.id.customer_name);\n            OControls.setText(view, R.id.customer_name, row.getString(\"customer_name\"));\n        } else {\n            OControls.setGone(view, R.id.customer_name);\n        }\n        if (row.getString(\"call_type\").equals(\"false\")) {\n            OControls.setGone(view, R.id.call_type_icon);\n        } else {\n            OControls.setVisible(view, R.id.call_type_icon);\n            if (row.getString(\"call_type\").equals(\"Inbound\")) {\n                OControls.setImage(view, R.id.call_type_icon, R.drawable.ic_action_call_inbound);\n            } else {\n                OControls.setImage(view, R.id.call_type_icon, R.drawable.ic_action_call_outbound);\n            }\n        }\n\n        if (row.getString(\"lead_name\").equals(\"\")) {\n            OControls.setGone(view, R.id.lead_name);\n        } else {\n            OControls.setVisible(view, R.id.lead_name);\n            OControls.setText(view, R.id.lead_name, row.getString(\"lead_name\"));\n        }\n    }\n\n    @Override\n    public Loader<Cursor> onCreateLoader(int id, Bundle data) {\n        String where;\n        List<String> args = new ArrayList<>();\n        if (mType == Type.Logged) {\n            where = \" state = ?\";\n            args.add(\"done\");\n        } else {\n            where = \" state != ?\";\n            args.add(\"done\");\n        }\n        if (mFilter != null) {\n            where += \" and name like ? or lead_name like ? or customer_name like ?\";\n            args.add(\"%\" + mFilter + \"%\");\n            args.add(\"%\" + mFilter + \"%\");\n            args.add(\"%\" + mFilter + \"%\");\n        }\n        return new CursorLoader(getActivity(), db().uri(), null, where,\n                (args.size() > 0) ? args.toArray(new String[args.size()]) : null, \"date\");\n    }\n\n    @Override\n    public void onLoadFinished(Loader<Cursor> loader, Cursor data) {\n        mAdapter.changeCursor(data);\n        if (data.getCount() > 0) {\n            new Handler().postDelayed(new Runnable() {\n                @Override\n                public void run() {\n                    OControls.setGone(mView, R.id.loadingProgress);\n                    OControls.setVisible(mView, R.id.swipe_container);\n                    OControls.setGone(mView, R.id.customer_no_items);\n                    setHasSwipeRefreshView(mView, R.id.swipe_container, PhoneCalls.this);\n                }\n            }, 500);\n        } else {\n            if (db().isEmptyTable() && !syncRequested) {\n                syncRequested = true;\n                onRefresh();\n            }\n            new Handler().postDelayed(new Runnable() {\n                @Override\n                public void run() {\n                    OControls.setGone(mView, R.id.loadingProgress);\n                    OControls.setGone(mView, R.id.swipe_container);\n                    OControls.setVisible(mView, R.id.customer_no_items);\n                    setHasSwipeRefreshView(mView, R.id.customer_no_items, PhoneCalls.this);\n                    OControls.setImage(mView, R.id.icon, R.drawable.ic_action_customers);\n                    if (mType == Type.Logged) {\n                        OControls.setText(mView, R.id.title, _s(R.string.label_no_logged_calls_found));\n                        OControls.setImage(mView, R.id.icon,R.drawable.ic_action_call_logs);\n                    } else {\n                        OControls.setText(mView, R.id.title, _s(R.string.label_no_scheduled_calls_found));\n                        OControls.setImage(mView, R.id.icon,R.drawable.ic_action_schedule_call);\n                    }\n                    OControls.setText(mView, R.id.subTitle, \"\");\n                }\n            }, 500);\n        }\n    }\n\n    @Override\n    public void onLoaderReset(Loader<Cursor> loader) {\n        mAdapter.changeCursor(null);\n    }\n\n    @Override\n    public List<ODrawerItem> drawerMenus(Context context) {\n        List<ODrawerItem> menu = new ArrayList<>();\n        menu.add(new ODrawerItem(TAG)\n                .setTitle(OResource.string(context, R.string.label_phone_calls))\n                .setGroupTitle());\n        menu.add(new ODrawerItem(TAG)\n                .setTitle(OResource.string(context, R.string.label_logged_calls))\n                .setIcon(R.drawable.ic_action_call_logs)\n                .setExtra(extra(Type.Logged))\n                .setInstance(new PhoneCalls()));\n        menu.add(new ODrawerItem(TAG)\n                .setTitle(OResource.string(context, R.string.label_scheduled_calls))\n                .setIcon(R.drawable.ic_action_schedule_call)\n                .setExtra(extra(Type.Scheduled))\n                .setInstance(new PhoneCalls()));\n        return menu;\n    }\n\n    private Bundle extra(Type type) {\n        Bundle extra = new Bundle();\n        extra.putString(\"type\", type.toString());\n        return extra;\n    }\n\n    @Override\n    public Class<CRMPhoneCalls> database() {\n        return CRMPhoneCalls.class;\n    }\n\n\n    @Override\n    public void onRefresh() {\n        if (inNetwork()) {\n            parent().sync().requestSync(CRMPhoneCalls.AUTHORITY);\n            setSwipeRefreshing(true);\n        } else {\n            hideRefreshingProgress();\n            Toast.makeText(getActivity(), _s(R.string.toast_network_required), Toast.LENGTH_LONG)\n                    .show();\n        }\n    }\n\n    @Override\n    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {\n        super.onCreateOptionsMenu(menu, inflater);\n        menu.clear();\n        inflater.inflate(R.menu.menu_phonecalls, menu);\n        setHasSearchView(this, menu, R.id.menu_phonecall_search);\n\n    }\n\n    @Override\n    public boolean onSearchViewTextChange(String newFilter) {\n        mFilter = newFilter;\n        getLoaderManager().restartLoader(0, null, this);\n        return true;\n    }\n\n    @Override\n    public void onSearchViewClose() {\n        //Nothing to do\n    }\n\n    @Override\n    public void onClick(View v) {\n        switch (v.getId()) {\n            case R.id.fabButton:\n                IntentUtils.startActivity(getActivity(), PhoneCallDetail.class, null);\n                break;\n        }\n    }\n\n    @Override\n    public void onStatusChange(Boolean refreshing) {\n        getLoaderManager().restartLoader(0, null, this);\n    }\n\n//    @Override\n//    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {\n//        ODataRow row = OCursorUtils.toDatarow((Cursor) mAdapter.getItem(position));\n//        IntentUtils.startActivity(getActivity(), PhoneCallDetail.class, row.getPrimaryBundleData());\n//    }\n\n\n    @Override\n    public void onItemClick(BottomSheet sheet, MenuItem menu, Object extras) {\n        dismissSheet(sheet);\n        actionEvent(menu, (Cursor) extras);\n\n    }\n\n    @Override\n    public void onItemDoubleClick(View view, int position) {\n        ODataRow row = OCursorUtils.toDatarow((Cursor) mAdapter.getItem(position));\n        IntentUtils.startActivity(getActivity(), PhoneCallDetail.class, row.getPrimaryBundleData());\n    }\n\n    @Override\n    public void onItemClick(View view, int position) {\n        Cursor cr = (Cursor) mAdapter.getItem(position);\n        showSheet(cr);\n    }\n\n    private void showSheet(Cursor data) {\n        if (mSheet != null) {\n            mSheet.dismiss();\n        }\n        BottomSheet.Builder builder = new BottomSheet.Builder(getActivity());\n        builder.listener(this);\n        builder.setIconColor(_c(R.color.body_text_2));\n        builder.setTextColor(_c(R.color.body_text_1));\n        builder.setData(data);\n        builder.actionListener(this);\n        builder.setActionIcon(R.drawable.ic_action_edit);\n        builder.title(data.getString(data.getColumnIndex(\"name\")));\n        builder.setOnSheetMenuCreateListener(this);\n        builder.menu(R.menu.menu_dashboard_phonecalls);\n        mSheet = builder.create();\n        mSheet.show();\n    }\n\n    private void actionEvent(MenuItem menu, Cursor cr) {\n        String is_done = cr.getString(cr.getColumnIndex(\"is_done\"));\n        final OValues values = new OValues();\n        values.put(\"_is_dirty\", \"false\"); // to ignore update on server\n        final int row_id = cr.getInt(cr.getColumnIndex(OColumn.ROW_ID));\n        values.put(\"is_done\", (is_done.equals(\"0\")) ? 1 : 0);\n        String done_label = (is_done.equals(\"0\")) ? \"done\" : \"undone\";\n        final ODataRow row = OCursorUtils.toDatarow(cr);\n        Bundle data = row.getPrimaryBundleData();\n        switch (menu.getItemId()) {\n\n            case R.id.menu_phonecall_call:\n                int partner_id = cr.getInt(cr.getColumnIndex(\"partner_id\"));\n                if (partner_id != 0) {\n                    String contact = ResPartner.getContact(getActivity(), partner_id);\n                    if (contact != null && !contact.equals(\"false\")) {\n                        IntentUtils.requestCall(getActivity(), contact);\n                    } else {\n                        Toast.makeText(getActivity(), _s(R.string.label_no_contact_found),\n                                Toast.LENGTH_LONG).show();\n                    }\n                } else {\n                    Toast.makeText(getActivity(), _s(R.string.label_no_contact_found),\n                            Toast.LENGTH_LONG).show();\n                }\n                break;\n\n            case R.id.menu_phonecall_reschedule:\n                List<String> choices = new ArrayList<>();\n                choices = new ArrayList<>();\n                choices.add(\"Re-Schedule call\");\n                choices.add(\"Schedule other call\");\n                OChoiceDialog.get(getActivity()).withOptions(choices, -1)\n                        .show(new OChoiceDialog.OnChoiceSelectListener() {\n                            @Override\n                            public void choiceSelected(int position, String value) {\n                                switch (position) {\n                                    case 0: // Re-Schedule\n                                        IntentUtils.startActivity(getActivity(), PhoneCallDetail.class,\n                                                row.getPrimaryBundleData());\n\n                                        break;\n                                    case 1: // Schedule other call\n                                        Bundle extra = row.getPrimaryBundleData();\n                                        extra.putInt(\"call_id\", row.getInt(OColumn.ROW_ID));\n                                        IntentUtils.startActivity(getActivity(), PhoneCallDetail.class,\n                                                extra);\n                                        break;\n                                }\n                            }\n                        });\n                break;\n            // All done menu\n            case R.id.menu_phonecall_all_done:\n                final CRMPhoneCalls phone_call = new CRMPhoneCalls(getActivity(), null);\n                values.put(\"state\", \"done\");\n                phone_call.update(row_id, values);\n                getLoaderManager().restartLoader(0, null, this);\n                SnackBar.get(getActivity()).text(_s(R.string.toast_phone_call_marked_done))\n                        .duration(SnackbarBuilder.SnackbarDuration.LENGTH_LONG)\n                        .withEventListener(this).show();\n                break;\n\n\n        }\n    }\n\n    private void dismissSheet(final BottomSheet sheet) {\n        new Handler().postDelayed(new Runnable() {\n\n            @Override\n            public void run() {\n                sheet.dismiss();\n            }\n        }, 100);\n    }\n\n    @Override\n    public void onShow(int i) {\n        hideFab();\n    }\n\n    @Override\n    public void onDismiss(int i) {\n        showFab();\n    }\n\n    @Override\n    public void onSheetActionClick(BottomSheet sheet, final Object extras) {\n        sheet.dismiss();\n        new Handler().postDelayed(new Runnable() {\n\n            @Override\n            public void run() {\n                Cursor cr = (Cursor) extras;\n                String data_type = cr.getString(cr.getColumnIndex(\"data_type\"));\n                int record_id = cr.getInt(cr.getColumnIndex(OColumn.ROW_ID));\n                Bundle extra = new Bundle();\n                extra.putInt(OColumn.ROW_ID, record_id);\n                IntentUtils.startActivity(getActivity(), PhoneCallDetail.class, extra);\n            }\n        }, 250);\n    }\n\n    @Override\n    public void onSheetMenuCreate(Menu menu, Object o) {\n        if (mType == Type.Logged)\n            menu.findItem(R.id.menu_phonecall_all_done).setVisible(false);\n\n    }\n\n    @Override\n    public boolean onBackPressed() {\n        if (mSheet != null && mSheet.isShowing()) {\n            mSheet.dismiss();\n            return false;\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/addons/phonecall/features/CallerWindow.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 13/1/15 6:11 PM\n */\npackage com.odoo.addons.phonecall.features;\n\nimport android.app.Activity;\nimport android.app.KeyguardManager;\nimport android.content.Context;\nimport android.graphics.Bitmap;\nimport android.graphics.PixelFormat;\nimport android.os.Handler;\nimport android.util.Log;\nimport android.view.Gravity;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.WindowManager;\n\nimport com.odoo.core.orm.ODataRow;\nimport com.odoo.core.utils.BitmapUtils;\nimport com.odoo.core.utils.OControls;\nimport com.odoo.core.utils.OPreferenceManager;\nimport com.odoo.R;\n\npublic class CallerWindow {\n    public static final String TAG = CallerWindow.class.getSimpleName();\n    public static final String KEY_CALLER_WINDOW = \"key_caller_window\";\n    private WindowManager windowManager;\n    private Context context;\n    private OPreferenceManager mPref;\n    private KeyguardManager keyguardManager;\n    private View callerView = null;\n\n    public CallerWindow(Context context) {\n        this.context = context;\n        mPref = new OPreferenceManager(context);\n        windowManager = (WindowManager) context.getSystemService(Activity.WINDOW_SERVICE);\n        keyguardManager = (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);\n        mPref.setBoolean(KEY_CALLER_WINDOW, false);\n    }\n\n    private WindowManager.LayoutParams getWindowParams() {\n        WindowManager.LayoutParams params = new WindowManager.LayoutParams(\n                WindowManager.LayoutParams.MATCH_PARENT,\n                WindowManager.LayoutParams.WRAP_CONTENT,\n                WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,\n                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE\n                        | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL\n                        | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,\n                PixelFormat.TRANSLUCENT);\n        params.gravity = Gravity.TOP;\n        return params;\n    }\n\n    private View buildView() {\n        View view = LayoutInflater.from(context).inflate(R.layout.crm_caller_window_layout,\n                null);\n\n        return view;\n    }\n\n    public boolean inIdleMode() {\n        return keyguardManager.inKeyguardRestrictedInputMode();\n    }\n\n    public boolean isLollipop() {\n        return (android.os.Build.VERSION.SDK_INT > 19);\n    }\n\n    private void bindView(ODataRow row) {\n        OControls.setText(callerView, R.id.partner_name, row.getString(\"name\"));\n        OControls.setText(callerView, R.id.company_name, row.getString(\"company_name\"));\n        Bitmap bmp;\n        if (row.getString(\"image_small\").equals(\"false\")) {\n            bmp = BitmapUtils.getAlphabetImage(context, row.getString(\"name\"));\n        } else {\n            String base64;\n            if (row.getString(\"large_image\").equals(\"false\")) {\n                base64 = row.getString(\"image_small\");\n            } else {\n                base64 = row.getString(\"large_image\");\n            }\n            bmp = BitmapUtils.getBitmapImage(context, base64);\n        }\n        if (row.getString(\"lead_name\").equals(\"false\")) {\n            row.put(\"lead_name\", \"No any lead found\");\n        }\n        if (row.getString(\"probability\").equals(\"false\"))\n            row.put(\"probability\", \"\");\n        OControls.setImage(callerView, R.id.customerImage, bmp);\n        OControls.setText(callerView, R.id.leadName, row.getString(\"lead_name\"));\n        OControls.setText(callerView, R.id.oppProbability, row.getString(\"probability\"));\n        OControls.setText(callerView, R.id.partner_contact, row.getString(\"caller_contact\"));\n    }\n\n    public void show(final Boolean dialed, final ODataRow row) {\n        if (!mPref.getBoolean(KEY_CALLER_WINDOW, false)) {\n            Log.i(TAG, \"Showing caller window\");\n            mPref.setBoolean(KEY_CALLER_WINDOW, true);\n            new Handler().postDelayed(new Runnable() {\n                @Override\n                public void run() {\n                    callerView = buildView();\n                    bindView(row);\n                    WindowManager.LayoutParams params = getWindowParams();\n                    if (!dialed && !inIdleMode() && isLollipop()) {\n                        params.gravity = Gravity.BOTTOM;\n                    }\n                    windowManager.addView(callerView, params);\n                }\n            }, 1000);\n        }\n    }\n\n    public void dismiss() {\n        if (mPref.getBoolean(KEY_CALLER_WINDOW, false)) {\n            Log.i(TAG, \"Removing caller window\");\n            mPref.setBoolean(KEY_CALLER_WINDOW, false);\n            try {\n                if (callerView != null)\n                    windowManager.removeViewImmediate(callerView);\n            } catch (Exception e) {\n                e.printStackTrace();\n            }\n        }\n    }\n\n    public boolean isShowing() {\n        return mPref.getBoolean(KEY_CALLER_WINDOW, false);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/addons/phonecall/features/CustomerFinder.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 13/1/15 6:33 PM\n */\npackage com.odoo.addons.phonecall.features;\n\nimport android.content.Context;\nimport android.os.AsyncTask;\nimport android.text.TextUtils;\nimport android.util.Log;\n\nimport com.odoo.addons.crm.models.CRMLead;\nimport com.odoo.base.addons.res.ResPartner;\nimport com.odoo.core.orm.ODataRow;\nimport com.odoo.core.orm.ServerDataHelper;\nimport com.odoo.core.orm.fields.OColumn;\nimport com.odoo.core.support.OdooFields;\n\nimport java.util.List;\n\nimport odoo.ODomain;\n\npublic class CustomerFinder {\n    public static final String TAG = CustomerFinder.class.getSimpleName();\n    private Context mContext;\n    private IOnCustomerFindListener customerFindListener;\n    private ResPartner resPartner;\n    private CustomerFinderTask customerFinderTask;\n    private Boolean dialed = false;\n\n    public CustomerFinder(Context context) {\n        mContext = context;\n        resPartner = new ResPartner(context, null);\n    }\n\n    public void findCustomer(Boolean isDialed, String callerNumber) {\n        Log.i(TAG, \"Finding customer for \" + callerNumber);\n        dialed = isDialed;\n        customerFinderTask = new CustomerFinderTask();\n        customerFinderTask.execute(callerNumber);\n    }\n\n    public void setOnCustomerFindListener(IOnCustomerFindListener listener) {\n        customerFindListener = listener;\n    }\n\n    private class CustomerFinderTask extends AsyncTask<String, Void, ODataRow> {\n        private String mContactLast2Chars = \"\";\n        private String mContactLast3Chars = \"\";\n\n\n        @Override\n        protected ODataRow doInBackground(String... params) {\n            String number = params[0].trim().replaceAll(\" \", \"\").replace(\"+\", \"\");\n            Log.d(TAG, \"Checking for number \" + number + \" in database\");\n            mContactLast2Chars = number.substring(number.length() - 2);\n            mContactLast3Chars = number.substring(number.length() - 3);\n            String where = \"phone like ? or phone like ? or mobile like ? or mobile like ?\";\n            String[] args = new String[]{\"%\" + mContactLast2Chars,\n                    \"%\" + mContactLast3Chars, \"%\" + mContactLast2Chars,\n                    \"%\" + mContactLast3Chars};\n            ODataRow partner = null;\n            for (ODataRow row : resPartner.select(null, where, args)) {\n                String partnerPhone = row.getString(\"phone\").trim().replaceAll(\" \", \"\")\n                        .replace(\"+\", \"\");\n                String partnerMobile = row.getString(\"mobile\").trim().replaceAll(\" \", \"\")\n                        .replace(\"+\", \"\");\n                if (!partnerPhone.equals(\"false\") &&\n                        (partnerPhone.contains(number) || number.contains(partnerPhone))) {\n                    partner = row;\n                    break;\n                }\n                if (!partnerMobile.equals(\"false\") &&\n                        (partnerMobile.contains(number) || number.contains(partnerMobile))) {\n                    partner = row;\n                    break;\n                }\n            }\n            if (partner == null) {\n                ServerDataHelper helper = resPartner.getServerDataHelper();\n                try {\n                    ODomain domain = new ODomain();\n                    domain.add(\"|\");\n                    domain.add(\"|\");\n                    domain.add(\"phone\", \"=like\", \"%\" + mContactLast2Chars);\n                    domain.add(\"phone\", \"=like\", \"%\" + mContactLast3Chars);\n                    domain.add(\"|\");\n                    domain.add(\"mobile\", \"=like\", \"%\" + mContactLast2Chars);\n                    domain.add(\"mobile\", \"=like\", \"%\" + mContactLast3Chars);\n                    OdooFields fields = new OdooFields(resPartner.getColumns());\n                    List<ODataRow> partners = helper.searchRecords(fields, domain, 10);\n                    if (partners.size() > 0) {\n                        for (ODataRow row : partners) {\n                            String phone = row.getString(\"phone\").trim();\n                            String mobile = row.getString(\"mobile\").trim();\n                            String contact = ((phone.equals(\"false\") || TextUtils\n                                    .isEmpty(phone)) ? mobile : phone).trim().replaceAll(\" \", \"\")\n                                    .replace(\"+\", \"\");\n                            if (number.contains(contact) || contact.contains(number)) {\n                                return resPartner.quickCreateRecord(row);\n                            }\n                        }\n                    } else {\n                        Log.i(TAG, \"No Customer found on server with number \" + number);\n                    }\n                } catch (Exception e) {\n                    e.printStackTrace();\n                }\n            } else {\n                // Finding Leads or Opportunity for customer in local\n                CRMLead crmLead = new CRMLead(mContext, null);\n                String projection[] = {\"name\", \"company_currency\", \"probability\", \"planned_revenue\", \"type\"};\n                List<ODataRow> records = crmLead.select(projection, \"partner_id = ?\",\n                        new String[]{partner.getString(OColumn.ROW_ID)}, \"type DESC\");\n                if (records.size() > 0) {\n                    ODataRow record = records.get(0);\n                    String more = \"\";\n                    if (records.size() > 1) {\n                        more = \" and \" + (records.size() - 1) + \" more...\";\n                    }\n                    partner.put(\"lead_name\", record.getString(\"name\") + \" \" + more);\n                    partner.put(\"opportunity_id\", record.getInt(OColumn.ROW_ID));\n                    if (!record.getString(\"type\").equals(\"lead\")) {\n                        partner.put(\"probability\", record.getString(\"planned_revenue\") + \" \" +\n                                record.getM2ORecord(\"company_currency\").browse().getString(\"symbol\")\n                                + \" at \" + record.getString(\"probability\") + \"%\");\n                    } else {\n                        partner.put(\"probability\", \"\");\n                    }\n                }\n            }\n            return partner;\n        }\n\n        @Override\n        protected void onPostExecute(ODataRow row) {\n            super.onPostExecute(row);\n            if (row != null) {\n                customerFindListener.onCustomerFind(dialed, row);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/addons/phonecall/features/IOnCustomerFindListener.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 13/1/15 6:34 PM\n */\npackage com.odoo.addons.phonecall.features;\n\nimport com.odoo.core.orm.ODataRow;\n\npublic interface IOnCustomerFindListener {\n    public void onCustomerFind(Boolean dialed, ODataRow row);\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/addons/phonecall/features/receivers/PhoneStateReceiver.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 13/1/15 6:12 PM\n */\npackage com.odoo.addons.phonecall.features.receivers;\n\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.telephony.PhoneStateListener;\nimport android.telephony.TelephonyManager;\nimport android.util.Log;\n\nimport com.odoo.addons.phonecall.PhoneCallDetail;\nimport com.odoo.addons.phonecall.features.CallerWindow;\nimport com.odoo.addons.phonecall.features.CustomerFinder;\nimport com.odoo.addons.phonecall.features.IOnCustomerFindListener;\nimport com.odoo.core.orm.ODataRow;\nimport com.odoo.core.support.OUser;\nimport com.odoo.core.utils.OPreferenceManager;\nimport com.odoo.core.utils.OResource;\nimport com.odoo.core.utils.notification.ONotificationBuilder;\nimport com.odoo.R;\n\nimport java.util.Date;\n\npublic class PhoneStateReceiver extends BroadcastReceiver implements IOnCustomerFindListener {\n    public static final String TAG = PhoneStateReceiver.class.getSimpleName();\n    public static final String ACTION_CALL_BACK = \"action_call_back\";\n    public static final String ACTION_CALL_SCHEDULE = \"action_call_schedule\";\n    public static final Integer REQUEST_CALL_BACK = 5567;\n    public static final Integer REQUEST_CALL_SCHEDULE = 5568;\n    public static final String KEY_RECEIVED = \"phone_state_received\";\n    public static final String KEY_RINGING = \"phone_state_ringing\";\n    public static final String KEY_OFFHOOK = \"phone_state_offhook\";\n    public static final String KEY_DURATION_START = \"key_duration_start\";\n    public static final String KEY_DURATION_END = \"key_duration_end\";\n    public static final String KEY_ACTIVITY_STARTED = \"key_activity_started\";\n    private String callerNumber = null;\n    private TelephonyManager telephonyManager;\n    private OPreferenceManager mPref;\n    private static CallerWindow callerWindow;\n    private CustomerFinder customerFinder;\n    private Context mContext;\n    private Bundle extra = null;\n\n    @Override\n    public void onReceive(Context context, Intent intent) {\n        mContext = context;\n        if (OUser.current(mContext) != null) {\n            Log.v(TAG, \"Phone state received.\");\n            mPref = new OPreferenceManager(context);\n            if (callerWindow == null)\n                callerWindow = new CallerWindow(context);\n            customerFinder = new CustomerFinder(context);\n            customerFinder.setOnCustomerFindListener(this);\n            if (mPref.getBoolean(KEY_RECEIVED, true) && !callerWindow.isShowing()) {\n                mPref.setBoolean(KEY_RECEIVED, false);\n                mPref.setBoolean(KEY_RINGING, false);\n            }\n            if (!mPref.getBoolean(KEY_RECEIVED, false)) {\n                telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);\n                Bundle bundle = intent.getExtras();\n                callerNumber = bundle.getString(TelephonyManager.EXTRA_INCOMING_NUMBER);\n                if (callerNumber != null) {\n                    telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);\n                }\n                mPref.setBoolean(KEY_RECEIVED, true);\n            }\n        }\n    }\n\n    PhoneStateListener phoneStateListener = new PhoneStateListener() {\n        @Override\n        public void onCallStateChanged(int state, String incomingNumber) {\n            super.onCallStateChanged(state, incomingNumber);\n            switch (state) {\n                case TelephonyManager.CALL_STATE_IDLE:\n                    Log.i(TAG, callerNumber + \" CALL_STATE_IDLE\");\n\n                    mPref.setBoolean(KEY_RECEIVED, false);\n                    mPref.setBoolean(KEY_RINGING, false);\n                    if (extra != null) {\n                        extra.putBoolean(\"in_bound\", mPref.getBoolean(\"in_bound\", false));\n                        extra.putString(KEY_DURATION_END, new Date().getTime() + \"\");\n                    }\n                    if (!mPref.getBoolean(KEY_OFFHOOK, false)) {\n                        showMissCallNotification(extra);\n                    } else {\n                        startLogCallActivity(extra);\n                    }\n                    if (callerWindow != null)\n                        callerWindow.dismiss();\n                    callerWindow = null;\n                    customerFinder = null;\n                    extra = null;\n                    break;\n                case TelephonyManager.CALL_STATE_OFFHOOK:\n                    Log.i(TAG, callerNumber + \" CALL_STATE_OFFHOOK\");\n                    mPref.setBoolean(KEY_OFFHOOK, true);\n                    // Call Started (received or dialed)\n                    callStarted();\n                    if (!mPref.getBoolean(KEY_RINGING, false)) {\n                        mPref.setBoolean(\"in_bound\", false);\n                        if (customerFinder != null)\n                            customerFinder.findCustomer(true, callerNumber);\n                    }\n                    break;\n                case TelephonyManager.CALL_STATE_RINGING:\n                    Log.i(TAG, callerNumber + \" CALL_STATE_RINGING\");\n                    mPref.setBoolean(KEY_RINGING, true);\n                    mPref.setBoolean(KEY_OFFHOOK, false);\n                    mPref.setBoolean(\"notified\", false);\n                    mPref.setBoolean(\"in_bound\", true);\n                    if (customerFinder != null)\n                        customerFinder.findCustomer(false, callerNumber);\n                    break;\n            }\n        }\n    };\n\n    private void showMissCallNotification(Bundle data) {\n        mPref.setBoolean(KEY_OFFHOOK, false);\n        if (data != null && !mPref.getBoolean(\"notified\", false)) {\n            mPref.setBoolean(\"notified\", true);\n            int notification_id = 55568;\n            ONotificationBuilder builder = new ONotificationBuilder(mContext, notification_id);\n            data.putInt(\"notification_id\", notification_id);\n            builder.setTitle(_s(R.string.label_missed_call_from_customer));\n            builder.setIcon(R.drawable.ic_action_user);\n            builder.setText(data.getString(\"name\"));\n            ONotificationBuilder.NotificationAction callBack =\n                    new ONotificationBuilder.NotificationAction(R.drawable.ic_action_phone,\n                            \"Call back\", REQUEST_CALL_BACK,\n                            ACTION_CALL_BACK, PhoneCallDetail.class, data);\n            builder.addAction(callBack);\n            data.putBoolean(PhoneCallDetail.KEY_LOG_CALL_REQUEST, true);\n            data.putString(PhoneCallDetail.KEY_PHONE_NUMBER, callerNumber);\n            data.putInt(PhoneCallDetail.KEY_OPPORTUNITY_ID, data.getInt(\"opportunity_id\"));\n            ONotificationBuilder.NotificationAction scheduleCall =\n                    new ONotificationBuilder.NotificationAction(R.drawable.ic_action_reschedule,\n                            \"Schedule\", REQUEST_CALL_SCHEDULE,\n                            ACTION_CALL_SCHEDULE, PhoneCallDetail.class, data);\n            builder.addAction(scheduleCall);\n            builder.allowVibrate(false);\n            builder.build().show();\n        }\n    }\n\n    public String _s(int res_id) {\n        return OResource.string(mContext, res_id);\n    }\n\n    private void startLogCallActivity(Bundle data) {\n        if (data != null && !mPref.getBoolean(KEY_ACTIVITY_STARTED, false)) {\n            mPref.setBoolean(KEY_ACTIVITY_STARTED, true);\n            Intent intent = new Intent(mContext, PhoneCallDetail.class);\n            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\n            data.putBoolean(PhoneCallDetail.KEY_LOG_CALL_REQUEST, true);\n            data.putString(PhoneCallDetail.KEY_PHONE_NUMBER, callerNumber);\n            data.putInt(PhoneCallDetail.KEY_OPPORTUNITY_ID, data.getInt(\"opportunity_id\"));\n            intent.putExtras(data);\n            mContext.startActivity(intent);\n        }\n    }\n\n    private void callStarted() {\n        if (extra != null && !extra.containsKey(KEY_DURATION_START)) {\n            extra.putString(KEY_DURATION_START, new Date().getTime() + \"\");\n        }\n    }\n\n    @Override\n    public void onCustomerFind(Boolean dialed, ODataRow row) {\n        if (row != null) {\n            extra = new Bundle();\n            extra = row.getPrimaryBundleData();\n            callStarted();\n            extra.putString(\"name\", row.getString(\"name\"));\n            int row_id = (row.getString(\"opportunity_id\").equals(\"false\")) ? -1\n                    : row.getInt(\"opportunity_id\");\n            extra.putInt(\"opportunity_id\", row_id);\n            row.put(\"caller_contact\", callerNumber);\n            if(callerWindow!=null) {\n                callerWindow.show(dialed, row);\n                mPref.setBoolean(KEY_ACTIVITY_STARTED, false);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/addons/phonecall/models/CRMPhoneCalls.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 13/1/15 11:20 AM\n */\npackage com.odoo.addons.phonecall.models;\n\nimport android.content.Context;\nimport android.net.Uri;\nimport android.os.Bundle;\n\nimport com.odoo.addons.crm.models.CRMLead;\nimport com.odoo.base.addons.res.ResPartner;\nimport com.odoo.base.addons.res.ResUsers;\nimport com.odoo.core.orm.ODataRow;\nimport com.odoo.core.orm.OModel;\nimport com.odoo.core.orm.OValues;\nimport com.odoo.core.orm.annotation.Odoo;\nimport com.odoo.core.orm.fields.OColumn;\nimport com.odoo.core.orm.fields.types.OBoolean;\nimport com.odoo.core.orm.fields.types.ODateTime;\nimport com.odoo.core.orm.fields.types.OFloat;\nimport com.odoo.core.orm.fields.types.OInteger;\nimport com.odoo.core.orm.fields.types.OSelection;\nimport com.odoo.core.orm.fields.types.OText;\nimport com.odoo.core.orm.fields.types.OVarchar;\nimport com.odoo.core.support.OUser;\nimport com.odoo.core.utils.ODateUtils;\nimport com.odoo.core.utils.reminder.ReminderUtils;\n\nimport org.json.JSONArray;\n\nimport java.util.Date;\n\nimport odoo.ODomain;\n\npublic class CRMPhoneCalls extends OModel {\n    public static final String TAG = CRMPhoneCalls.class.getSimpleName();\n    public static final String AUTHORITY = \"com.odoo.core.crm.provider.content.sync.crm_phonecall\";\n    private Context mContext;\n    OColumn user_id = new OColumn(\"Responsible\", ResUsers.class,\n            OColumn.RelationType.ManyToOne).setRequired();\n    OColumn partner_id = new OColumn(\"Contact\", ResPartner.class,\n            OColumn.RelationType.ManyToOne).setRequired();\n    OColumn description = new OColumn(\"Description\", OText.class);\n    OColumn state = new OColumn(\"status\", OSelection.class)\n            .addSelection(\"open\", \"Confirmed\")\n            .addSelection(\"cancel\", \"Cancelled\")\n            .addSelection(\"pending\", \"Pending\")\n            .addSelection(\"done\", \"Held\");\n    OColumn name = new OColumn(\"Call summary\", OVarchar.class).setRequired();\n    OColumn duration = new OColumn(\"Duration\", OFloat.class);\n    OColumn categ_id = new OColumn(\"Category\", CRMPhoneCallsCategory.class,\n            OColumn.RelationType.ManyToOne);\n    OColumn date = new OColumn(\"Date\", ODateTime.class);\n    OColumn opportunity_id = new OColumn(\"Lead/Opportunity\", CRMLead.class,\n            OColumn.RelationType.ManyToOne);\n    OColumn call_audio_file = new OColumn(\"recorded audio file\",\n            OVarchar.class).setSize(200).setLocalColumn();\n    OColumn data_type = new OColumn(\"Data type\", OVarchar.class).setSize(34)\n            .setLocalColumn().setDefaultValue(\"phone_call\");\n    OColumn is_done = new OColumn(\"Mark as Done\", OInteger.class)\n            .setLocalColumn().setDefaultValue(\"0\");\n    OColumn partner_phone = new OColumn(\"Partner Phone\", OVarchar.class).setSize(20);\n    @Odoo.Functional(depends = {\"opportunity_id\"}, store = true, method = \"storeLeadName\")\n    OColumn lead_name = new OColumn(\"Lead\", OVarchar.class).setSize(100)\n            .setLocalColumn();\n    @Odoo.Functional(depends = {\"user_id\"}, store = true, method = \"storeUserName\")\n    OColumn user_name = new OColumn(\"Username\", OVarchar.class).setSize(100)\n            .setLocalColumn();\n    @Odoo.Functional(depends = {\"partner_id\"}, store = true, method = \"storeCustomerName\")\n    OColumn customer_name = new OColumn(\"Username\", OVarchar.class).setSize(100)\n            .setLocalColumn();\n    @Odoo.Functional(depends = {\"categ_id\"}, store = true, method = \"storeCallType\")\n    OColumn call_type = new OColumn(\"Call Type\", OVarchar.class).setSize(100)\n            .setLocalColumn();\n    OColumn has_reminder = new OColumn(\"Has reminder\", OBoolean.class).setLocalColumn()\n            .setDefaultValue(\"false\");\n    OColumn reminder_datetime = new OColumn(\"Reminder type\", ODateTime.class)\n            .setDefaultValue(\"false\").setLocalColumn();\n\n    OColumn color_index = new OColumn(\"Color index\", OInteger.class).setSize(5)\n            .setLocalColumn().setDefaultValue(6);\n\n    public CRMPhoneCalls(Context context, OUser user) {\n        super(context, \"crm.phonecall\", user);\n        mContext = context;\n    }\n\n    @Override\n    public Uri uri() {\n        return buildURI(AUTHORITY);\n    }\n\n    @Override\n    public ODomain defaultDomain() {\n        ODomain domain = new ODomain();\n        domain.add(\"user_id\", \"=\", getUser().getUser_id());\n        return domain;\n    }\n\n    public String storeLeadName(OValues values) {\n        try {\n            if (!values.getString(\"opportunity_id\").equals(\"false\")) {\n                JSONArray opportunity_id = new JSONArray(values.getString(\"opportunity_id\"));\n                return opportunity_id.getString(1);\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return \"\";\n    }\n\n    public String storeUserName(OValues values) {\n        try {\n            if (!values.getString(\"user_id\").equals(\"false\")) {\n                JSONArray user_id = new JSONArray(values.getString(\"user_id\"));\n                return user_id.getString(1);\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return \"\";\n    }\n\n    public String storeCustomerName(OValues values) {\n        try {\n            if (!values.getString(\"partner_id\").equals(\"false\")) {\n                JSONArray partner_id = new JSONArray(values.getString(\"partner_id\"));\n                return partner_id.getString(1);\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return \"\";\n    }\n\n    public String storeCallType(OValues values) {\n        try {\n            if (!values.getString(\"categ_id\").equals(\"false\")) {\n                JSONArray categ_id = new JSONArray(values.getString(\"categ_id\"));\n                return categ_id.getString(1);\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return \"false\";\n    }\n\n    public void setReminder(int row_id) {\n        ODataRow row = browse(row_id);\n        Date start_date = ODateUtils.createDateObject(row.getString(\"date\"),\n                ODateUtils.DEFAULT_FORMAT, false);\n        Date now = new Date();\n        if (now.compareTo(start_date) < 0) {\n            Bundle extra = row.getPrimaryBundleData();\n            extra.putString(ReminderUtils.KEY_REMINDER_TYPE, \"phonecall\");\n            if (ReminderUtils.get(mContext).resetReminder(start_date, extra)) {\n                OValues values = new OValues();\n                values.put(\"_is_dirty\", \"false\");\n                values.put(\"has_reminder\", \"true\");\n                update(row_id, values);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/addons/phonecall/models/CRMPhoneCallsCategory.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 13/1/15 4:27 PM\n */\npackage com.odoo.addons.phonecall.models;\n\nimport android.content.Context;\n\nimport com.odoo.core.orm.ODataRow;\nimport com.odoo.core.orm.OModel;\nimport com.odoo.core.orm.fields.OColumn;\nimport com.odoo.core.orm.fields.types.OVarchar;\nimport com.odoo.core.support.OUser;\n\nimport odoo.ODomain;\n\npublic class CRMPhoneCallsCategory extends OModel {\n    public static final String TAG = CRMPhoneCallsCategory.class.getSimpleName();\n\n    public enum Type {\n        Inbound, OutBound\n    }\n\n    OColumn name = new OColumn(\"Name\", OVarchar.class);\n\n    public CRMPhoneCallsCategory(Context context, OUser user) {\n        super(context, \"crm.phonecall.category\", user);\n        String serie = getOdooVersion().getServer_serie();\n        if (getOdooVersion().getVersion_number() < 9 && !serie.equals(\"8.saas~6\")) {\n            setModelName(\"crm.case.categ\");\n        }\n    }\n\n\n    @Override\n    public ODomain defaultDomain() {\n        ODomain domain = new ODomain();\n        domain.add(\"object_id.model\", \"=\", getModelName());\n        return domain;\n    }\n\n    public static int getId(Context context, Type type) {\n        int id = 0;\n        CRMPhoneCallsCategory category = new CRMPhoneCallsCategory(context, null);\n        if (category.count(null, null) > 0) {\n            ODataRow row = category.browse(new String[]{}, \"name = ?\", new String[]{\n                    (type == Type.Inbound) ? \"Inbound\" : \"Outbound\"\n            });\n            if (row != null) {\n                id = row.getInt(OColumn.ROW_ID);\n            }\n        }\n        return id;\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/addons/phonecall/providers/PhoneCallProvider.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 13/1/15 4:58 PM\n */\npackage com.odoo.addons.phonecall.providers;\n\nimport android.net.Uri;\n\nimport com.odoo.addons.phonecall.models.CRMPhoneCalls;\nimport com.odoo.core.orm.provider.BaseModelProvider;\n\npublic class PhoneCallProvider extends BaseModelProvider {\n    public static final String TAG = PhoneCallProvider.class.getSimpleName();\n\n    @Override\n    public void setModel(Uri uri) {\n        super.setModel(uri);\n        mModel = new CRMPhoneCalls(getContext(), getUser(uri));\n    }\n\n    @Override\n    public String authority() {\n        return CRMPhoneCalls.AUTHORITY;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/addons/phonecall/services/PhoneCallSyncService.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 13/1/15 4:59 PM\n */\npackage com.odoo.addons.phonecall.services;\n\nimport android.content.Context;\nimport android.content.SyncResult;\nimport android.os.Bundle;\n\nimport com.odoo.addons.phonecall.models.CRMPhoneCalls;\nimport com.odoo.core.orm.ODataRow;\nimport com.odoo.core.orm.fields.OColumn;\nimport com.odoo.core.service.ISyncFinishListener;\nimport com.odoo.core.service.OSyncAdapter;\nimport com.odoo.core.service.OSyncService;\nimport com.odoo.core.support.OUser;\n\nimport java.util.List;\n\nimport odoo.ODomain;\n\npublic class PhoneCallSyncService extends OSyncService implements ISyncFinishListener {\n    public static final String TAG = PhoneCallSyncService.class.getSimpleName();\n    private Context mContext;\n\n    @Override\n    public OSyncAdapter getSyncAdapter(OSyncService service, Context context) {\n        mContext = context;\n        return new OSyncAdapter(context, CRMPhoneCalls.class, service, true);\n    }\n\n    @Override\n    public void performDataSync(OSyncAdapter adapter, Bundle extras, OUser user) {\n        if (adapter.getModel().getModelName().equals(\"crm.phonecall\")) {\n            ODomain domain = new ODomain();\n            domain.add(\"user_id\", \"=\", user.getUser_id());\n            adapter.setDomain(domain).syncDataLimit(10);\n            adapter.onSyncFinish(this).syncDataLimit(50);\n        }\n    }\n\n    @Override\n    public OSyncAdapter performNextSync(OUser user, SyncResult syncResult) {\n        CRMPhoneCalls crmPhoneCalls = new CRMPhoneCalls(mContext, user);\n        List<ODataRow> rows = crmPhoneCalls.select(new String[]{});\n        for (ODataRow row : rows) {\n            crmPhoneCalls.setReminder(row.getInt(OColumn.ROW_ID));\n        }\n        return null;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/addons/sale/AddProductLineWizard.java",
    "content": "package com.odoo.addons.sale;\n\nimport android.app.ProgressDialog;\nimport android.content.Intent;\nimport android.graphics.Color;\nimport android.os.AsyncTask;\nimport android.os.Bundle;\nimport android.support.v7.app.ActionBarActivity;\nimport android.text.Editable;\nimport android.text.InputType;\nimport android.text.TextWatcher;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.AdapterView;\nimport android.widget.EditText;\nimport android.widget.ImageView;\nimport android.widget.ListView;\n\nimport com.odoo.R;\nimport com.odoo.addons.sale.models.ProductProduct;\nimport com.odoo.core.orm.ODataRow;\nimport com.odoo.core.orm.ServerDataHelper;\nimport com.odoo.core.orm.fields.OColumn;\nimport com.odoo.core.support.OdooFields;\nimport com.odoo.core.support.list.OListAdapter;\nimport com.odoo.core.utils.OAlert;\nimport com.odoo.core.utils.OControls;\nimport com.odoo.core.utils.OResource;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\n\nimport odoo.ODomain;\nimport odoo.controls.IOnQuickRecordCreateListener;\n\npublic class AddProductLineWizard extends ActionBarActivity implements\n        AdapterView.OnItemClickListener, TextWatcher, View.OnClickListener,\n        OListAdapter.OnSearchChange, IOnQuickRecordCreateListener, AdapterView.OnItemLongClickListener {\n\n    private ProductProduct productProduct;\n    private EditText edt_searchable_input;\n    private ListView mList = null;\n    private OListAdapter mAdapter;\n    private List<Object> objects = new ArrayList<>();\n    private List<Object> localItems = new ArrayList<>();\n    private int selected_position = -1;\n    private LiveSearch mLiveDataLoader = null;\n    private OColumn mCol = null;\n    private HashMap<String, Float> lineValues = new HashMap<>();\n    private Boolean mLongClicked = false;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.sale_add_item);\n        setResult(RESULT_CANCELED);\n        productProduct = new ProductProduct(this, null);\n        edt_searchable_input = (EditText) findViewById(R.id.edt_searchable_input);\n        edt_searchable_input.addTextChangedListener(this);\n        findViewById(R.id.done).setOnClickListener(this);\n        Bundle extra = getIntent().getExtras();\n        if (extra != null) {\n            mList = (ListView) findViewById(R.id.searchable_items);\n            mList.setOnItemClickListener(this);\n            mList.setOnItemLongClickListener(this);\n            for (String key : extra.keySet()) {\n                lineValues.put(key, extra.getFloat(key));\n            }\n            for (Object local : productProduct.select()) {\n                ODataRow product = (ODataRow) local;\n                if (lineValues.containsKey(product.getString(\"id\") + \"\")) {\n                    localItems.add(0, product);\n                } else {\n                    localItems.add(product);\n                }\n            }\n            objects.addAll(localItems);\n            mAdapter = new OListAdapter(this,\n                    R.layout.sale_product_line_item, objects) {\n                @Override\n                public View getView(int position, View convertView, ViewGroup parent) {\n                    View v = convertView;\n                    if (v == null)\n                        v = getLayoutInflater().inflate(getResource(), parent, false);\n                    generateView(v, position);\n                    return v;\n                }\n            };\n            mAdapter.setOnSearchChange(this);\n            mList.setAdapter(mAdapter);\n        } else {\n            finish();\n        }\n    }\n\n    private void generateView(View v, int position) {\n        final ODataRow row = (ODataRow) objects.get(position);\n        Float qty = (lineValues.containsKey(row.getString(\"id\")) &&\n                lineValues.get(row.getString(\"id\")) > 0) ? lineValues.get(row.getString(\"id\")) : 0;\n        if (qty <= 0) {\n            OControls.setGone(v, R.id.productQty);\n            OControls.setGone(v, R.id.remove_qty);\n        } else {\n            OControls.setVisible(v, R.id.remove_qty);\n            v.findViewById(R.id.remove_qty).setOnClickListener(new View.OnClickListener() {\n                @Override\n                public void onClick(View v) {\n                    Float lineQty = lineValues.get(row.getString(\"id\"));\n                    lineValues.put(row.getString(\"id\"), lineQty - 1);\n                    mAdapter.notifiyDataChange(objects);\n                }\n            });\n            OControls.setVisible(v, R.id.productQty);\n            OControls.setText(v, R.id.productQty, qty + \" \");\n        }\n        OControls.setText(v, R.id.productName,\n                row.getString(productProduct.getDefaultNameColumn()));\n        if (row.contains(OColumn.ROW_ID)\n                && selected_position == row.getInt(OColumn.ROW_ID)) {\n            v.setBackgroundColor(getResources().getColor(\n                    R.color.control_pressed));\n        } else {\n            v.setBackgroundColor(Color.TRANSPARENT);\n        }\n    }\n\n    @Override\n    public void onItemClick(AdapterView<?> parent, View view, int position,\n                            long id) {\n        ODataRow data = (ODataRow) objects.get(position);\n        int row_id = productProduct.selectRowId(data.getInt(\"id\"));\n        if (row_id != -1) {\n            data.put(OColumn.ROW_ID, row_id);\n        }\n        if (!data.contains(OColumn.ROW_ID)) {\n            QuickCreateRecordProcess quickCreateRecordProcess = new QuickCreateRecordProcess(this);\n            quickCreateRecordProcess.execute(data);\n        } else {\n            onRecordCreated(data);\n        }\n    }\n\n    @Override\n    public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {\n        ODataRow data = (ODataRow) objects.get(position);\n        mLongClicked = true;\n        int row_id = productProduct.selectRowId(data.getInt(\"id\"));\n        if (row_id != -1) {\n            data.put(OColumn.ROW_ID, row_id);\n        }\n        if (!data.contains(OColumn.ROW_ID)) {\n            QuickCreateRecordProcess quickCreateRecordProcess = new QuickCreateRecordProcess(this);\n            quickCreateRecordProcess.execute(data);\n        } else {\n            onLongClicked(data);\n        }\n        return true;\n    }\n\n    private void onLongClicked(final ODataRow row) {\n        mLongClicked = false;\n        final Float count = ((lineValues.containsKey(row.getString(\"id\")))\n                ? lineValues.get(row.getString(\"id\")) : 0);\n        OAlert.inputDialog(this, \"Quantity\", new OAlert.OnUserInputListener() {\n            @Override\n            public void onViewCreated(EditText inputView) {\n                inputView.setInputType(InputType.TYPE_CLASS_NUMBER\n                        | InputType.TYPE_NUMBER_FLAG_DECIMAL | InputType.TYPE_NUMBER_FLAG_SIGNED);\n                inputView.setText(count + \"\");\n            }\n\n            @Override\n            public void onUserInputted(Object value) {\n                float userData = Float.parseFloat(value.toString());\n                lineValues.put(row.getString(\"id\"), userData);\n                mAdapter.notifiyDataChange(objects);\n            }\n        });\n    }\n\n    @Override\n    public void onRecordCreated(ODataRow row) {\n        if (!mLongClicked) {\n            Float count = ((lineValues.containsKey(row.getString(\"id\")))\n                    ? lineValues.get(row.getString(\"id\")) : 0);\n            lineValues.put(row.getString(\"id\"), ++count);\n            mAdapter.notifiyDataChange(objects);\n        } else {\n            onLongClicked(row);\n        }\n    }\n\n    @Override\n    public void beforeTextChanged(CharSequence s, int start, int count,\n                                  int after) {\n\n    }\n\n    @Override\n    public void onTextChanged(CharSequence s, int start, int before, int count) {\n        mAdapter.getFilter().filter(s);\n        ImageView imgView = (ImageView) findViewById(R.id.search_icon);\n        if (s.length() > 0) {\n            imgView.setImageResource(R.drawable.ic_action_navigation_close);\n            imgView.setOnClickListener(this);\n            imgView.setClickable(true);\n        } else {\n            imgView.setClickable(false);\n            imgView.setImageResource(R.drawable.ic_action_search);\n            imgView.setOnClickListener(null);\n        }\n    }\n\n    @Override\n    public void afterTextChanged(Editable s) {\n\n    }\n\n    @Override\n    public void onClick(View v) {\n        switch (v.getId()) {\n            case R.id.done:\n                Bundle data = new Bundle();\n                for (String key : lineValues.keySet()) {\n                    data.putFloat(key, lineValues.get(key));\n                }\n                Intent intent = new Intent();\n                intent.putExtras(data);\n                setResult(RESULT_OK, intent);\n                finish();\n                break;\n            default:\n                setResult(RESULT_CANCELED);\n                finish();\n        }\n    }\n\n    @Override\n    public void onSearchChange(List<Object> newRecords) {\n        if (newRecords.size() <= 2) {\n            if (mLiveDataLoader != null)\n                mLiveDataLoader.cancel(true);\n            if (edt_searchable_input.getText().length() >= 2) {\n                mLiveDataLoader = new LiveSearch();\n                mLiveDataLoader.execute(edt_searchable_input.getText()\n                        .toString());\n            }\n        }\n    }\n\n\n    private class LiveSearch extends AsyncTask<String, Void, List<ODataRow>> {\n\n        @Override\n        protected void onPreExecute() {\n            super.onPreExecute();\n            findViewById(R.id.loading_progress).setVisibility(View.VISIBLE);\n            mList.setVisibility(View.GONE);\n        }\n\n        @Override\n        protected List<ODataRow> doInBackground(String... params) {\n            try {\n                ServerDataHelper helper = productProduct.getServerDataHelper();\n                ODomain domain = new ODomain();\n//                domain.add(productProduct.getDefaultNameColumn(), \"ilike\", params[0]);\n                domain.add(\"id\", \"not in\", productProduct.getServerIds());\n                if (mCol != null) {\n                    for (String key : mCol.getDomains().keySet()) {\n                        // domain.add(\"sale_ok\", \"=\", true);\n                    }\n                }\n                OdooFields fields = new OdooFields(productProduct.getColumns());\n                //return helper.searchRecords(fields, domain, 10);\n                return helper.nameSearch(params[0], domain, 10);\n            } catch (Exception e) {\n                e.printStackTrace();\n            }\n            return null;\n        }\n\n        @Override\n        protected void onPostExecute(List<ODataRow> result) {\n            super.onPostExecute(result);\n            findViewById(R.id.loading_progress).setVisibility(View.GONE);\n            mList.setVisibility(View.VISIBLE);\n            if (result != null && result.size() > 0) {\n                objects.clear();\n                objects.addAll(localItems);\n                objects.addAll(result);\n                mAdapter.notifiyDataChange(objects);\n            }\n        }\n\n        @Override\n        protected void onCancelled() {\n            super.onCancelled();\n            findViewById(R.id.loading_progress).setVisibility(View.GONE);\n            mList.setVisibility(View.VISIBLE);\n        }\n    }\n\n    private class QuickCreateRecordProcess extends AsyncTask<ODataRow, Void, ODataRow> {\n\n        private ProgressDialog progressDialog;\n        IOnQuickRecordCreateListener mOnQuickRecordCreateListener = null;\n\n        public QuickCreateRecordProcess(IOnQuickRecordCreateListener listener) {\n            mOnQuickRecordCreateListener = listener;\n        }\n\n        @Override\n        protected void onPreExecute() {\n            super.onPreExecute();\n            progressDialog = new ProgressDialog(AddProductLineWizard.this);\n            progressDialog.setTitle(R.string.title_please_wait);\n            progressDialog.setMessage(OResource.string(AddProductLineWizard.this, R.string.title_working));\n            progressDialog.setCancelable(false);\n            progressDialog.show();\n        }\n\n        @Override\n        protected ODataRow doInBackground(ODataRow... params) {\n            try {\n                Thread.sleep(700);\n                return productProduct.quickCreateRecord(params[0]);\n            } catch (Exception e) {\n                e.printStackTrace();\n            }\n            return null;\n        }\n\n        @Override\n        protected void onPostExecute(ODataRow data) {\n            super.onPostExecute(data);\n            if (data != null && mOnQuickRecordCreateListener != null) {\n                mOnQuickRecordCreateListener.onRecordCreated(data);\n            }\n            progressDialog.dismiss();\n        }\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/addons/sale/Sales.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 13/1/15 11:06 AM\n */\npackage com.odoo.addons.sale;\n\nimport android.content.Context;\nimport android.database.Cursor;\nimport android.graphics.Color;\nimport android.os.Bundle;\nimport android.os.Handler;\nimport android.support.annotation.Nullable;\nimport android.support.v4.app.LoaderManager;\nimport android.support.v4.content.CursorLoader;\nimport android.support.v4.content.Loader;\nimport android.support.v4.widget.SwipeRefreshLayout;\nimport android.view.LayoutInflater;\nimport android.view.Menu;\nimport android.view.MenuInflater;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.ListView;\nimport android.widget.Toast;\n\nimport com.odoo.R;\nimport com.odoo.addons.sale.models.SaleOrder;\nimport com.odoo.core.orm.ODataRow;\nimport com.odoo.core.support.addons.fragment.BaseFragment;\nimport com.odoo.core.support.addons.fragment.IOnSearchViewChangeListener;\nimport com.odoo.core.support.addons.fragment.ISyncStatusObserverListener;\nimport com.odoo.core.support.drawer.ODrawerItem;\nimport com.odoo.core.support.list.IOnItemClickListener;\nimport com.odoo.core.support.list.OCursorListAdapter;\nimport com.odoo.core.utils.IntentUtils;\nimport com.odoo.core.utils.OAlert;\nimport com.odoo.core.utils.OControls;\nimport com.odoo.core.utils.OCursorUtils;\nimport com.odoo.core.utils.ODateUtils;\nimport com.odoo.core.utils.OResource;\nimport com.odoo.core.utils.sys.IOnBackPressListener;\nimport com.odoo.widgets.bottomsheet.BottomSheet;\nimport com.odoo.widgets.bottomsheet.BottomSheetListeners;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\n\npublic class Sales extends BaseFragment implements\n        OCursorListAdapter.OnViewBindListener, LoaderManager.LoaderCallbacks<Cursor>,\n        SwipeRefreshLayout.OnRefreshListener, IOnSearchViewChangeListener,\n        ISyncStatusObserverListener, IOnItemClickListener, BottomSheetListeners.OnSheetItemClickListener, BottomSheetListeners.OnSheetActionClickListener, IOnBackPressListener, View.OnClickListener {\n    public static final String TAG = Sales.class.getSimpleName();\n    public static final String KEY_MENU = \"key_sales_menu\";\n\n    private View mView;\n    private ListView mList;\n    private OCursorListAdapter mAdapter;\n    private String mFilter = null;\n    private BottomSheet mSheet;\n    private Type mType = Type.Quotation;\n    private Boolean mSyncRequested = false;\n\n    public enum Type {\n        Quotation,\n        SaleOrder\n    }\n\n    @Override\n    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,\n                             @Nullable Bundle savedInstanceState) {\n        setHasOptionsMenu(true);\n        mType = Type.valueOf(getArguments().getString(KEY_MENU));\n        return inflater.inflate(R.layout.common_listview, container, false);\n    }\n\n    @Override\n    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {\n        super.onViewCreated(view, savedInstanceState);\n        parent().setOnBackPressListener(this);\n        mView = view;\n        initAdapter();\n    }\n\n    private void initAdapter() {\n        mList = (ListView) mView.findViewById(R.id.listview);\n        mAdapter = new OCursorListAdapter(getActivity(), null, R.layout.sale_order_item);\n        mAdapter.setOnViewBindListener(this);\n        mList.setAdapter(mAdapter);\n        mAdapter.handleItemClickListener(mList, this);\n        setHasFloatingButton(mView, R.id.fabButton, mList, this);\n        if (mType == Type.SaleOrder)\n            mView.findViewById(R.id.fabButton).setVisibility(View.GONE);\n        setHasSyncStatusObserver(TAG, this, db());\n        setHasSwipeRefreshView(mView, R.id.swipe_container, this);\n        getLoaderManager().initLoader(0, null, this);\n    }\n\n    @Override\n    public void onViewBind(View view, Cursor cursor, ODataRow row) {\n        OControls.setText(view, R.id.name, row.getString(\"name\"));\n        String format = (db().getUser().getVersion_number() <= 7)\n                ? ODateUtils.DEFAULT_DATE_FORMAT : ODateUtils.DEFAULT_FORMAT;\n        String date = ODateUtils.convertToDefault(row.getString(\"date_order\"),\n                format, \"MMMM, dd\");\n        OControls.setText(view, R.id.date_order, date);\n        OControls.setText(view, R.id.state, row.getString(\"state_title\"));\n        if (row.getString(\"partner_name\").equals(\"false\")) {\n            OControls.setGone(view, (R.id.partner_name));\n        } else {\n            OControls.setVisible(view, R.id.partner_name);\n            OControls.setText(view, R.id.partner_name, row.getString(\"partner_name\"));\n        }\n        OControls.setText(view, R.id.amount_total, row.getString(\"amount_total\"));\n        if (row.getString(\"currency_symbol\").equals(\"false\")) {\n            OControls.setGone(view, (R.id.currency_symbol));\n        } else {\n            OControls.setVisible(view, R.id.currency_symbol);\n            OControls.setText(view, R.id.currency_symbol, row.getString(\"currency_symbol\"));\n        }\n        OControls.setText(view, R.id.order_lines, row.getString(\"order_line_count\"));\n    }\n\n    @Override\n    public List<ODrawerItem> drawerMenus(Context context) {\n        List<ODrawerItem> menu = new ArrayList<>();\n        menu.add(new ODrawerItem(TAG).setTitle(OResource.string(context, R.string.label_quotation))\n                .setIcon(R.drawable.ic_action_quotation)\n                .setInstance(new Sales())\n                .setExtra(data(Type.Quotation)));\n        menu.add(new ODrawerItem(TAG).setTitle(OResource.string(context, R.string.label_sale_orders))\n                .setIcon(R.drawable.ic_action_sale_order)\n                .setInstance(new Sales())\n                .setExtra(data(Type.SaleOrder)));\n        return menu;\n    }\n\n    @Override\n    public Loader<Cursor> onCreateLoader(int id, Bundle data) {\n        String where = null;\n        String[] whereArgs = null;\n        List<String> args = new ArrayList<>();\n        switch (mType) {\n            case Quotation:\n                where = \" (state = ? or state = ?)\";\n                args.addAll(Arrays.asList(new String[]{\"draft\", \"cancel\"}));\n                break;\n            case SaleOrder:\n                where = \"(state = ? or state = ? or state = ?)\";\n                args.addAll(Arrays.asList(new String[]{\"manual\", \"progress\",\n                        \"done\"}));\n                break;\n        }\n        if (mFilter != null) {\n            where += \" and (name like ? or partner_name like ? or state_title like ?)\";\n            args.add(\"%\" + mFilter + \"%\");\n            args.add(\"%\" + mFilter + \"%\");\n            args.add(\"%\" + mFilter + \"%\");\n        }\n        whereArgs = args.toArray(new String[args.size()]);\n        return new CursorLoader(getActivity(), db().uri(), null, where, whereArgs, \"date_order DESC\");\n    }\n\n    @Override\n    public void onLoadFinished(Loader<Cursor> loader, Cursor data) {\n        mAdapter.changeCursor(data);\n        if (data.getCount() > 0) {\n            new Handler().postDelayed(new Runnable() {\n                @Override\n                public void run() {\n                    OControls.setGone(mView, R.id.loadingProgress);\n                    OControls.setVisible(mView, R.id.swipe_container);\n                    OControls.setGone(mView, R.id.customer_no_items);\n                    setHasSwipeRefreshView(mView, R.id.swipe_container, Sales.this);\n                }\n            }, 500);\n        } else {\n            if (db().isEmptyTable() && !mSyncRequested) {\n                mSyncRequested = true;\n                onRefresh();\n            }\n            new Handler().postDelayed(new Runnable() {\n                @Override\n                public void run() {\n                    OControls.setGone(mView, R.id.loadingProgress);\n                    OControls.setGone(mView, R.id.swipe_container);\n                    OControls.setVisible(mView, R.id.customer_no_items);\n                    setHasSwipeRefreshView(mView, R.id.customer_no_items, Sales.this);\n                    OControls.setImage(mView, R.id.icon,\n                            (mType == Type.Quotation) ? R.drawable.ic_action_quotation : R.drawable.ic_action_sale_order);\n                    OControls.setText(mView, R.id.title, \"No \" + mType + \" Found\");\n                    OControls.setText(mView, R.id.subTitle, \"\");\n                }\n            }, 500);\n        }\n    }\n\n    @Override\n    public void onLoaderReset(Loader<Cursor> loader) {\n        mAdapter.changeCursor(null);\n    }\n\n    private Bundle data(Type type) {\n        Bundle extra = new Bundle();\n        extra.putString(KEY_MENU, type.toString());\n        return extra;\n    }\n\n    @Override\n    public Class<SaleOrder> database() {\n        return SaleOrder.class;\n    }\n\n\n    @Override\n    public void onRefresh() {\n        if (inNetwork()) {\n            parent().sync().requestSync(SaleOrder.AUTHORITY);\n            setSwipeRefreshing(true);\n        } else {\n            hideRefreshingProgress();\n            Toast.makeText(getActivity(), _s(R.string.toast_network_required), Toast.LENGTH_LONG)\n                    .show();\n        }\n    }\n\n    @Override\n    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {\n        super.onCreateOptionsMenu(menu, inflater);\n        menu.clear();\n        inflater.inflate(R.menu.menu_sales_order, menu);\n        setHasSearchView(this, menu, R.id.menu_sales_search);\n\n    }\n\n    @Override\n    public boolean onSearchViewTextChange(String newFilter) {\n        mFilter = newFilter;\n        getLoaderManager().restartLoader(0, null, this);\n        return true;\n    }\n\n    @Override\n    public void onSearchViewClose() {\n        //Nothing to do\n    }\n\n\n    @Override\n    public void onStatusChange(Boolean refreshing) {\n        getLoaderManager().restartLoader(0, null, this);\n    }\n\n    @Override\n    public void onItemDoubleClick(View view, int position) {\n        onDoubleClick(position);\n    }\n\n    private void onDoubleClick(int position) {\n        ODataRow row = OCursorUtils.toDatarow((Cursor) mAdapter.getItem(position));\n        Bundle data = row.getPrimaryBundleData();\n        data.putString(\"type\", mType.toString());\n        IntentUtils.startActivity(getActivity(), SalesDetail.class, data);\n    }\n\n    @Override\n    public void onItemClick(View view, int position) {\n        if (mType == Type.Quotation)\n            showSheet((Cursor) mAdapter.getItem(position));\n        else\n            onDoubleClick(position);\n    }\n\n    private void showSheet(Cursor data) {\n        BottomSheet.Builder builder = new BottomSheet.Builder(getActivity());\n        builder.listener(this);\n        builder.setIconColor(_c(R.color.theme_primary_dark));\n        builder.setTextColor(Color.parseColor(\"#414141\"));\n        builder.setData(data);\n        builder.actionListener(this);\n        builder.setActionIcon(R.drawable.ic_action_edit);\n        builder.title(data.getString(data.getColumnIndex(\"name\")));\n\n        if (data.getString(data.getColumnIndex(\"state\")).equals(\"cancel\"))\n            builder.menu(R.menu.menu_quotation_cancel_sheet);\n        else\n            builder.menu(R.menu.menu_quotation_sheet);\n        mSheet = builder.create();\n        mSheet.show();\n\n    }\n\n    @Override\n    public void onItemClick(BottomSheet sheet, MenuItem menu, Object extras) {\n        mSheet.dismiss();\n        ODataRow row = OCursorUtils.toDatarow((Cursor) extras);\n        switch (menu.getItemId()) {\n//            case R.id.menu_so_send_by_email:\n//                break;\n            case R.id.menu_quotation_cancel:\n                ((SaleOrder) db()).cancelOrder(mType, row, cancelOrder);\n                break;\n            case R.id.menu_quotation_new:\n                if (inNetwork()) {\n                    ((SaleOrder) db()).newCopyQuotation(row, newCopyQuotation);\n                } else {\n                    Toast.makeText(getActivity(), R.string.toast_network_required, Toast.LENGTH_LONG).show();\n                }\n                break;\n            case R.id.menu_so_confirm_sale:\n                if (row.getFloat(\"amount_total\") > 0) {\n                    if (inNetwork()) {\n                        ((SaleOrder) db()).confirmSale(row, confirmSale);\n                    } else {\n                        Toast.makeText(getActivity(), R.string.toast_network_required, Toast.LENGTH_LONG).show();\n                    }\n                } else {\n                    OAlert.showWarning(getActivity(), \"You cannot a sales order which has no line\");\n                }\n                break;\n        }\n    }\n\n    SaleOrder.OnOperationSuccessListener cancelOrder = new SaleOrder.OnOperationSuccessListener() {\n        @Override\n        public void OnSuccess() {\n            Toast.makeText(getActivity(), mType + \" cancelled\", Toast.LENGTH_LONG).show();\n        }\n\n        @Override\n        public void OnCancelled() {\n\n        }\n    };\n    SaleOrder.OnOperationSuccessListener confirmSale = new SaleOrder.OnOperationSuccessListener() {\n        @Override\n        public void OnSuccess() {\n            Toast.makeText(getActivity(), \"Quotation confirmed !\", Toast.LENGTH_LONG).show();\n        }\n\n        @Override\n        public void OnCancelled() {\n\n        }\n    };\n    SaleOrder.OnOperationSuccessListener newCopyQuotation = new SaleOrder.OnOperationSuccessListener() {\n        @Override\n        public void OnSuccess() {\n            Toast.makeText(getActivity(), R.string.label_copy_quotation, Toast.LENGTH_LONG).show();\n        }\n\n        @Override\n        public void OnCancelled() {\n\n        }\n    };\n\n    @Override\n    public void onSheetActionClick(BottomSheet sheet, Object extras) {\n        mSheet.dismiss();\n        ODataRow row = OCursorUtils.toDatarow((Cursor) extras);\n        Bundle data = row.getPrimaryBundleData();\n        data.putString(\"type\", mType.toString());\n        IntentUtils.startActivity(getActivity(), SalesDetail.class, data);\n    }\n\n    @Override\n    public boolean onBackPressed() {\n        if (mSheet != null && mSheet.isShowing()) {\n            mSheet.dismiss();\n            return false;\n        }\n        return true;\n    }\n\n    @Override\n    public void onClick(View v) {\n        switch (v.getId()) {\n            case R.id.fabButton:\n                Bundle bundle = new Bundle();\n                bundle.putString(\"type\", Type.Quotation.toString());\n                IntentUtils.startActivity(getActivity(), SalesDetail.class, bundle);\n                break;\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/addons/sale/SalesDetail.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 13/1/15 5:09 PM\n */\npackage com.odoo.addons.sale;\n\nimport android.app.Activity;\nimport android.app.ProgressDialog;\nimport android.content.Intent;\nimport android.os.AsyncTask;\nimport android.os.Bundle;\nimport android.support.v7.app.ActionBar;\nimport android.support.v7.app.ActionBarActivity;\nimport android.view.Menu;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.LinearLayout;\nimport android.widget.TextView;\nimport android.widget.Toast;\n\nimport com.odoo.App;\nimport com.odoo.R;\nimport com.odoo.addons.sale.models.ProductProduct;\nimport com.odoo.addons.sale.models.SaleOrder;\nimport com.odoo.addons.sale.models.SalesOrderLine;\nimport com.odoo.base.addons.res.ResPartner;\nimport com.odoo.core.orm.ODataRow;\nimport com.odoo.core.orm.OValues;\nimport com.odoo.core.orm.ServerDataHelper;\nimport com.odoo.core.orm.fields.OColumn;\nimport com.odoo.core.utils.JSONUtils;\nimport com.odoo.core.utils.OActionBarUtils;\nimport com.odoo.core.utils.OAlert;\nimport com.odoo.core.utils.OControls;\nimport com.odoo.core.utils.OResource;\nimport com.odoo.core.utils.StringUtils;\n\nimport org.json.JSONArray;\nimport org.json.JSONObject;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\n\nimport odoo.OArguments;\nimport odoo.controls.ExpandableListControl;\nimport odoo.controls.OField;\nimport odoo.controls.OForm;\n\nimport static com.odoo.addons.sale.Sales.Type;\n\npublic class SalesDetail extends ActionBarActivity implements View.OnClickListener {\n    public static final String TAG = SalesDetail.class.getSimpleName();\n    public static final int REQUEST_ADD_ITEMS = 323;\n    private Bundle extra;\n    private OForm mForm;\n    private ODataRow record;\n    private SaleOrder sale;\n    private ActionBar actionBar;\n    private ExpandableListControl mList;\n    private ExpandableListControl.ExpandableListAdapter mAdapter;\n    private List<Object> objects = new ArrayList<>();\n    private HashMap<String, Float> lineValues = new HashMap<>();\n    private HashMap<String, Integer> lineIds = new HashMap<>();\n    private TextView txvType, currency1, currency2, currency3, untaxedAmt, taxesAmt, total_amt;\n    private ODataRow currencyObj;\n    private ResPartner partner = null;\n    private ProductProduct products = null;\n    private String mSOType = \"\";\n    private LinearLayout layoutAddItem = null;\n    private Type mType;\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.sale_detail);\n        OActionBarUtils.setActionBar(this, true);\n        actionBar = getSupportActionBar();\n        sale = new SaleOrder(this, null);\n        extra = getIntent().getExtras();\n        mType = Type.valueOf(extra.getString(\"type\"));\n        currencyObj = sale.currency();\n        partner = new ResPartner(this, null);\n        products = new ProductProduct(this, null);\n        init();\n        initAdapter();\n    }\n\n    private void init() {\n        mForm = (OForm) findViewById(R.id.saleForm);\n        mForm.setEditable(true);\n        txvType = (TextView) findViewById(R.id.txvType);\n        currency1 = (TextView) findViewById(R.id.currency1);\n        currency2 = (TextView) findViewById(R.id.currency2);\n        currency3 = (TextView) findViewById(R.id.currency3);\n        String currencySymbol = currencyObj.getString(\"symbol\");\n        untaxedAmt = (TextView) findViewById(R.id.untaxedTotal);\n        taxesAmt = (TextView) findViewById(R.id.taxesTotal);\n        total_amt = (TextView) findViewById(R.id.fTotal);\n        untaxedAmt.setText(\"0.00\");\n        taxesAmt.setText(\"0.00\");\n        total_amt.setText(\"0.00\");\n        layoutAddItem = (LinearLayout) findViewById(R.id.layoutAddItem);\n        layoutAddItem.setOnClickListener(this);\n        if (extra == null || !extra.containsKey(OColumn.ROW_ID)) {\n            mForm.initForm(null);\n            actionBar.setTitle(R.string.label_new);\n            actionBar.setHomeAsUpIndicator(R.drawable.ic_action_navigation_close);\n            txvType.setText(R.string.label_quotation);\n        } else {\n            record = sale.browse(extra.getInt(OColumn.ROW_ID));\n            if (record == null) {\n                finish();\n            }\n            if (!record.getString(\"partner_id\").equals(\"false\") && mType == Type.Quotation) {\n                OnCustomerChangeUpdate onCustomerChangeUpdate = new OnCustomerChangeUpdate();\n                onCustomerChangeUpdate.execute(record.getM2ORecord(\"partner_id\").browse());\n            }\n            if (mType == Type.Quotation) {\n                actionBar.setTitle(R.string.label_quotation);\n                txvType.setText(R.string.label_quotation);\n                if (record.getString(\"state\").equals(\"cancel\"))\n                    layoutAddItem.setVisibility(View.GONE);\n            } else {\n                layoutAddItem.setVisibility(View.GONE);\n                actionBar.setTitle(R.string.label_sale_orders);\n                txvType.setText(R.string.label_sale_orders);\n                mForm.setEditable(false);\n            }\n            currencySymbol = record.getM2ORecord(\"currency_id\").browse().getString(\"symbol\");\n            untaxedAmt.setText(String.format(\"%.2f\", record.getFloat(\"amount_untaxed\")));\n            taxesAmt.setText(String.format(\"%.2f\", record.getFloat(\"amount_tax\")));\n            total_amt.setText(String.format(\"%.2f\", record.getFloat(\"amount_total\")));\n            mForm.initForm(record);\n        }\n        mSOType = txvType.getText().toString();\n        currency1.setText(currencySymbol);\n        currency2.setText(currencySymbol);\n        currency3.setText(currencySymbol);\n    }\n\n    private void initAdapter() {\n        mList = (ExpandableListControl) findViewById(R.id.expListOrderLine);\n        mList.setVisibility(View.VISIBLE);\n        if (extra != null && record != null) {\n            List<ODataRow> lines = record.getO2MRecord(\"order_line\").browseEach();\n            for (ODataRow line : lines) {\n                int product_id = products.selectServerId(line.getInt(\"product_id\"));\n                if (product_id != 0) {\n                    lineValues.put(product_id + \"\", line.getFloat(\"product_uom_qty\"));\n                    lineIds.put(product_id + \"\", line.getInt(\"id\"));\n                }\n            }\n            objects.addAll(lines);\n        }\n        mAdapter = mList.getAdapter(R.layout.sale_order_line_item, objects,\n                new ExpandableListControl.ExpandableListAdapterGetViewListener() {\n                    @Override\n                    public View getView(int position, View mView, ViewGroup parent) {\n                        ODataRow row = (ODataRow) mAdapter.getItem(position);\n                        OControls.setText(mView, R.id.edtName, row.getString(\"name\"));\n                        OControls.setText(mView, R.id.edtProductQty, row.getString(\"product_uom_qty\"));\n                        OControls.setText(mView, R.id.edtProductPrice, String.format(\"%.2f\", row.getFloat(\"price_unit\")));\n                        OControls.setText(mView, R.id.edtSubTotal, String.format(\"%.2f\", row.getFloat(\"price_subtotal\")));\n                        return mView;\n                    }\n                });\n        mAdapter.notifyDataSetChanged(objects);\n    }\n\n    @Override\n    public boolean onCreateOptionsMenu(Menu menu) {\n        getMenuInflater().inflate(R.menu.menu_sale_detail, menu);\n        OField name = (OField) mForm.findViewById(R.id.fname);\n        name.setEditable(false);\n        if (extra != null && !extra.getString(\"type\").equals(Type.SaleOrder.toString())) {\n            // Operation on Sale Order\n        } else {\n            menu.findItem(R.id.menu_sale_save).setVisible(false);\n            menu.findItem(R.id.menu_sale_confirm_sale).setVisible(false);\n        }\n        if (extra != null && record != null && record.getString(\"state\").equals(\"cancel\")) {\n            menu.findItem(R.id.menu_sale_save).setVisible(true).setTitle(\"Copy Quotation\");\n            menu.findItem(R.id.menu_sale_detail_more).setVisible(false);\n            mForm.setEditable(true);\n        } else {\n            menu.findItem(R.id.menu_sale_detail_more).setVisible(false);\n            menu.findItem(R.id.menu_sale_new_copy_of_quotation).setVisible(false);\n        }\n        if (extra == null || !extra.containsKey(OColumn.ROW_ID)) {\n            menu.findItem(R.id.menu_sale_save).setVisible(true);\n            menu.findItem(R.id.menu_sale_detail_more).setVisible(false);\n        }\n        return true;\n    }\n\n    @Override\n    public boolean onOptionsItemSelected(MenuItem item) {\n        OValues values = mForm.getValues();\n        App app = (App) getApplicationContext();\n        switch (item.getItemId()) {\n            case android.R.id.home:\n                finish();\n                break;\n            case R.id.menu_sale_save:\n                if (values != null) {\n                    if (app.inNetwork()) {\n                        values.put(\"partner_name\", partner.getName(values.getInt(\"partner_id\")));\n                        SaleOrderOperation saleOrderOperation = new SaleOrderOperation();\n                        saleOrderOperation.execute(values);\n                    } else {\n                        Toast.makeText(this, R.string.toast_network_required, Toast.LENGTH_LONG).show();\n                    }\n                }\n                break;\n            case R.id.menu_sale_confirm_sale:\n                if (record != null) {\n                    if (extra != null && record.getFloat(\"amount_total\") > 0) {\n                        if (app.inNetwork()) {\n                            sale.confirmSale(record, confirmSale);\n                        } else {\n                            Toast.makeText(this, R.string.toast_network_required, Toast.LENGTH_LONG).show();\n                        }\n                    } else {\n                        OAlert.showWarning(this, R.string.label_no_order_line + \"\");\n                    }\n                }\n                break;\n        }\n        return super.onOptionsItemSelected(item);\n    }\n\n    private class SaleOrderOperation extends AsyncTask<OValues, Void, Boolean> {\n\n        private ProgressDialog mDialog;\n\n        @Override\n        protected void onPreExecute() {\n            super.onPreExecute();\n            mDialog = new ProgressDialog(SalesDetail.this);\n            mDialog.setTitle(R.string.title_working);\n            mDialog.setMessage(\"Creating lines\");\n            mDialog.setCancelable(false);\n            mDialog.show();\n        }\n\n        @Override\n        protected Boolean doInBackground(OValues... params) {\n            try {\n                Thread.sleep(500);\n                OValues values = params[0];\n                // Creating oneToMany order lines\n                JSONArray order_line = new JSONArray();\n                for (Object line : objects) {\n                    JSONArray o_line = new JSONArray();\n                    ODataRow row = (ODataRow) line;\n                    String product_id = row.getString(\"product_id\");\n                    o_line.put((lineIds.containsKey(product_id)) ? 1 : 0);\n                    o_line.put((lineIds.containsKey(product_id)) ? lineIds.get(product_id) : false);\n                    if (lineIds.containsKey(product_id)) {\n                        JSONObject line_data = new JSONObject();\n                        line_data.put(\"product_uom_qty\", row.get(\"product_uom_qty\"));\n                        line_data.put(\"product_uos_qty\", row.get(\"product_uos_qty\"));\n                        o_line.put(line_data);\n                    } else\n                        o_line.put(JSONUtils.toJSONObject(row));\n                    order_line.put(o_line);\n                    lineIds.remove(product_id);\n                }\n                if (lineIds.size() > 0) {\n                    for (String key : lineIds.keySet()) {\n                        JSONArray o_line = new JSONArray();\n                        o_line.put(2);\n                        o_line.put(lineIds.get(key));\n                        o_line.put(false);\n                        order_line.put(o_line);\n                    }\n                }\n                Thread.sleep(500);\n                JSONObject data = new JSONObject();\n                data.put(\"name\", values.getString(\"name\"));\n                data.put(\"partner_id\", partner.selectServerId(values.getInt(\"partner_id\")));\n                data.put(\"date_order\", values.getString(\"date_order\"));\n                data.put(\"payment_term\", values.get(\"payment_term\"));\n                data.put(\"order_line\", order_line);\n\n                if (record == null) {\n                    runOnUiThread(new Runnable() {\n                        @Override\n                        public void run() {\n                            mDialog.setMessage(\"Creating \" + mSOType);\n                        }\n                    });\n                    Thread.sleep(500);\n                    int new_id = sale.getServerDataHelper().createOnServer(data);\n                    values.put(\"id\", new_id);\n                    ODataRow record = new ODataRow();\n                    record.put(\"id\", new_id);\n                    sale.quickCreateRecord(record);\n                    //sale.insert(values);\n                } else {\n                    runOnUiThread(new Runnable() {\n                        @Override\n                        public void run() {\n                            mDialog.setMessage(\"Updating \" + mSOType);\n                        }\n                    });\n                    Thread.sleep(500);\n                    sale.getServerDataHelper().updateOnServer(data, record.getInt(\"id\"));\n                    sale.quickCreateRecord(record);\n                }\n                return true;\n            } catch (Exception e) {\n                e.printStackTrace();\n            }\n            return false;\n        }\n\n        @Override\n        protected void onPostExecute(Boolean success) {\n            super.onPostExecute(success);\n            mDialog.dismiss();\n            if (success) {\n                Toast.makeText(SalesDetail.this, (record != null) ? mSOType + \" updated\"\n                        : mSOType + \" created\", Toast.LENGTH_LONG).show();\n                finish();\n            }\n        }\n    }\n\n    SaleOrder.OnOperationSuccessListener cancelOrder = new SaleOrder.OnOperationSuccessListener() {\n        @Override\n        public void OnSuccess() {\n            Toast.makeText(SalesDetail.this, StringUtils.capitalizeString(extra.getString(\"type\"))\n                    + \" cancelled\", Toast.LENGTH_LONG).show();\n            finish();\n        }\n\n        @Override\n        public void OnCancelled() {\n\n        }\n    };\n\n    SaleOrder.OnOperationSuccessListener confirmSale = new SaleOrder.OnOperationSuccessListener() {\n        @Override\n        public void OnSuccess() {\n            Toast.makeText(SalesDetail.this, R.string.label_quotation_confirm, Toast.LENGTH_LONG).show();\n            finish();\n        }\n\n        @Override\n        public void OnCancelled() {\n\n        }\n    };\n\n    @Override\n    public void onClick(View v) {\n        switch (v.getId()) {\n            case R.id.layoutAddItem:\n                if (mForm.getValues() != null) {\n                    Intent intent = new Intent(this, AddProductLineWizard.class);\n                    Bundle extra = new Bundle();\n                    for (String key : lineValues.keySet()) {\n                        extra.putFloat(key, lineValues.get(key));\n                    }\n                    intent.putExtras(extra);\n                    startActivityForResult(intent, REQUEST_ADD_ITEMS);\n                }\n                break;\n        }\n    }\n\n    private class OnCustomerChangeUpdate extends AsyncTask<ODataRow, Void, Void> {\n        private ProgressDialog progressDialog;\n\n        @Override\n        protected void onPreExecute() {\n            super.onPreExecute();\n            progressDialog = new ProgressDialog(SalesDetail.this);\n            progressDialog.setCancelable(false);\n            progressDialog.setTitle(R.string.title_please_wait);\n            progressDialog.setMessage(OResource.string(SalesDetail.this, R.string.title_working));\n            progressDialog.show();\n        }\n\n        @Override\n        protected Void doInBackground(ODataRow... params) {\n            sale.onPartnerIdChange(params[0]);\n            return null;\n        }\n\n        @Override\n        protected void onPostExecute(Void aVoid) {\n            super.onPostExecute(aVoid);\n            progressDialog.dismiss();\n        }\n    }\n\n    private class OnProductChange extends AsyncTask<HashMap<String, Float>, Void, List<ODataRow>> {\n        private ProgressDialog progressDialog;\n        private String warning = null;\n\n        @Override\n        protected void onPreExecute() {\n            super.onPreExecute();\n            progressDialog = new ProgressDialog(SalesDetail.this);\n            progressDialog.setCancelable(false);\n            progressDialog.setTitle(R.string.title_please_wait);\n            progressDialog.setMessage(OResource.string(SalesDetail.this, R.string.title_working));\n            progressDialog.show();\n        }\n\n        @Override\n        protected List<ODataRow> doInBackground(HashMap<String, Float>... params) {\n            List<ODataRow> items = new ArrayList<>();\n            try {\n                ProductProduct productProduct = new ProductProduct(SalesDetail.this, sale.getUser());\n                SalesOrderLine saleLine = new SalesOrderLine(SalesDetail.this, sale.getUser());\n                ResPartner partner = new ResPartner(SalesDetail.this, sale.getUser());\n                ODataRow customer = partner.browse(mForm.getValues().getInt(\"partner_id\"));\n                ServerDataHelper helper = saleLine.getServerDataHelper();\n                boolean stockInstalled = saleLine.isInstalledOnServer(\"stock\");\n                for (String key : params[0].keySet()) {\n                    ODataRow product = productProduct.browse(productProduct.selectRowId(Integer.parseInt(key)));\n                    Float qty = params[0].get(key);\n                    OArguments arguments = new OArguments();\n                    arguments.add(new JSONArray());\n                    int pricelist = customer.getInt(\"pricelist_id\");\n                    arguments.add(pricelist); // Price List for customer\n                    arguments.add(product.getInt(\"id\")); // product id\n                    arguments.add(qty); // Quantity\n                    arguments.add(false); // UOM\n                    arguments.add(qty); // Qty_UOS\n                    arguments.add(false);// UOS\n                    arguments.add((product.getString(\"name\").equals(\"false\")) ? false\n                            : product.getString(\"name\"));\n                    arguments.add(customer.getInt(\"id\")); // Partner id\n                    arguments.add(false); // lang\n                    arguments.add(true); // update_tax\n                    arguments.add((customer.getString(\"date_order\").equals(\"false\")) ? false\n                            : customer.getString(\"date_order\")); // date order\n                    arguments.add(false); // packaging\n                    Object fiscal_position = (customer.getString(\"fiscal_position\").equals(\"false\"))\n                            ? false : customer.getString(\"fiscal_position\");\n                    arguments.add(fiscal_position);// fiscal position\n                    arguments.add(false); // flag\n                    int version = saleLine.getOdooVersion().getVersion_number();\n                    if (stockInstalled && version > 7) {\n                        arguments.add(false);\n                    }\n                    JSONObject context = new JSONObject();\n                    context.put(\"partner_id\", customer.getInt(\"id\"));\n                    context.put(\"quantity\", qty);\n                    context.put(\"pricelist\", pricelist);\n\n                    // Fixed for Odoo 7.0 no product_id_change_with_wh available for v7\n                    String method = (stockInstalled && version > 7) ? \"product_id_change_with_wh\" : \"product_id_change\";\n                    JSONObject response = ((JSONObject) helper.callMethod(method, arguments, context));\n                    JSONObject res = response.getJSONObject(\"value\");\n                    if (response.has(\"warning\") && !response.getString(\"warning\").equals(\"false\")) {\n                        JSONObject warning_data = response.getJSONObject(\"warning\");\n                        if (warning_data.has(\"message\"))\n                            warning = warning_data.getString(\"message\");\n                    }\n                    OValues values = new OValues();\n                    values.put(\"product_id\", product.getInt(\"id\"));\n                    values.put(\"name\", res.get(\"name\"));\n                    values.put(\"product_uom_qty\", res.get(\"product_uos_qty\"));\n                    values.put(\"product_uom\", res.get(\"product_uom\"));\n                    values.put(\"price_unit\", res.get(\"price_unit\"));\n                    values.put(\"product_uos_qty\", res.getDouble(\"product_uos_qty\"));\n                    values.put(\"product_uos\", false);\n                    values.put(\"price_subtotal\", res.getDouble(\"price_unit\") * res.getDouble(\"product_uos_qty\"));\n                    JSONArray tax_id = new JSONArray();\n                    tax_id.put(6);\n                    tax_id.put(false);\n                    tax_id.put(res.getJSONArray(\"tax_id\"));\n                    values.put(\"tax_id\", new JSONArray().put(tax_id));\n                    values.put(\"th_weight\", (res.has(\"th_weight\")) ? res.get(\"th_weight\") : 0);\n                    values.put(\"discount\", (res.has(\"discount\")) ? res.get(\"discount\") : 0);\n                    if (stockInstalled) {\n                        values.put(\"route_id\", (res.has(\"route_id\")) ? res.get(\"route_id\") : false);\n                        values.put(\"delay\", res.get(\"delay\"));\n                    }\n                    if (extra != null)\n                        values.put(\"order_id\", extra.getInt(OColumn.ROW_ID));\n                    items.add(values.toDataRow());\n                }\n            } catch (Exception e) {\n                e.printStackTrace();\n            }\n            return items;\n        }\n\n        @Override\n        protected void onPostExecute(List<ODataRow> row) {\n            super.onPostExecute(row);\n            if (row != null) {\n                objects.clear();\n                objects.addAll(row);\n                mAdapter.notifyDataSetChanged(objects);\n                float total = 0.0f;\n                for (ODataRow rec : row) {\n                    total += rec.getFloat(\"price_subtotal\");\n                }\n                total_amt.setText(String.format(\"%.2f\", total));\n                untaxedAmt.setText(total_amt.getText());\n            }\n            progressDialog.dismiss();\n            if (warning != null) {\n                OAlert.showWarning(SalesDetail.this, warning.trim());\n            }\n        }\n    }\n\n    @Override\n    protected void onActivityResult(int requestCode, int resultCode, Intent data) {\n        super.onActivityResult(requestCode, resultCode, data);\n        if (requestCode == REQUEST_ADD_ITEMS && resultCode == Activity.RESULT_OK) {\n            lineValues.clear();\n            for (String key : data.getExtras().keySet()) {\n                if (data.getExtras().getFloat(key) > 0)\n                    lineValues.put(key, data.getExtras().getFloat(key));\n            }\n            OnProductChange onProductChange = new OnProductChange();\n            onProductChange.execute(lineValues);\n        }\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/addons/sale/models/AccountPaymentTerm.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 21/1/15 10:47 AM\n */\npackage com.odoo.addons.sale.models;\n\nimport android.content.Context;\n\nimport com.odoo.core.orm.OModel;\nimport com.odoo.core.orm.fields.OColumn;\nimport com.odoo.core.orm.fields.types.OBoolean;\nimport com.odoo.core.orm.fields.types.OVarchar;\nimport com.odoo.core.support.OUser;\n\npublic class AccountPaymentTerm extends OModel {\n    public static final String TAG = AccountPaymentTerm.class.getSimpleName();\n\n    OColumn name = new OColumn(\"Payment Term\", OVarchar.class);\n    OColumn active = new OColumn(\"Active\", OBoolean.class);\n\n    public AccountPaymentTerm(Context context, OUser user) {\n        super(context, \"account.payment.term\", user);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/addons/sale/models/ProductProduct.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 13/1/15 11:11 AM\n */\npackage com.odoo.addons.sale.models;\n\nimport android.content.Context;\n\nimport com.odoo.core.orm.OModel;\nimport com.odoo.core.orm.fields.OColumn;\nimport com.odoo.core.orm.fields.types.OBoolean;\nimport com.odoo.core.orm.fields.types.OInteger;\nimport com.odoo.core.orm.fields.types.OVarchar;\nimport com.odoo.core.support.OUser;\n\npublic class ProductProduct extends OModel {\n    public static final String TAG = ProductProduct.class.getSimpleName();\n    OColumn name_template = new OColumn(\"Name\", OVarchar.class).setSize(64);\n    OColumn default_code = new OColumn(\"Internal Reference\", OVarchar.class).setSize(64);\n    OColumn lst_price = new OColumn(\"Public price\", OInteger.class);\n    OColumn sale_ok = new OColumn(\"Stock OK\", OBoolean.class).setDefaultValue(false);\n\n    public ProductProduct(Context context, OUser user) {\n        super(context, \"product.product\", user);\n        setDefaultNameColumn(\"name_template\");\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/addons/sale/models/SaleOrder.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 13/1/15 11:06 AM\n */\npackage com.odoo.addons.sale.models;\n\nimport android.app.ProgressDialog;\nimport android.content.Context;\nimport android.net.Uri;\nimport android.os.AsyncTask;\n\nimport com.odoo.App;\nimport com.odoo.R;\nimport com.odoo.addons.sale.Sales;\nimport com.odoo.base.addons.res.ResCompany;\nimport com.odoo.base.addons.res.ResCurrency;\nimport com.odoo.base.addons.res.ResPartner;\nimport com.odoo.base.addons.res.ResUsers;\nimport com.odoo.core.orm.ODataRow;\nimport com.odoo.core.orm.OModel;\nimport com.odoo.core.orm.OValues;\nimport com.odoo.core.orm.ServerDataHelper;\nimport com.odoo.core.orm.annotation.Odoo;\nimport com.odoo.core.orm.fields.OColumn;\nimport com.odoo.core.orm.fields.types.ODate;\nimport com.odoo.core.orm.fields.types.ODateTime;\nimport com.odoo.core.orm.fields.types.OFloat;\nimport com.odoo.core.orm.fields.types.OInteger;\nimport com.odoo.core.orm.fields.types.OVarchar;\nimport com.odoo.core.support.OUser;\nimport com.odoo.core.utils.OResource;\n\nimport org.json.JSONArray;\nimport org.json.JSONObject;\n\nimport java.util.HashMap;\nimport java.util.List;\n\nimport odoo.OArguments;\n\npublic class SaleOrder extends OModel {\n    public static final String TAG = SaleOrder.class.getSimpleName();\n    public static final String AUTHORITY = \"com.odoo.core.crm.provider.content.sync.sale_order\";\n    private Context mContext;\n    OColumn name = new OColumn(\"name\", OVarchar.class);\n    OColumn date_order = new OColumn(\"Date\", ODateTime.class);\n    @Odoo.onChange(method = \"onPartnerIdChange\", bg_process = true)\n    OColumn partner_id = new OColumn(\"Customer\", ResPartner.class,\n            OColumn.RelationType.ManyToOne).setRequired();\n    OColumn user_id = new OColumn(\"Salesperson\", ResUsers.class,\n            OColumn.RelationType.ManyToOne);\n    OColumn amount_total = new OColumn(\"Total\", OFloat.class);\n    OColumn payment_term = new OColumn(\"Payment Term\", AccountPaymentTerm.class, OColumn.RelationType.ManyToOne);\n    OColumn amount_untaxed = new OColumn(\"Untaxed\", OInteger.class);\n    OColumn amount_tax = new OColumn(\"Tax\", OInteger.class);\n    OColumn client_order_ref = new OColumn(\"Client Order Reference\",\n            OVarchar.class).setSize(100);\n    OColumn state = new OColumn(\"status\", OVarchar.class).setSize(10)\n            .setDefaultValue(\"draft\");\n    @Odoo.Functional(method = \"getStateTitle\", store = true, depends = {\"state\"})\n    OColumn state_title = new OColumn(\"State Title\", OVarchar.class)\n            .setLocalColumn();\n    @Odoo.Functional(method = \"storePartnerName\", store = true, depends = {\"partner_id\"})\n    OColumn partner_name = new OColumn(\"State Title\", OVarchar.class)\n            .setLocalColumn();\n    OColumn currency_id = new OColumn(\"currency\", ResCurrency.class,\n            OColumn.RelationType.ManyToOne);\n    @Odoo.Functional(method = \"storeCurrencySymbol\", store = true, depends = {\"currency_id\"})\n    OColumn currency_symbol = new OColumn(\"State Title\", OVarchar.class)\n            .setLocalColumn();\n    OColumn order_line = new OColumn(\"Order Lines\", SalesOrderLine.class,\n            OColumn.RelationType.OneToMany).setRelatedColumn(\"order_id\");\n    @Odoo.Functional(method = \"countOrderLines\", store = true, depends = {\"order_line\"})\n    OColumn order_line_count = new OColumn(\"Total Lines\", OVarchar.class)\n            .setLocalColumn();\n\n    OColumn partner_invoice_id = new OColumn(\"partner_invoice_id\", OVarchar.class).setLocalColumn();\n    OColumn partner_shipping_id = new OColumn(\"partner_shipping_id\", OVarchar.class).setLocalColumn();\n    OColumn pricelist_id = new OColumn(\"pricelist_id\", OVarchar.class).setLocalColumn();\n    OColumn fiscal_position = new OColumn(\"fiscal_position\", OVarchar.class).setLocalColumn();\n\n    public SaleOrder(Context context, OUser user) {\n        super(context, \"sale.order\", user);\n        mContext = context;\n        setHasMailChatter(true);\n        if (getUser().getVersion_number() == 7) {\n            date_order.setType(ODate.class);\n        }\n\n    }\n\n    @Override\n    public Uri uri() {\n        return buildURI(AUTHORITY);\n    }\n\n    public ODataRow onPartnerIdChange(ODataRow row) {\n        ODataRow data = new ODataRow();\n        try {\n            ResPartner partner = new ResPartner(mContext, getUser());\n            AccountPaymentTerm term = new AccountPaymentTerm(mContext, getUser());\n            ODataRow customer = partner.browse(row.getInt(OColumn.ROW_ID));\n            App app = (App) mContext.getApplicationContext();\n            if (app.inNetwork()) {\n                ServerDataHelper helper = getServerDataHelper();\n                OArguments args = new OArguments();\n                args.add(new JSONArray());\n                args.add(customer.getInt(\"id\"));\n                JSONObject res = ((JSONObject) helper.callMethod(\"onchange_partner_id\", args, new JSONObject()))\n                        .getJSONObject(\"value\");\n                if (res.has(\"partner_invoice_id\"))\n                    data.put(\"partner_invoice_id\", res.get(\"partner_invoice_id\"));\n                if (res.has(\"partner_shipping_id\"))\n                    data.put(\"partner_shipping_id\", res.get(\"partner_shipping_id\"));\n                if (res.has(\"pricelist_id\"))\n                    data.put(\"pricelist_id\", res.get(\"pricelist_id\"));\n                if (res.has(\"payment_term\") && !res.getString(\"payment_term\").equals(\"false\"))\n                    data.put(\"payment_term\", term.selectRowId(res.getInt(\"payment_term\")));\n                if (res.has(\"fiscal_position\")) {\n                    data.put(\"fiscal_position\", res.get(\"fiscal_position\"));\n                }\n                partner.update(customer.getInt(OColumn.ROW_ID), data.toValues());\n            } else {\n                data.put(\"partner_invoice_id\", customer.get(\"partner_invoice_id\"));\n                data.put(\"partner_shipping_id\", customer.get(\"partner_shipping_id\"));\n                data.put(\"pricelist_id\", customer.get(\"pricelist_id\"));\n                data.put(\"payment_term\", customer.get(\"payment_term\"));\n                data.put(\"fiscal_position\", customer.get(\"fiscal_position\"));\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return data;\n    }\n\n    public ODataRow currency() {\n        ResCompany company = new ResCompany(mContext, getUser());\n        ODataRow row = company.browse(null, \"id = ? \", new String[]{getUser().getCompany_id()});\n        if (row != null && !row.getString(\"currency_id\").equals(\"false\")) {\n            return row.getM2ORecord(\"currency_id\").browse();\n        } else {\n            ResCurrency currency = new ResCurrency(mContext, getUser());\n            List<ODataRow> list = currency.select();\n            if (list.size() > 0) {\n                return list.get(0);\n            }\n        }\n        return null;\n    }\n\n    public String getStateTitle(OValues row) {\n        HashMap<String, String> mStates = new HashMap<String, String>();\n        mStates.put(\"draft\", \"Draft Quotation\");\n        mStates.put(\"sent\", \"Quotation Sent\");\n        mStates.put(\"cancel\", \"Cancelled\");\n        mStates.put(\"waiting_date\", \"Waiting Schedule\");\n        mStates.put(\"progress\", \"Sales Order\");\n        mStates.put(\"manual\", \"Sale to Invoice\");\n        mStates.put(\"shipping_except\", \"Shipping Exception\");\n        mStates.put(\"invoice_except\", \"Invoice Exception\");\n        mStates.put(\"done\", \"Done\");\n        return mStates.get(row.getString(\"state\"));\n    }\n\n    public String storeCurrencySymbol(OValues values) {\n        try {\n            if (!values.getString(\"currency_id\").equals(\"false\")) {\n                JSONArray currency_id = new JSONArray(values.getString(\"currency_id\"));\n                return currency_id.getString(1);\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return \"false\";\n    }\n\n    public String storePartnerName(OValues values) {\n        try {\n            if (!values.getString(\"partner_id\").equals(\"false\")) {\n                JSONArray partner_id = new JSONArray(values.getString(\"partner_id\"));\n                return partner_id.getString(1);\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return \"false\";\n    }\n\n    public String countOrderLines(OValues values) {\n        try {\n            JSONArray order_line = new JSONArray(values.getString(\"order_line\"));\n            if (order_line.length() > 0) {\n                return \" (\" + order_line.length() + \" lines)\";\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return \" (No lines)\";\n    }\n\n    public void cancelOrder(final Sales.Type type, final ODataRow quotation, final OnOperationSuccessListener listener) {\n        new AsyncTask<Void, Void, Void>() {\n            private ProgressDialog dialog;\n\n            @Override\n            protected void onPreExecute() {\n                super.onPreExecute();\n                dialog = new ProgressDialog(mContext);\n                dialog.setTitle(R.string.title_please_wait);\n                dialog.setMessage(OResource.string(mContext, R.string.title_working));\n                dialog.setCancelable(false);\n                dialog.show();\n            }\n\n            @Override\n            protected Void doInBackground(Void... params) {\n                try {\n                    if (type == Sales.Type.SaleOrder) {\n                        OArguments args = new OArguments();\n                        args.add(new JSONArray().put(quotation.getInt(\"id\")));\n                        args.add(new JSONObject());\n                        getServerDataHelper().callMethod(\"action_cancel\", args);\n                    } else {\n                        getServerDataHelper().executeWorkFlow(quotation.getInt(\"id\"), \"cancel\");\n                    }\n                    OValues values = new OValues();\n                    values.put(\"state\", \"cancel\");\n                    values.put(\"state_title\", getStateTitle(values));\n                    values.put(\"_is_dirty\", \"false\");\n                    update(quotation.getInt(OColumn.ROW_ID), values);\n                } catch (Exception e) {\n                    e.printStackTrace();\n                }\n                return null;\n            }\n\n            @Override\n            protected void onPostExecute(Void aVoid) {\n                super.onPostExecute(aVoid);\n                dialog.dismiss();\n                if (listener != null) {\n                    listener.OnSuccess();\n                }\n            }\n\n            @Override\n            protected void onCancelled() {\n                super.onCancelled();\n                dialog.dismiss();\n                if (listener != null) {\n                    listener.OnCancelled();\n                }\n            }\n        }.execute();\n    }\n\n    public void confirmSale(final ODataRow quotation, final OnOperationSuccessListener listener) {\n        new AsyncTask<Void, Void, Void>() {\n            private ProgressDialog dialog;\n\n            @Override\n            protected void onPreExecute() {\n                super.onPreExecute();\n                dialog = new ProgressDialog(mContext);\n                dialog.setTitle(R.string.title_please_wait);\n                dialog.setMessage(OResource.string(mContext, R.string.title_working));\n                dialog.setCancelable(false);\n                dialog.show();\n            }\n\n            @Override\n            protected Void doInBackground(Void... params) {\n                try {\n                    OArguments args = new OArguments();\n                    args.add(new JSONArray().put(quotation.getInt(\"id\")));\n                    args.add(new JSONObject());\n                    getServerDataHelper().callMethod(\"action_button_confirm\", args);\n                    OValues values = new OValues();\n                    values.put(\"state\", \"manual\");\n                    values.put(\"state_title\", getStateTitle(values));\n                    values.put(\"_is_dirty\", \"false\");\n                    update(quotation.getInt(OColumn.ROW_ID), values);\n                } catch (Exception e) {\n                    e.printStackTrace();\n                }\n                return null;\n            }\n\n            @Override\n            protected void onPostExecute(Void aVoid) {\n                super.onPostExecute(aVoid);\n                dialog.dismiss();\n                if (listener != null) {\n                    listener.OnSuccess();\n                }\n            }\n\n            @Override\n            protected void onCancelled() {\n                super.onCancelled();\n                dialog.dismiss();\n                if (listener != null) {\n                    listener.OnCancelled();\n                }\n            }\n        }.execute();\n    }\n\n    public void newCopyQuotation(final ODataRow quotation, final OnOperationSuccessListener listener) {\n        new AsyncTask<Void, Void, Void>() {\n            private ProgressDialog dialog;\n\n            @Override\n            protected void onPreExecute() {\n                super.onPreExecute();\n                dialog = new ProgressDialog(mContext);\n                dialog.setTitle(R.string.title_please_wait);\n                dialog.setMessage(OResource.string(mContext, R.string.title_working));\n                dialog.setCancelable(false);\n                dialog.show();\n            }\n\n            @Override\n            protected Void doInBackground(Void... params) {\n                try {\n                    OArguments args = new OArguments();\n                    args.add(new JSONArray().put(quotation.getInt(\"id\")));\n                    args.add(new JSONObject());\n                    getServerDataHelper().callMethod(\"copy_quotation\", args);\n                } catch (Exception e) {\n                    e.printStackTrace();\n                }\n                return null;\n            }\n\n            @Override\n            protected void onPostExecute(Void aVoid) {\n                super.onPostExecute(aVoid);\n                dialog.dismiss();\n                if (listener != null) {\n                    listener.OnSuccess();\n                }\n            }\n\n            @Override\n            protected void onCancelled() {\n                super.onCancelled();\n                dialog.dismiss();\n                if (listener != null) {\n                    listener.OnCancelled();\n                }\n            }\n        }.execute();\n    }\n\n    public static interface OnOperationSuccessListener {\n        public void OnSuccess();\n\n        public void OnCancelled();\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/addons/sale/models/SalesOrderLine.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 13/1/15 11:08 AM\n */\npackage com.odoo.addons.sale.models;\n\nimport android.content.Context;\n\nimport com.odoo.core.orm.OModel;\nimport com.odoo.core.orm.fields.OColumn;\nimport com.odoo.core.orm.fields.types.OFloat;\nimport com.odoo.core.orm.fields.types.OInteger;\nimport com.odoo.core.orm.fields.types.OText;\nimport com.odoo.core.support.OUser;\n\npublic class SalesOrderLine extends OModel {\n    public static final String TAG = SalesOrderLine.class.getSimpleName();\n    OColumn product_id = new OColumn(\"Product\", ProductProduct.class,\n            OColumn.RelationType.ManyToOne);\n    OColumn name = new OColumn(\"Description \", OText.class);\n    OColumn product_uom_qty = new OColumn(\"Quantity\", OInteger.class);\n    OColumn price_unit = new OColumn(\"Unit Price\", OFloat.class);\n    OColumn price_subtotal = new OColumn(\"Sub Total\", OFloat.class);\n    OColumn order_id = new OColumn(\"ID\", SaleOrder.class,\n            OColumn.RelationType.ManyToOne);\n\n    public SalesOrderLine(Context context, OUser user) {\n        super(context, \"sale.order.line\", user);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/addons/sale/providers/SaleOrderProvider.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 13/1/15 11:40 AM\n */\npackage com.odoo.addons.sale.providers;\n\nimport android.net.Uri;\n\nimport com.odoo.addons.sale.models.SaleOrder;\nimport com.odoo.core.orm.provider.BaseModelProvider;\n\npublic class SaleOrderProvider extends BaseModelProvider {\n    public static final String TAG = SaleOrderProvider.class.getSimpleName();\n\n    @Override\n    public void setModel(Uri uri) {\n        super.setModel(uri);\n        mModel = new SaleOrder(getContext(), getUser(uri));\n    }\n\n    @Override\n    public String authority() {\n        return SaleOrder.AUTHORITY;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/addons/sale/services/SaleOrderSyncService.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 13/1/15 11:40 AM\n */\npackage com.odoo.addons.sale.services;\n\nimport android.content.Context;\nimport android.content.SyncResult;\nimport android.os.Bundle;\n\nimport com.odoo.addons.sale.models.AccountPaymentTerm;\nimport com.odoo.addons.sale.models.SaleOrder;\nimport com.odoo.core.orm.ODataRow;\nimport com.odoo.core.service.ISyncFinishListener;\nimport com.odoo.core.service.OSyncAdapter;\nimport com.odoo.core.service.OSyncService;\nimport com.odoo.core.support.OUser;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport odoo.ODomain;\n\npublic class SaleOrderSyncService extends OSyncService implements ISyncFinishListener {\n    public static final String TAG = SaleOrderSyncService.class.getSimpleName();\n    public Boolean firstSync = false;\n\n    @Override\n    public OSyncAdapter getSyncAdapter(OSyncService service, Context context) {\n        return new OSyncAdapter(context, SaleOrder.class, service, true);\n    }\n\n    @Override\n    public void performDataSync(OSyncAdapter adapter, Bundle extras, OUser user) {\n        if (adapter.getModel().getModelName().equals(\"sale.order\")) {\n            ODomain domain = new ODomain();\n            SaleOrder saleOrder = new SaleOrder(getApplicationContext(), user);\n            List<Integer> newIds = new ArrayList<>();\n            for (ODataRow row : saleOrder.select(new String[]{}, \"name = ? and id != ?\", new String[]{\"/\", \"0\"})) {\n                newIds.add(row.getInt(\"id\"));\n            }\n            if (newIds.size() > 0) {\n                domain.add(\"id\", \"in\", newIds);\n            }\n            if (!firstSync)\n                adapter.onSyncFinish(this);\n            domain.add(\"user_id\", \"=\", user.getUser_id());\n            adapter.setDomain(domain).syncDataLimit(50);\n        }\n        if (adapter.getModel().getModelName().equals(\"account.payment.term\")) {\n            adapter.onSyncFinish(syncFinishListener);\n        }\n    }\n\n    @Override\n    public OSyncAdapter performNextSync(OUser user, SyncResult syncResult) {\n        return new OSyncAdapter(getApplicationContext(), AccountPaymentTerm.class, SaleOrderSyncService.this, true);\n    }\n\n    ISyncFinishListener syncFinishListener = new ISyncFinishListener() {\n        @Override\n        public OSyncAdapter performNextSync(OUser user, SyncResult syncResult) {\n            firstSync = true;\n            return new OSyncAdapter(getApplicationContext(), SaleOrder.class, SaleOrderSyncService.this, true);\n        }\n    };\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/base/addons/BaseModels.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 31/12/14 12:59 PM\n */\npackage com.odoo.base.addons;\n\nimport android.content.Context;\n\nimport com.odoo.base.addons.ir.IrAttachment;\nimport com.odoo.base.addons.ir.IrModel;\nimport com.odoo.base.addons.mail.MailMessage;\nimport com.odoo.base.addons.res.ResCompany;\nimport com.odoo.base.addons.res.ResPartner;\nimport com.odoo.base.addons.res.ResUsers;\nimport com.odoo.core.orm.OModel;\nimport com.odoo.core.support.OUser;\nimport com.odoo.news.models.OdooNews;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class BaseModels {\n    public static final String TAG = BaseModels.class.getSimpleName();\n\n    public static List<OModel> baseModels(Context context, OUser user) {\n        List<OModel> models = new ArrayList<>();\n        models.add(new OdooNews(context, user));\n        models.add(new IrModel(context, user));\n        models.add(new ResPartner(context, user));\n        models.add(new ResUsers(context, user));\n        models.add(new ResCompany(context, user));\n        models.add(new IrAttachment(context, user));\n        models.add(new MailMessage(context, user));\n        return models;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/base/addons/ir/IrAttachment.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 31/12/14 12:41 PM\n */\npackage com.odoo.base.addons.ir;\n\nimport android.content.Context;\n\nimport com.odoo.base.addons.res.ResCompany;\nimport com.odoo.core.orm.OModel;\nimport com.odoo.core.orm.OValues;\nimport com.odoo.core.orm.fields.OColumn;\nimport com.odoo.core.orm.fields.types.OInteger;\nimport com.odoo.core.orm.fields.types.OText;\nimport com.odoo.core.orm.fields.types.OVarchar;\nimport com.odoo.core.support.OUser;\n\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport odoo.ODomain;\n\npublic class IrAttachment extends OModel {\n    public static final String TAG = IrAttachment.class.getSimpleName();\n\n    OColumn name = new OColumn(\"Name\", OVarchar.class);\n    OColumn datas_fname = new OColumn(\"Data file name\", OText.class);\n    OColumn file_size = new OColumn(\"File Size\", OInteger.class);\n    OColumn res_model = new OColumn(\"Model\", OVarchar.class).setSize(100);\n    OColumn file_type = new OColumn(\"Content Type\", OVarchar.class).setSize(100);\n    OColumn company_id = new OColumn(\"Company\", ResCompany.class,\n            OColumn.RelationType.ManyToOne);\n    OColumn res_id = new OColumn(\"Resource id\", OInteger.class).setDefaultValue(0);\n    OColumn scheme = new OColumn(\"File Scheme\", OVarchar.class).setSize(100)\n            .setLocalColumn();\n    // Local Column\n    OColumn file_uri = new OColumn(\"File URI\", OVarchar.class).setSize(150)\n            .setLocalColumn().setDefaultValue(false);\n    OColumn type = new OColumn(\"Type\", OText.class).setLocalColumn();\n\n    public IrAttachment(Context context, OUser user) {\n        super(context, \"ir.attachment\", user);\n    }\n\n    public boolean createAttachment(OValues value, String rel_model, int res_id) {\n        OValues values = new OValues();\n        values.put(\"name\", value.get(\"name\"));\n        values.put(\"datas_fname\", value.getString(\"name\"));\n        values.put(\"file_size\", value.get(\"file_size\"));\n        values.put(\"file_type\", value.get(\"file_type\"));\n        values.put(\"company_id\", getUser().getCompany_id());\n        values.put(\"res_id\", res_id);\n        values.put(\"res_model\", rel_model);\n        values.put(\"file_uri\", value.getString(\"file_uri\"));\n        values.put(\"type\", value.getString(\"file_type\"));\n        values.put(\"id\", value.get(\"id\"));\n        insert(values);\n        return true;\n    }\n\n    public static JSONObject valuesToData(OModel model, OValues value) {\n        JSONObject data = new JSONObject();\n        try {\n            data.put(\"name\", value.get(\"name\"));\n            data.put(\"db_datas\", value.getString(\"datas\"));\n            data.put(\"datas_fname\", value.get(\"name\"));\n            data.put(\"file_size\", value.get(\"file_size\"));\n            data.put(\"res_model\", false);\n            data.put(\"res_id\", false);\n            data.put(\"file_type\", value.get(\"file_type\"));\n            data.put(\"company_id\", model.getUser().getCompany_id());\n            return data;\n        } catch (JSONException e) {\n            e.printStackTrace();\n        }\n        return null;\n    }\n\n    public String getDatasFromServer(Integer row_id) {\n        try {\n            ODomain domain = new ODomain();\n            domain.add(\"id\", \"=\", selectServerId(row_id));\n            JSONObject fields = new JSONObject();\n            fields.accumulate(\"fields\", \"datas\");\n            JSONObject result = getServerDataHelper().getOdoo().search_read(getModelName(), fields,\n                    domain.get());\n            if (result.getJSONArray(\"records\").length() > 0) {\n                JSONObject row = result.getJSONArray(\"records\")\n                        .getJSONObject(0);\n                return row.getString(\"datas\");\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return \"false\";\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/base/addons/ir/IrModel.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 2/1/15 3:18 PM\n */\npackage com.odoo.base.addons.ir;\n\nimport android.content.Context;\nimport android.net.Uri;\nimport android.util.Log;\n\nimport com.odoo.core.orm.OModel;\nimport com.odoo.core.orm.OValues;\nimport com.odoo.core.orm.fields.OColumn;\nimport com.odoo.core.orm.fields.types.ODateTime;\nimport com.odoo.core.orm.fields.types.OVarchar;\nimport com.odoo.core.support.OUser;\nimport com.odoo.core.utils.ODateUtils;\n\nimport java.util.Calendar;\nimport java.util.Date;\n\npublic class IrModel extends OModel {\n    public static final String TAG = IrModel.class.getSimpleName();\n    public static final String AUTHORITY = \"com.odoo.crm.core.provider.content.sync.ir_model\";\n    OColumn name = new OColumn(\"Model Description\", OVarchar.class).setSize(100);\n    OColumn model = new OColumn(\"Model\", OVarchar.class).setSize(100);\n    OColumn state = new OColumn(\"State\", OVarchar.class).setSize(64);\n\n    OColumn last_synced = new OColumn(\"Last Synced on \", ODateTime.class)\n            .setLocalColumn();\n\n    public IrModel(Context context, OUser user) {\n        super(context, \"ir.model\", user);\n    }\n\n    @Override\n    public Uri uri() {\n        return buildURI(AUTHORITY);\n    }\n\n    @Override\n    public boolean checkForCreateDate() {\n        return false;\n    }\n\n    @Override\n    public boolean checkForWriteDate() {\n        return false;\n    }\n\n    public void setLastSyncDateTimeToNow(OModel model) {\n        Log.i(TAG, \"Model Sync Update : \" + model.getModelName());\n        OValues values = new OValues();\n        values.put(\"model\", model.getModelName());\n        Date last_sync = ODateUtils.createDateObject(ODateUtils.getUTCDate(), ODateUtils.DEFAULT_FORMAT, true);\n        Calendar cal = Calendar.getInstance();\n        cal.setTime(last_sync);\n        /*\n                Fixed for Postgres SQL\n                It stores milliseconds so comparing date wrong.\n             */\n        cal.set(Calendar.SECOND, cal.get(Calendar.SECOND) + 2);\n        last_sync = cal.getTime();\n        values.put(\"last_synced\", ODateUtils.getDate(last_sync, ODateUtils.DEFAULT_FORMAT));\n        insertOrUpdate(\"model = ?\", new String[]{model.getModelName()}, values);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/base/addons/ir/feature/OFileManager.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 16/1/15 3:36 PM\n */\npackage com.odoo.base.addons.ir.feature;\n\nimport android.annotation.TargetApi;\nimport android.app.Activity;\nimport android.app.AlertDialog;\nimport android.content.ActivityNotFoundException;\nimport android.content.ContentResolver;\nimport android.content.ContentValues;\nimport android.content.Context;\nimport android.content.DialogInterface;\nimport android.content.Intent;\nimport android.database.Cursor;\nimport android.graphics.Bitmap;\nimport android.net.Uri;\nimport android.os.AsyncTask;\nimport android.os.Build;\nimport android.provider.DocumentsContract;\nimport android.provider.MediaStore;\nimport android.provider.OpenableColumns;\nimport android.util.Base64;\nimport android.webkit.MimeTypeMap;\nimport android.widget.Toast;\n\nimport com.odoo.App;\nimport com.odoo.R;\nimport com.odoo.base.addons.ir.IrAttachment;\nimport com.odoo.core.orm.ODataRow;\nimport com.odoo.core.orm.OValues;\nimport com.odoo.core.orm.fields.OColumn;\nimport com.odoo.core.utils.BitmapUtils;\nimport com.odoo.core.utils.OAlert;\nimport com.odoo.core.utils.OResource;\nimport com.odoo.core.utils.OStorageUtils;\nimport com.odoo.core.utils.notification.ONotificationBuilder;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.InputStream;\nimport java.net.FileNameMap;\nimport java.net.URLConnection;\n\nimport static android.widget.Toast.LENGTH_SHORT;\nimport static android.widget.Toast.makeText;\n\npublic class OFileManager implements DialogInterface.OnClickListener {\n    public static final String TAG = OFileManager.class.getSimpleName();\n    public static final int REQUEST_CAMERA = 111;\n    public static final int REQUEST_IMAGE = 112;\n    public static final int REQUEST_AUDIO = 113;\n    public static final int REQUEST_FILE = 114;\n    public static final int REQUEST_ALL_FILE = 115;\n    private static final int SINGLE_ATTACHMENT_STREAM = 115;\n    private static final long IMAGE_MAX_SIZE = 1000000; // 1 MB\n    private Context mContext = null;\n    private String[] mOptions = null;\n    private RequestType requestType = null;\n    private Uri newImageUri = null;\n    private IrAttachment irAttachment = null;\n    private App mApp;\n\n    public enum RequestType {\n        CAPTURE_IMAGE, IMAGE, IMAGE_OR_CAPTURE_IMAGE, AUDIO, FILE, ALL_FILE_TYPE\n    }\n\n    public OFileManager(Context context) {\n        mContext = context;\n        irAttachment = new IrAttachment(context, null);\n        mApp = (App) mContext.getApplicationContext();\n    }\n\n    public void downloadAttachment(int attachment_id) {\n        ODataRow attachment = irAttachment.browse(attachment_id);\n        if (attachment != null) {\n            String uri = attachment.getString(\"file_uri\");\n            if (uri.equals(\"false\")) {\n                // Downloading new file\n                _download(attachment);\n            } else {\n                Uri file_uri = Uri.parse(uri);\n                if (fileExists(file_uri)) {\n                    requestIntent(file_uri);\n                } else if (atLeastKitKat()) {\n                    String file_path = getDocPath(file_uri);\n                    if (file_path != null) {\n                        file_uri = Uri.fromFile(new File(file_path));\n                        requestIntent(file_uri);\n                    } else if (attachment.getInt(\"id\") != 0) {\n                        // Downloading new file\n                        _download(attachment);\n                    } else {\n                        // Failed to get file\n                        OAlert.showAlert(mContext, \"Unable to find file !\");\n                    }\n                } else if (fileExists(file_uri)) {\n                    requestIntent(file_uri);\n                } else {\n                    // Failed to get file\n                    OAlert.showAlert(mContext, \"Unable to find file !\");\n                }\n            }\n        }\n    }\n\n\n    private void _download(ODataRow attachment) {\n        ONotificationBuilder builder = new ONotificationBuilder(mContext,\n                attachment.getInt(OColumn.ROW_ID));\n        builder.setTitle(\"Downloading \" + attachment.getString(\"name\"));\n        builder.setText(\"Download in progress\");\n        builder.setOngoing(true);\n        builder.setAutoCancel(true);\n        DownloadManager downloader = new DownloadManager(builder);\n        downloader.execute(attachment);\n    }\n\n    private class DownloadManager extends AsyncTask<ODataRow, Void, ODataRow> {\n\n        ONotificationBuilder notificationBuilder;\n\n        public DownloadManager(ONotificationBuilder builder) {\n            notificationBuilder = builder;\n        }\n\n        @Override\n        protected void onPreExecute() {\n            super.onPreExecute();\n            notificationBuilder.allowVibrate(false);\n            notificationBuilder.withRingTone(false);\n            notificationBuilder.setProgress(0, 0, true);\n            notificationBuilder.build().show();\n        }\n\n        @Override\n        protected ODataRow doInBackground(ODataRow... params) {\n            if (mApp.inNetwork()) {\n                try {\n                    Thread.sleep(500);\n                    ODataRow attachment = params[0];\n                    String base64 = irAttachment.getDatasFromServer(attachment.getInt(OColumn.ROW_ID));\n                    if (!base64.equals(\"false\")) {\n                        String file = createFile(attachment.getString(\"name\"),\n                                Base64.decode(base64, 0)\n                                , attachment.getString(\"file_type\"));\n                        Uri uri = Uri.fromFile(new File(file));\n                        OValues values = new OValues();\n                        values.put(\"file_uri\", uri.toString());\n                        irAttachment.update(attachment.getInt(OColumn.ROW_ID), values);\n                        return irAttachment.browse(attachment.getInt(OColumn.ROW_ID));\n                    }\n                } catch (Exception e) {\n                    e.printStackTrace();\n                }\n            }\n            return null;\n        }\n\n        @Override\n        protected void onPostExecute(ODataRow row) {\n            super.onPostExecute(row);\n            ONotificationBuilder.cancelNotification(mContext, row.getInt(OColumn.ROW_ID));\n            if (row != null) {\n                ONotificationBuilder builder = new ONotificationBuilder(mContext,\n                        row.getInt(OColumn.ROW_ID));\n                builder.allowVibrate(true);\n                builder.withRingTone(true);\n                builder.setTitle(row.getString(\"name\"));\n                builder.setText(\"Download Complete\");\n                builder.setBigText(\"Download Complete\");\n                if (row.getString(\"file_type\").contains(\"image\")) {\n                    Bitmap bmp = getBitmapFromURI(Uri.parse(row.getString(\"file_uri\")));\n                    builder.setBigPicture(bmp);\n                }\n                Intent intent = new Intent(Intent.ACTION_VIEW);\n                intent.setDataAndType(Uri.parse(row.getString(\"file_uri\")), row.getString(\"file_type\"));\n                builder.setResultIntent(intent);\n                builder.build().show();\n            }\n        }\n    }\n\n    private String createFile(String name, byte[] fileAsBytes, String file_type) {\n\n        InputStream is = new ByteArrayInputStream(fileAsBytes);\n        String filename = name.replaceAll(\"[-+^:=, ]\", \"_\");\n        String file_path = OStorageUtils.getDirectoryPath(file_type) + \"/\" + filename;\n        try {\n            FileOutputStream fos = new FileOutputStream(file_path);\n            byte data[] = new byte[1024];\n            int count = 0;\n            while ((count = is.read(data)) != -1) {\n                fos.write(data, 0, count);\n            }\n            is.close();\n            fos.close();\n\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return file_path;\n    }\n\n    private void requestIntent(Uri uri) {\n        Intent intent = new Intent(Intent.ACTION_VIEW);\n        FileNameMap mime = URLConnection.getFileNameMap();\n        String mimeType = mime.getContentTypeFor(uri.getPath());\n        intent.setDataAndType(uri, mimeType);\n        try {\n            mContext.startActivity(intent);\n        } catch (ActivityNotFoundException e) {\n            Toast.makeText(mContext, OResource.string(mContext, R.string.toast_no_activity_found_to_handle_file),\n                    Toast.LENGTH_LONG).show();\n        }\n    }\n\n\n    private boolean fileExists(Uri uri) {\n        return new File(uri.getPath()).exists();\n    }\n\n    public Bitmap getBitmapFromURI(Uri uri) {\n        Bitmap bitmap;\n        if (!fileExists(uri) && atLeastKitKat()) {\n            String path = getDocPath(uri);\n            bitmap = BitmapUtils.getBitmapImage(mContext,\n                    BitmapUtils.uriToBase64(Uri.fromFile(new File(path)), mContext.getContentResolver()));\n        } else {\n            bitmap = BitmapUtils.getBitmapImage(mContext,\n                    BitmapUtils.uriToBase64(uri, mContext.getContentResolver()));\n        }\n        return bitmap;\n    }\n\n    @TargetApi(Build.VERSION_CODES.KITKAT)\n    public String getDocPath(Uri uri) {\n        String wholeID = DocumentsContract.getDocumentId(uri);\n        String id = wholeID.split(\":\")[1];\n        String[] column = {MediaStore.Images.Media.DATA};\n        String sel = MediaStore.Images.Media._ID + \"=?\";\n        Cursor cursor = mContext.getContentResolver().query(\n                MediaStore.Images.Media.EXTERNAL_CONTENT_URI, column, sel,\n                new String[]{id}, null);\n        String filePath = null;\n        int columnIndex = cursor.getColumnIndex(column[0]);\n        if (cursor.moveToFirst()) {\n            filePath = cursor.getString(columnIndex);\n        }\n        cursor.close();\n        return filePath;\n    }\n\n    public boolean atLeastKitKat() {\n        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;\n    }\n\n    public void requestForFile(RequestType type) {\n        Intent intent = new Intent();\n        intent.setAction(Intent.ACTION_GET_CONTENT);\n        switch (type) {\n            case AUDIO:\n                intent.setType(\"audio/*\");\n                requestIntent(intent, REQUEST_AUDIO);\n                break;\n            case IMAGE:\n                if (Build.VERSION.SDK_INT < 19) {\n                    intent = new Intent();\n                    intent.setAction(Intent.ACTION_GET_CONTENT);\n                } else {\n                    intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);\n                    intent.addCategory(Intent.CATEGORY_OPENABLE);\n                }\n                intent.setType(\"image/*\");\n                requestIntent(intent, REQUEST_IMAGE);\n                break;\n            case CAPTURE_IMAGE:\n                ContentValues values = new ContentValues();\n                values.put(MediaStore.Images.Media.TITLE, \"Odoo Mobile Attachment\");\n                values.put(MediaStore.Images.Media.DESCRIPTION,\n                        \"Captured from Odoo Mobile App\");\n                newImageUri = mContext.getContentResolver().insert(\n                        MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);\n                intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);\n                intent.putExtra(MediaStore.EXTRA_OUTPUT, newImageUri);\n                requestIntent(intent, REQUEST_CAMERA);\n                break;\n            case IMAGE_OR_CAPTURE_IMAGE:\n                requestDialog(type);\n                break;\n            case FILE:\n                intent.setType(\"application/*\");\n                requestIntent(intent, REQUEST_FILE);\n                break;\n            case ALL_FILE_TYPE:\n                intent.setType(\"*/*\");\n                requestIntent(intent, REQUEST_ALL_FILE);\n                break;\n        }\n    }\n\n    public OValues getURIDetails(Uri uri) {\n        OValues values = new OValues();\n        ContentResolver mCR = mContext.getContentResolver();\n        if (uri.getScheme().equals(\"content\")) {\n            Cursor cr = mCR.query(uri, null, null, null, null);\n            int nameIndex = cr.getColumnIndex(OpenableColumns.DISPLAY_NAME);\n            int fileSize = cr.getColumnIndex(OpenableColumns.SIZE);\n            if (cr.moveToFirst()) {\n                values.put(\"name\", cr.getString(nameIndex));\n                values.put(\"datas_fname\", values.get(\"name\"));\n                values.put(\"file_size\", Long.toString(cr.getLong(fileSize)));\n                String path = getPath(uri);\n                if (path != null) {\n                    values.put(\"file_size\", new File(path).length() + \"\");\n                }\n            }\n        }\n        if (uri.getScheme().equals(\"file\")) {\n            File file = new File(uri.toString());\n            values.put(\"name\", file.getName());\n            values.put(\"datas_fname\", values.get(\"name\"));\n            values.put(\"file_size\", Long.toString(file.length()));\n        }\n        values.put(\"file_uri\", uri.toString());\n        values.put(\"scheme\", uri.getScheme());\n        MimeTypeMap mime = MimeTypeMap.getSingleton();\n        String type = mime.getMimeTypeFromExtension(mime\n                .getExtensionFromMimeType(mCR.getType(uri)));\n        values.put(\"file_type\", (type == null) ? uri.getScheme() : type);\n        values.put(\"type\", type);\n        return values;\n    }\n\n    public String getPath(Uri uri) {\n        ContentResolver mCR = mContext.getContentResolver();\n        String[] projection = {MediaStore.Images.Media.DATA};\n        Cursor cursor = mCR.query(uri, projection, null, null, null);\n        if (cursor == null) return null;\n        int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);\n        cursor.moveToFirst();\n        String s = cursor.getString(column_index);\n        cursor.close();\n        return s;\n    }\n\n    public OValues handleResult(int requestCode, int resultCode, Intent data) {\n        if (resultCode == Activity.RESULT_OK) {\n            switch (requestCode) {\n                case REQUEST_CAMERA:\n                    OValues values = getURIDetails(newImageUri);\n                    values.put(\"datas\", BitmapUtils.uriToBase64(newImageUri,\n                            mContext.getContentResolver(), true));\n                    return values;\n                case REQUEST_IMAGE:\n                    values = getURIDetails(data.getData());\n                    values.put(\"datas\", BitmapUtils.uriToBase64(data.getData(),\n                            mContext.getContentResolver(), true));\n                    return values;\n                case REQUEST_ALL_FILE:\n                default:\n                    return getURIDetails(data.getData());\n            }\n        }\n        return null;\n    }\n\n    private void requestIntent(Intent intent, int requestCode) {\n        try {\n            ((Activity) mContext).startActivityForResult(intent, requestCode);\n        } catch (ActivityNotFoundException e) {\n            makeText(mContext, \"No Activity Found to handle request\",\n                    LENGTH_SHORT).show();\n        }\n    }\n\n    private void requestDialog(RequestType type) {\n        AlertDialog.Builder builder = new AlertDialog.Builder(mContext);\n        switch (type) {\n            case IMAGE_OR_CAPTURE_IMAGE:\n                requestType = type;\n                mOptions = new String[]{\"Select Image\", \"Capture Image\"};\n                break;\n        }\n        builder.setSingleChoiceItems(mOptions, -1, this);\n        builder.create().show();\n    }\n\n    @Override\n    public void onClick(DialogInterface dialog, int which) {\n        switch (requestType) {\n            case IMAGE_OR_CAPTURE_IMAGE:\n                requestForFile((which == 0) ? RequestType.IMAGE : RequestType.CAPTURE_IMAGE);\n                break;\n        }\n        dialog.dismiss();\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/base/addons/ir/providers/IrModelProvider.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 6/2/15 10:05 AM\n */\npackage com.odoo.base.addons.ir.providers;\n\nimport android.net.Uri;\n\nimport com.odoo.base.addons.ir.IrModel;\nimport com.odoo.core.orm.provider.BaseModelProvider;\n\npublic class IrModelProvider extends BaseModelProvider {\n    public static final String TAG = IrModelProvider.class.getSimpleName();\n\n    @Override\n    public void setModel(Uri uri) {\n        mModel = new IrModel(getContext(), getUser(uri));\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/base/addons/mail/MailMessage.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 25/2/15 11:49 AM\n */\npackage com.odoo.base.addons.mail;\n\nimport android.content.Context;\n\nimport com.odoo.base.addons.ir.IrAttachment;\nimport com.odoo.base.addons.res.ResPartner;\nimport com.odoo.core.orm.ODataRow;\nimport com.odoo.core.orm.OModel;\nimport com.odoo.core.orm.OValues;\nimport com.odoo.core.orm.annotation.Odoo;\nimport com.odoo.core.orm.fields.OColumn;\nimport com.odoo.core.orm.fields.types.OBoolean;\nimport com.odoo.core.orm.fields.types.ODateTime;\nimport com.odoo.core.orm.fields.types.OInteger;\nimport com.odoo.core.orm.fields.types.OText;\nimport com.odoo.core.orm.fields.types.OVarchar;\nimport com.odoo.core.support.OUser;\n\nimport org.json.JSONArray;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class MailMessage extends OModel {\n    public static final String TAG = MailMessage.class.getSimpleName();\n    OColumn author_id = new OColumn(\"Author\", ResPartner.class, OColumn.RelationType.ManyToOne);\n    OColumn email_from = new OColumn(\"Email From\", OVarchar.class).setDefaultValue(\"false\");\n    OColumn subject = new OColumn(\"Subject\", OVarchar.class).setSize(100);\n    OColumn body = new OColumn(\"Body\", OText.class);\n    OColumn date = new OColumn(\"Date\", ODateTime.class);\n    OColumn record_name = new OColumn(\"Record Name\", OVarchar.class).setSize(150);\n    OColumn model = new OColumn(\"Model\", OVarchar.class).setDefaultValue(\"false\");\n    OColumn res_id = new OColumn(\"Resource Id\", OInteger.class).setDefaultValue(0);\n    OColumn attachment_ids = new OColumn(\"Attachments\", IrAttachment.class,\n            OColumn.RelationType.ManyToMany);\n    OColumn type = new OColumn(\"Type\", OVarchar.class);\n    OColumn subtype_id = new OColumn(\"Subtype\", MailMessageSubType.class, OColumn.RelationType.ManyToOne);\n    @Odoo.Functional(method = \"authorName\", depends = {\"author_id\", \"email_from\"}, store = true)\n    OColumn author_name = new OColumn(\"Author Name\", OVarchar.class).setLocalColumn();\n\n    @Odoo.Functional(method = \"hasAttachment\", depends = {\"attachment_ids\"}, store = true)\n    OColumn has_attachments = new OColumn(\"Has Attachments\", OBoolean.class).setLocalColumn()\n            .setDefaultValue(false);\n\n    public MailMessage(Context context, OUser user) {\n        super(context, \"mail.message\", user);\n    }\n\n    public boolean hasAttachment(OValues values) {\n        try {\n            JSONArray attachment_ids = (JSONArray) values.get(\"attachment_ids\");\n            if (attachment_ids.length() > 0) {\n                return true;\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return false;\n    }\n\n    public String authorName(OValues values) {\n        try {\n            if (!values.getString(\"author_id\").equals(\"false\")) {\n                JSONArray author_id = new JSONArray(values.getString(\"author_id\"));\n                return author_id.getString(1);\n            } else {\n                return values.getString(\"email_from\");\n            }\n        } catch (Exception e) {\n\n        }\n        return \"\";\n    }\n\n    public String getAuthorImage(int row_id) {\n        ODataRow row = browse(new String[]{\"author_id\"}, row_id);\n        if (row.getInt(\"author_id\") != 0) {\n            ODataRow author_id = row.getM2ORecord(\"author_id\").browse();\n            return author_id.getString(\"image_small\");\n        }\n        return \"false\";\n    }\n\n    public List<Integer> getServerIds(String model, int res_server_id) {\n        List<Integer> ids = new ArrayList<>();\n        for (ODataRow row : select(new String[]{}, \"model = ? and res_id = ?\",\n                new String[]{model, res_server_id + \"\"})) {\n            ids.add(row.getInt(\"id\"));\n        }\n        return ids;\n    }\n\n    @Override\n    public boolean checkForWriteDate() {\n        return false;\n    }\n\n    @Override\n    public boolean allowCreateRecordOnServer() {\n        return false;\n    }\n\n    @Override\n    public boolean allowDeleteRecordOnServer() {\n        return false;\n    }\n\n    @Override\n    public boolean allowUpdateRecordOnServer() {\n        return false;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/base/addons/mail/MailMessageSubType.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 27/3/15 12:33 PM\n */\npackage com.odoo.base.addons.mail;\n\nimport android.content.Context;\n\nimport com.odoo.core.orm.OModel;\nimport com.odoo.core.orm.fields.OColumn;\nimport com.odoo.core.orm.fields.types.OVarchar;\nimport com.odoo.core.support.OUser;\n\npublic class MailMessageSubType extends OModel {\n    public static final String TAG = MailMessageSubType.class.getSimpleName();\n\n    OColumn name = new OColumn(\"Name\", OVarchar.class);\n\n    public MailMessageSubType(Context context, OUser user) {\n        super(context, \"mail.message.subtype\", user);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/base/addons/mail/widget/MailChatterCompose.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 27/2/15 5:53 PM\n */\npackage com.odoo.base.addons.mail.widget;\n\nimport android.app.ProgressDialog;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.net.Uri;\nimport android.os.AsyncTask;\nimport android.os.Bundle;\nimport android.support.v7.app.ActionBarActivity;\nimport android.text.TextUtils;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.EditText;\nimport android.widget.ImageView;\nimport android.widget.LinearLayout;\nimport android.widget.TextView;\n\nimport com.odoo.R;\nimport com.odoo.base.addons.ir.IrAttachment;\nimport com.odoo.base.addons.ir.feature.OFileManager;\nimport com.odoo.base.addons.mail.MailMessage;\nimport com.odoo.base.addons.res.ResPartner;\nimport com.odoo.core.orm.ODataRow;\nimport com.odoo.core.orm.OModel;\nimport com.odoo.core.orm.OValues;\nimport com.odoo.core.orm.fields.OColumn;\nimport com.odoo.core.utils.BitmapUtils;\nimport com.odoo.core.utils.JSONUtils;\nimport com.odoo.core.utils.OControls;\nimport com.odoo.core.utils.OResource;\nimport com.odoo.core.utils.OStringColorUtil;\nimport com.odoo.core.utils.logger.OLog;\n\nimport org.json.JSONArray;\nimport org.json.JSONObject;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport odoo.OArguments;\n\npublic class MailChatterCompose extends ActionBarActivity implements View.OnClickListener {\n    public static final String TAG = MailChatterCompose.class.getSimpleName();\n    private OModel mModel;\n    private IrAttachment irAttachment;\n    private int server_id = -1;\n    private int partner_id = -1;\n    private OFileManager fileManager;\n    private LinearLayout horizontalScrollView;\n    private List<Integer> attachmentIds = new ArrayList<>();\n\n    public enum MessageType {\n        Message, InternalNote\n    }\n\n    private MessageType mType = MessageType.Message;\n    private View parent;\n    private MailMessage mailMessage;\n    private EditText edtSubject, edtBody;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.base_mail_chatter_message_compose);\n        getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);\n        getSupportActionBar().hide();\n        fileManager = new OFileManager(this);\n        Bundle extra = getIntent().getExtras();\n        mType = MessageType.valueOf(extra.getString(\"type\"));\n        mModel = OModel.get(this, extra.getString(\"model\"), null);\n        irAttachment = new IrAttachment(this, null);\n        mailMessage = new MailMessage(this, null);\n        server_id = extra.getInt(\"server_id\");\n        if (mModel.getModelName().equals(\"res.partner\")) {\n            partner_id = server_id;\n        } else {\n            ODataRow row = mModel.browse(mModel.selectRowId(server_id));\n            for (OColumn col : mModel.getColumns(false)) {\n                if (col.getType().isAssignableFrom(ResPartner.class)) {\n                    if (col.getRelationType() != null\n                            && col.getRelationType() == OColumn.RelationType.ManyToOne) {\n                        ODataRow partner = null;\n                        if (!row.getString(col.getName()).equals(\"false\")) {\n                            partner = row.getM2ORecord(col.getName()).browse();\n                        }\n                        if (partner != null && partner.getInt(\"id\") != 0) {\n                            partner_id = partner.getInt(\"id\");\n                        }\n                    }\n                }\n            }\n        }\n        findViewById(R.id.btnAttachment).setOnClickListener(this);\n        findViewById(R.id.btnSend).setOnClickListener(this);\n        findViewById(R.id.btnCancel).setOnClickListener(this);\n        edtSubject = (EditText) findViewById(R.id.messageSubject);\n        edtBody = (EditText) findViewById(R.id.messageBody);\n        horizontalScrollView = (LinearLayout) findViewById(R.id.attachmentsList);\n        init();\n    }\n\n    private void init() {\n        TextView recordName = (TextView) findViewById(R.id.recordName);\n        parent = (View) recordName.getParent().getParent();\n        ODataRow record = mModel.browse(mModel.selectRowId(server_id));\n        String name = record.getString(mModel.getDefaultNameColumn());\n        findViewById(R.id.dialogHeader)\n                .setBackgroundColor(OStringColorUtil.getStringColor(this, name));\n        if (mType == MessageType.Message) {\n            edtSubject.setText(\"Re: \" + name);\n            recordName.setText(String.format(OResource.string(this, R.string.message_to), name));\n        } else {\n            recordName.setText(R.string.add_internal_note);\n            edtSubject.setVisibility(View.GONE);\n            edtBody.setHint(R.string.internal_note_hint);\n            OControls.setText(parent, R.id.btnSend, R.string.label_log_note);\n        }\n        edtBody.requestFocus();\n    }\n\n    @Override\n    public void onClick(View v) {\n        switch (v.getId()) {\n            case R.id.btnSend:\n                sendMessage();\n                break;\n            case R.id.btnCancel:\n                finish();\n                break;\n            case R.id.btnAttachment:\n                fileManager.requestForFile(OFileManager.RequestType.ALL_FILE_TYPE);\n                break;\n        }\n    }\n\n    @Override\n    protected void onActivityResult(int requestCode, int resultCode, Intent data) {\n        super.onActivityResult(requestCode, resultCode, data);\n        OValues response = fileManager.handleResult(requestCode, resultCode, data);\n        if (response != null) {\n            addAttachment(response);\n        }\n    }\n\n    private void addAttachment(OValues values) {\n        View attachmentView = LayoutInflater.from(this)\n                .inflate(R.layout.base_attachment_item, horizontalScrollView, false);\n        String fileName = values.getString(\"name\");\n        String type = values.getString(\"file_type\");\n        ImageView imgPreview = (ImageView) attachmentView.findViewById(R.id.attachmentPreview);\n        if (type.contains(\"image\")) {\n            OLog.log(values.getString(\"file_uri\"));\n            imgPreview.setImageURI(Uri.parse(values.getString(\"file_uri\")));\n        } else if (type.contains(\"audio\")) {\n            imgPreview.setImageResource(R.drawable.audio);\n        } else if (type.contains(\"video\")) {\n            imgPreview.setImageResource(R.drawable.video);\n        } else {\n            imgPreview.setImageResource(R.drawable.file);\n        }\n        OControls.setText(attachmentView, R.id.attachmentFileName, fileName);\n        attachmentView.setTag(values);\n        attachmentView.findViewById(R.id.btnRemoveAttachment)\n                .setOnClickListener(new View.OnClickListener() {\n                    @Override\n                    public void onClick(View v) {\n                        horizontalScrollView.removeView(\n                                (View) v.getParent()\n                        );\n                    }\n                });\n        horizontalScrollView.addView(attachmentView);\n    }\n\n    private void sendMessage() {\n        edtSubject.setError(null);\n        edtBody.setError(null);\n        if (mType == MessageType.Message) {\n            if (TextUtils.isEmpty(edtSubject.getText())) {\n                edtSubject.setError(\"Subject required\");\n                edtSubject.requestFocus();\n                return;\n            }\n        }\n        if (TextUtils.isEmpty(edtBody.getText())) {\n            edtBody.setError(((mType == MessageType.Message) ? \"Message\" : \"Note\") + \" required\");\n            edtBody.requestFocus();\n            return;\n        }\n\n        int attachments_count = horizontalScrollView.getChildCount();\n        if (attachments_count > 0) {\n            // Has attachments\n            List<OValues> attachments = new ArrayList<>();\n            for (int i = 0; i < attachments_count; i++) {\n                attachments.add((OValues) horizontalScrollView.getChildAt(i).getTag());\n            }\n            CreateAttachments createAttachments = new CreateAttachments();\n            createAttachments.execute(attachments);\n        } else {\n            postMessage();\n        }\n    }\n\n    private void postMessage() {\n        String subject = (mType == MessageType.Message) ?\n                edtSubject.getText().toString() : \"false\";\n        MessagePost messagePost = new MessagePost();\n        messagePost.execute(subject, edtBody.getText().toString());\n    }\n\n    private class CreateAttachments extends AsyncTask<List<OValues>, Void, List<Integer>> {\n        private ProgressDialog progressDialog;\n\n        @Override\n        protected void onPreExecute() {\n            super.onPreExecute();\n            progressDialog = new ProgressDialog(MailChatterCompose.this);\n            progressDialog.setTitle(R.string.title_working);\n            progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);\n            progressDialog.setMessage(\"Uploading attachments...\");\n            progressDialog.setMax(horizontalScrollView.getChildCount());\n            progressDialog.setCancelable(false);\n            progressDialog.setProgress(1);\n            progressDialog.show();\n        }\n\n        @Override\n        protected List<Integer> doInBackground(final List<OValues>... params) {\n            try {\n                List<Integer> ids = new ArrayList<>();\n                for (final OValues value : params[0]) {\n                    boolean isImage = (value.getString(\"file_type\").contains(\"image\"));\n                    value.put(\"datas\", BitmapUtils.uriToBase64(\n                            Uri.parse(value.getString(\"file_uri\"))\n                            , getContentResolver(), isImage\n                    ));\n                    JSONObject data = IrAttachment.valuesToData(irAttachment, value);\n                    if (data != null) {\n                        runOnUiThread(new Runnable() {\n                            @Override\n                            public void run() {\n                                progressDialog.setProgress(params[0].indexOf(value) + 1);\n                            }\n                        });\n                        int newId = irAttachment.getServerDataHelper().createOnServer(data);\n                        value.put(\"id\", newId);\n                        irAttachment.createAttachment(value, mailMessage.getModelName(),\n                                0);\n                        ids.add(newId);\n                    }\n                }\n                return ids;\n            } catch (Exception e) {\n                e.printStackTrace();\n            }\n            return null;\n        }\n\n        @Override\n        protected void onPostExecute(List<Integer> ids) {\n            super.onPostExecute(ids);\n            progressDialog.dismiss();\n            attachmentIds.clear();\n            attachmentIds.addAll(ids);\n            if (ids != null)\n                postMessage();\n        }\n    }\n\n    private class MessagePost extends AsyncTask<String, Void, Boolean> {\n        private ProgressDialog progressDialog;\n\n        @Override\n        protected void onPreExecute() {\n            super.onPreExecute();\n            progressDialog = new ProgressDialog(MailChatterCompose.this);\n            progressDialog.setTitle(R.string.title_working);\n            progressDialog.setMessage(((mType == MessageType.Message) ? \"Sending message\" :\n                    \"Logging internal note\") + \"...\");\n            progressDialog.setCancelable(false);\n            progressDialog.show();\n        }\n\n        @Override\n        protected Boolean doInBackground(String... params) {\n            try {\n                String subject = params[0];\n                String body = params[1];\n                OArguments args = new OArguments();\n                args.add(server_id);\n                JSONObject data = new JSONObject();\n                data.put(\"body\", body);\n                data.put(\"subject\", (subject.equals(\"false\")) ? false : subject);\n                data.put(\"parent_id\", false);\n                data.put(\"attachment_ids\", JSONUtils.toArray(attachmentIds));\n                JSONArray partner_ids = new JSONArray();\n                if (partner_id != -1 && mType == MessageType.Message) {\n                    partner_ids.put(partner_id);\n                }\n                data.put(\"partner_ids\", partner_ids);\n                JSONObject context = new JSONObject();\n                context.put(\"mail_read_set_read\", true);\n                context.put(\"default_res_id\", server_id);\n                context.put(\"default_model\", mModel.getModelName());\n                context.put(\"mail_post_autofollow\", true);\n                context.put(\"mail_post_autofollow_partner_ids\", new JSONArray());\n                data.put(\"context\", context);\n                data.put(\"type\", \"comment\");\n                data.put(\"content_subtype\", \"plaintext\");\n                data.put(\"subtype\", (mType == MessageType.Message) ? \"mail.mt_comment\" : false);\n                int newId = (int)\n                        mModel.getServerDataHelper().callMethod(\"message_post\", args, null, data);\n                Thread.sleep(500);\n                ODataRow row = new ODataRow();\n                row.put(\"id\", newId);\n                mailMessage.quickCreateRecord(row);\n                return true;\n            } catch (Exception e) {\n                e.printStackTrace();\n            }\n            return false;\n        }\n\n        @Override\n        protected void onPostExecute(Boolean aBoolean) {\n            super.onPostExecute(aBoolean);\n            progressDialog.dismiss();\n            Context ctx = MailChatterCompose.this;\n            Intent intent = new Intent();\n            intent.setAction(\"mail.message.update\");\n            ctx.sendBroadcast(intent);\n            finish();\n\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/base/addons/mail/widget/MailChatterView.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 25/2/15 12:07 PM\n */\npackage com.odoo.base.addons.mail.widget;\n\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.IntentFilter;\nimport android.content.res.TypedArray;\nimport android.database.Cursor;\nimport android.graphics.Bitmap;\nimport android.graphics.Color;\nimport android.os.AsyncTask;\nimport android.os.Bundle;\nimport android.util.AttributeSet;\nimport android.util.Log;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.LinearLayout;\nimport android.widget.TextView;\nimport android.widget.Toast;\n\nimport com.odoo.App;\nimport com.odoo.R;\nimport com.odoo.base.addons.mail.MailMessage;\nimport com.odoo.core.orm.ODataRow;\nimport com.odoo.core.orm.OModel;\nimport com.odoo.core.orm.fields.OColumn;\nimport com.odoo.core.utils.BitmapUtils;\nimport com.odoo.core.utils.IntentUtils;\nimport com.odoo.core.utils.OControls;\nimport com.odoo.core.utils.OCursorUtils;\nimport com.odoo.core.utils.ODateUtils;\nimport com.odoo.core.utils.OResource;\nimport com.odoo.core.utils.StringUtils;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport odoo.ODomain;\nimport odoo.controls.ExpandableListControl;\n\npublic class MailChatterView extends LinearLayout implements\n        ExpandableListControl.ExpandableListAdapterGetViewListener, View.OnClickListener {\n    public static final String TAG = MailChatterView.class.getSimpleName();\n    private Context mContext;\n    private String modelName = null;\n    private int record_server_id = 0;\n    private View mChatterCardView;\n    private OModel mModel;\n    private ExpandableListControl mChatterListView;\n    private ExpandableListControl.ExpandableListAdapter mListAdapter;\n    private List<Object> chatterItems = new ArrayList<>();\n    private MailMessage mailMessage;\n    private ChatterMessagesLoader messagesLoader;\n    private App app;\n    private Boolean loadAllMessages = false;\n    private boolean isExecuting = false;\n\n    public MailChatterView(Context context) {\n        super(context);\n        init(context, null, 0);\n    }\n\n    public MailChatterView(Context context, AttributeSet attrs) {\n        super(context, attrs);\n        init(context, attrs, 0);\n    }\n\n    public MailChatterView(Context context, AttributeSet attrs, int defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n        init(context, attrs, defStyleAttr);\n    }\n\n    private void init(Context context, AttributeSet attrs, int defStyleAttr) {\n        mContext = context;\n        app = (App) mContext.getApplicationContext();\n        if (attrs != null) {\n            TypedArray types = mContext.obtainStyledAttributes(attrs,\n                    R.styleable.MailChatterView);\n            modelName = types.getString(R.styleable.MailChatterView_resModelName);\n            types.recycle();\n        }\n        setOrientation(VERTICAL);\n        mailMessage = new MailMessage(context, null);\n        mContext.registerReceiver(dataChangeReceiver, new IntentFilter(\"mail.message.update\"));\n    }\n\n    public void generateView() {\n        Log.v(TAG, \"Generating View for Mail Chatter\");\n        removeAllViews();\n        mChatterCardView = LayoutInflater.from(mContext).inflate(R.layout.base_mail_chatter, this, false);\n        addView(mChatterCardView);\n        findViewById(R.id.chatterSendMessage).setOnClickListener(this);\n        findViewById(R.id.chatterLogInternalNote).setOnClickListener(this);\n        if (modelName != null) {\n            mModel = OModel.get(mContext, modelName, null);\n            if (!mModel.hasMailChatter()) {\n                removeAllViews();\n            } else {\n                if (record_server_id > 0) {\n                    getMessages();\n                }\n            }\n        } else {\n            removeAllViews();\n        }\n    }\n\n    private void getMessages() {\n        mChatterListView = (ExpandableListControl) findViewById(R.id.chatterMessages);\n        mListAdapter = mChatterListView.getAdapter(\n                R.layout.base_mail_chatter_item, chatterItems, this);\n        mListAdapter.notifyDataSetChanged(chatterItems);\n\n        // Check for server updated messages\n        if (app.inNetwork()) {\n            messagesLoader = new ChatterMessagesLoader();\n            messagesLoader.execute();\n        }\n        // Updating chatter messages\n        updateChatterList();\n    }\n\n    private void updateChatterList() {\n        // Getting local messages\n        if (modelName != null) {\n            chatterItems.clear();\n            Cursor cr = mContext.getContentResolver().query(mailMessage.uri(),\n                    null, \"model = ? and res_id = ?\",\n                    new String[]{modelName, record_server_id + \"\"}, \"date desc\");\n            if (cr.moveToFirst()) {\n                int limit = (loadAllMessages) ? cr.getCount()\n                        : (cr.getCount() > 3) ? 3 : cr.getCount();\n                for (int i = 0; i < limit; i++) {\n                    ODataRow row = OCursorUtils.toDatarow(cr);\n                    chatterItems.add(row);\n                    cr.moveToNext();\n                }\n            }\n            TextView loadMore = (TextView) findViewById(R.id.chatterLoadMoreMessages);\n            if (cr.getCount() > 3 && !loadAllMessages) {\n                loadMore.setVisibility(View.VISIBLE);\n                loadMore.setOnClickListener(this);\n            } else {\n                loadMore.setVisibility(View.GONE);\n            }\n            mListAdapter.notifyDataSetChanged(chatterItems);\n            if (chatterItems.isEmpty()) {\n                loadMore.setVisibility(View.VISIBLE);\n                loadMore.setText(\"No messages !\");\n            }\n        }\n    }\n\n    public void setModelName(String model) {\n        modelName = model;\n    }\n\n    public void setRecordServerId(int record_server_id) {\n        this.record_server_id = record_server_id;\n    }\n\n    @Override\n    public View getView(int position, View view, ViewGroup parent) {\n        ODataRow row = (ODataRow) chatterItems.get(position);\n        if (row.getString(\"subtype_id\").equals(\"false\")) {\n            view.setBackgroundResource(R.color.base_chatter_view_note_background);\n        } else {\n            view.setBackgroundColor(Color.WHITE);\n        }\n        view.findViewById(R.id.imgAttachments).setVisibility(\n                (row.getBoolean(\"has_attachments\")) ?\n                        View.VISIBLE :\n                        View.GONE\n        );\n\n        if (row.getString(\"subject\").equals(\"false\")) {\n            OControls.setGone(view, R.id.chatterSubject);\n        } else {\n            OControls.setVisible(view, R.id.chatterSubject);\n            OControls.setText(view, R.id.chatterSubject, row.getString(\"subject\"));\n        }\n        String date = ODateUtils.convertToDefault(row.getString(\"date\"),\n                ODateUtils.DEFAULT_FORMAT, \"MMM dd hh:mm a\");\n        OControls.setText(view, R.id.chatterDate, date);\n        OControls.setText(view, R.id.chatterBody, StringUtils.htmlToString(row.getString(\"body\")));\n        OControls.setText(view, R.id.chatterAuthor, row.getString(\"author_name\"));\n        String author_image = mailMessage.getAuthorImage(row.getInt(OColumn.ROW_ID));\n        if (!author_image.equals(\"false\")) {\n            Bitmap author = BitmapUtils.getBitmapImage(mContext, author_image);\n            OControls.setImage(view, R.id.authorImage, author);\n        } else {\n            OControls.setImage(view, R.id.authorImage, R.drawable.avatar);\n        }\n\n        view.setTag(row);\n        view.setOnClickListener(this);\n        return view;\n    }\n\n    @Override\n    public void onClick(View v) {\n        Bundle extra = new Bundle();\n        extra.putString(\"model\", mModel.getModelName());\n        extra.putInt(\"server_id\", record_server_id);\n        switch (v.getId()) {\n            case R.id.chatterSendMessage:\n                if (app.inNetwork()) {\n                    extra.putString(\"type\", MailChatterCompose.MessageType.Message.toString());\n                    IntentUtils.startActivity(mContext, MailChatterCompose.class, extra);\n                } else {\n                    Toast.makeText(mContext, OResource.string(mContext,\n                            R.string.toast_network_required), Toast.LENGTH_LONG).show();\n                }\n                break;\n            case R.id.chatterLogInternalNote:\n                if (app.inNetwork()) {\n                    extra.putString(\"type\", MailChatterCompose.MessageType.InternalNote.toString());\n                    IntentUtils.startActivity(mContext, MailChatterCompose.class, extra);\n                } else {\n                    Toast.makeText(mContext, OResource.string(mContext,\n                            R.string.toast_network_required), Toast.LENGTH_LONG).show();\n                }\n                break;\n            case R.id.chatterLoadMoreMessages:\n                loadAllMessages = true;\n                updateChatterList();\n                break;\n            default:\n                ODataRow row = (ODataRow) v.getTag();\n                extra.putAll(row.getPrimaryBundleData());\n                if (row != null) {\n                    IntentUtils.startActivity(mContext, MailDetailDialog.class, extra);\n                }\n                break;\n        }\n    }\n\n    @Override\n    protected void onDetachedFromWindow() {\n        super.onDetachedFromWindow();\n        if (messagesLoader != null)\n            messagesLoader.cancel(true);\n        mContext.unregisterReceiver(dataChangeReceiver);\n    }\n\n    private class ChatterMessagesLoader extends AsyncTask<Void, Void, Void> {\n\n        @Override\n        protected void onPreExecute() {\n            super.onPreExecute();\n            findViewById(R.id.chatterProgress).setVisibility(View.VISIBLE);\n            findViewById(R.id.chatterOr).setVisibility(View.GONE);\n        }\n\n        @Override\n        protected Void doInBackground(Void... params) {\n            try {\n                Thread.sleep(500);\n                ODomain domain = new ODomain();\n                domain.add(\"model\", \"=\", modelName);\n                domain.add(\"res_id\", \"=\", record_server_id);\n                List<Integer> serverIds = mailMessage.getServerIds(modelName, record_server_id);\n                if (serverIds.size() > 0) {\n                    domain.add(\"id\", \"not in\", serverIds);\n                }\n                mailMessage.quickSyncRecords(domain);\n            } catch (Exception e) {\n            }\n            return null;\n        }\n\n        @Override\n        protected void onPostExecute(Void aVoid) {\n            super.onPostExecute(aVoid);\n            findViewById(R.id.chatterProgress).setVisibility(View.GONE);\n            findViewById(R.id.chatterOr).setVisibility(View.VISIBLE);\n            updateChatterList();\n            isExecuting = false;\n        }\n    }\n\n    private BroadcastReceiver dataChangeReceiver = new BroadcastReceiver() {\n        @Override\n        public void onReceive(Context context, Intent intent) {\n            if (!isExecuting) {\n                if (messagesLoader != null)\n                    messagesLoader.cancel(true);\n                messagesLoader = new ChatterMessagesLoader();\n                messagesLoader.execute();\n                isExecuting = true;\n            }\n        }\n    };\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/base/addons/mail/widget/MailDetailDialog.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 25/2/15 6:26 PM\n */\npackage com.odoo.base.addons.mail.widget;\n\nimport android.graphics.Bitmap;\nimport android.graphics.Color;\nimport android.net.Uri;\nimport android.os.AsyncTask;\nimport android.os.Bundle;\nimport android.support.v7.app.ActionBarActivity;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.webkit.WebView;\nimport android.widget.ImageView;\nimport android.widget.LinearLayout;\nimport android.widget.TextView;\n\nimport com.odoo.R;\nimport com.odoo.base.addons.ir.feature.OFileManager;\nimport com.odoo.base.addons.mail.MailMessage;\nimport com.odoo.core.orm.ODataRow;\nimport com.odoo.core.orm.OModel;\nimport com.odoo.core.orm.fields.OColumn;\nimport com.odoo.core.utils.BitmapUtils;\nimport com.odoo.core.utils.IntentUtils;\nimport com.odoo.core.utils.OControls;\nimport com.odoo.core.utils.ODateUtils;\nimport com.odoo.core.utils.OStringColorUtil;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class MailDetailDialog extends ActionBarActivity implements View.OnClickListener {\n    public static final String TAG = MailDetailDialog.class.getSimpleName();\n    private Bundle extra;\n    private MailMessage mailMessage;\n    private OModel baseModel;\n    private TextView recordName;\n    private View parent;\n    private List<ODataRow> attachments = new ArrayList<>();\n    private LoadAttachments loadAttachments = null;\n    private LinearLayout horizontalScrollView;\n    private OFileManager fileManager;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.base_mail_chatter_message_detail);\n        getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);\n        getSupportActionBar().hide();\n        fileManager = new OFileManager(this);\n        mailMessage = new MailMessage(this, null);\n        extra = getIntent().getExtras();\n        findViewById(R.id.btnClose).setOnClickListener(this);\n        findViewById(R.id.btnReply).setOnClickListener(this);\n        init();\n    }\n\n    private void init() {\n        recordName = (TextView) findViewById(R.id.recordName);\n        parent = (View) recordName.getParent();\n        ODataRow row = mailMessage.browse(extra.getInt(OColumn.ROW_ID));\n        attachments.addAll(row.getM2MRecord(\"attachment_ids\").browseEach());\n        if (attachments.size() > 0) {\n            loadAttachments = new LoadAttachments();\n            loadAttachments.execute();\n        }\n        horizontalScrollView = (LinearLayout) findViewById(R.id.attachmentsList);\n        baseModel = OModel.get(this, row.getString(\"model\"), mailMessage.getUser().getAndroidName());\n        ODataRow record = baseModel.browse(baseModel.selectRowId(row.getInt(\"res_id\")));\n        String name = record.getString(baseModel.getDefaultNameColumn());\n        recordName.setText(name);\n        recordName.setBackgroundColor(OStringColorUtil.getStringColor(this, name));\n\n        if (!row.getString(\"subject\").equals(\"false\"))\n            OControls.setText(parent, R.id.messageSubject, row.getString(\"subject\"));\n        else\n            OControls.setGone(parent, R.id.messageSubject);\n\n        WebView messageBody = (WebView) findViewById(R.id.messageBody);\n        messageBody.setBackgroundColor(Color.TRANSPARENT);\n        messageBody.loadData(row.getString(\"body\"), \"text/html; charset=UTF-8\", \"UTF-8\");\n\n        Bitmap author_image = BitmapUtils.getAlphabetImage(this, row.getString(\"author_name\"));\n        String author_img = mailMessage.getAuthorImage(row.getInt(OColumn.ROW_ID));\n        if (!author_img.equals(\"false\")) {\n            author_image = BitmapUtils.getBitmapImage(this, author_img);\n        }\n        OControls.setImage(parent, R.id.author_image, author_image);\n        OControls.setText(parent, R.id.authorName, row.getString(\"author_name\"));\n        String date = ODateUtils.convertToDefault(row.getString(\"date\"),\n                ODateUtils.DEFAULT_FORMAT, \"MMM dd, yyyy hh:mm a\");\n        OControls.setText(parent, R.id.messageDate, date);\n    }\n\n    private class LoadAttachments extends AsyncTask<Void, Void, Void> {\n\n        @Override\n        protected Void doInBackground(Void... params) {\n            runOnUiThread(new Runnable() {\n                @Override\n                public void run() {\n                    for (ODataRow row : attachments) {\n                        addAttachment(row);\n                    }\n                }\n            });\n            return null;\n        }\n    }\n\n    private void addAttachment(ODataRow values) {\n        View attachmentView = LayoutInflater.from(this)\n                .inflate(R.layout.base_attachment_item, horizontalScrollView, false);\n        String fileName = values.getString(\"name\");\n        String type = values.getString(\"file_type\");\n        ImageView imgPreview = (ImageView) attachmentView.findViewById(R.id.attachmentPreview);\n        if (type.contains(\"image\")) {\n            if (!values.getString(\"file_uri\").equals(\"false\")) {\n                Uri uri = Uri.parse(values.getString(\"file_uri\"));\n                imgPreview.setImageBitmap(fileManager.getBitmapFromURI(uri));\n            } else\n                imgPreview.setImageResource(R.drawable.image);\n        } else if (type.contains(\"audio\")) {\n            imgPreview.setImageResource(R.drawable.audio);\n        } else if (type.contains(\"video\")) {\n            imgPreview.setImageResource(R.drawable.video);\n        } else {\n            imgPreview.setImageResource(R.drawable.file);\n        }\n        OControls.setText(attachmentView, R.id.attachmentFileName, fileName);\n        attachmentView.setTag(values);\n        attachmentView.findViewById(R.id.btnRemoveAttachment).setVisibility(View.GONE);\n        attachmentView.setOnClickListener(this);\n        horizontalScrollView.addView(attachmentView);\n    }\n\n    @Override\n    public void onClick(View v) {\n        if (v.getTag() != null) {\n            ODataRow attachment = (ODataRow) v.getTag();\n            fileManager.downloadAttachment(attachment.getInt(OColumn.ROW_ID));\n        } else {\n            switch (v.getId()) {\n                case R.id.btnClose:\n                    finish();\n                    break;\n                case R.id.btnReply:\n                    extra.putString(\"type\", MailChatterCompose.MessageType.Message.toString());\n                    IntentUtils.startActivity(this, MailChatterCompose.class, extra);\n                    finish();\n                    break;\n            }\n        }\n    }\n\n    @Override\n    protected void onPause() {\n        super.onPause();\n        if (loadAttachments != null) {\n            loadAttachments.cancel(true);\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/base/addons/mail/widget/MessageObserver.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 27/2/15 6:55 PM\n */\npackage com.odoo.base.addons.mail.widget;\n\nimport android.database.ContentObserver;\nimport android.net.Uri;\nimport android.os.Handler;\n\npublic class MessageObserver extends ContentObserver {\n    public static final String TAG = MessageObserver.class.getSimpleName();\n    private OnDataSetChangeListener mOnDataSetChangeListener;\n\n    public MessageObserver() {\n        super(new Handler());\n    }\n\n    @Override\n    public void onChange(boolean selfChange) {\n        super.onChange(selfChange);\n        if (mOnDataSetChangeListener != null) {\n            mOnDataSetChangeListener.onDataSetChange();\n        }\n    }\n\n    @Override\n    public void onChange(boolean selfChange, Uri uri) {\n        super.onChange(selfChange, uri);\n        if (mOnDataSetChangeListener != null) {\n            mOnDataSetChangeListener.onDataSetChange();\n        }\n    }\n\n    public void setOnDataSetChangeListener(OnDataSetChangeListener listener) {\n        mOnDataSetChangeListener = listener;\n    }\n\n    public interface OnDataSetChangeListener {\n        public void onDataSetChange();\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/base/addons/res/ResCompany.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 31/12/14 12:53 PM\n */\npackage com.odoo.base.addons.res;\n\nimport android.content.Context;\n\nimport com.odoo.core.orm.ODataRow;\nimport com.odoo.core.orm.OModel;\nimport com.odoo.core.orm.fields.OColumn;\nimport com.odoo.core.orm.fields.types.OVarchar;\nimport com.odoo.core.support.OUser;\n\npublic class ResCompany extends OModel {\n    public static final String TAG = ResCompany.class.getSimpleName();\n\n    OColumn name = new OColumn(\"Name\", OVarchar.class);\n    OColumn currency_id = new OColumn(\"Currency\", ResCurrency.class,\n            OColumn.RelationType.ManyToOne);\n\n    public ResCompany(Context context, OUser user) {\n        super(context, \"res.company\", user);\n    }\n\n    public static ODataRow getCurrency(Context context) {\n        ResCompany company = new ResCompany(context, null);\n        int row_id = company.selectRowId(Integer.parseInt(company.getUser().getCompany_id()));\n        return company.browse(row_id).getM2ORecord(\"currency_id\").browse();\n    }\n\n    @Override\n    public boolean allowCreateRecordOnServer() {\n        return false;\n    }\n\n    @Override\n    public boolean allowUpdateRecordOnServer() {\n        return false;\n    }\n\n    @Override\n    public boolean allowDeleteRecordInLocal() {\n        return false;\n    }\n\n    public static int myId(Context context) {\n        ResCompany company = new ResCompany(context, null);\n        return company.selectRowId(Integer.parseInt(company.getUser().getCompany_id()));\n    }\n\n    public static int myCurrency(Context context) {\n        ResCompany company = new ResCompany(context, null);\n        ODataRow row = company.browse(company.selectRowId(Integer.parseInt(company.\n                getUser().getCompany_id())));\n        return row.getM2ORecord(\"currency_id\").browse().getInt(OColumn.ROW_ID);\n\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/base/addons/res/ResCountry.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 31/12/14 6:43 PM\n */\npackage com.odoo.base.addons.res;\n\nimport android.content.Context;\n\nimport com.odoo.core.orm.OModel;\nimport com.odoo.core.orm.fields.OColumn;\nimport com.odoo.core.orm.fields.types.OVarchar;\nimport com.odoo.core.support.OUser;\n\npublic class ResCountry extends OModel {\n\n    OColumn name = new OColumn(\"Name\", OVarchar.class).setSize(100);\n\n    public ResCountry(Context context, OUser user) {\n        super(context, \"res.country\", user);\n    }\n\n    @Override\n    public boolean allowCreateRecordOnServer() {\n        return false;\n    }\n\n    @Override\n    public boolean allowUpdateRecordOnServer() {\n        return false;\n    }\n\n    @Override\n    public boolean allowDeleteRecordInLocal() {\n        return false;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/base/addons/res/ResCurrency.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 13/1/15 10:19 AM\n */\npackage com.odoo.base.addons.res;\n\nimport android.content.Context;\n\nimport com.odoo.core.orm.ODataRow;\nimport com.odoo.core.orm.OModel;\nimport com.odoo.core.orm.fields.OColumn;\nimport com.odoo.core.orm.fields.types.OVarchar;\nimport com.odoo.core.support.OUser;\n\npublic class ResCurrency extends OModel {\n    public static final String TAG = ResCurrency.class.getSimpleName();\n    OColumn name = new OColumn(\"Name\", OVarchar.class);\n    OColumn symbol = new OColumn(\"Symbol\", OVarchar.class).setSize(10);\n\n    public ResCurrency(Context context, OUser user) {\n        super(context, \"res.currency\", user);\n    }\n\n    public static String getSymbol(Context context, int row_id) {\n        ResCurrency resCurrency = new ResCurrency(context, null);\n        ODataRow row = resCurrency.browse(row_id);\n        return (row != null) ? row.getString(\"symbol\") : \"\";\n    }\n\n    @Override\n    public boolean allowCreateRecordOnServer() {\n        return false;\n    }\n\n    @Override\n    public boolean allowUpdateRecordOnServer() {\n        return false;\n    }\n\n    @Override\n    public boolean allowDeleteRecordInLocal() {\n        return false;\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/base/addons/res/ResPartner.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 30/12/14 4:00 PM\n */\npackage com.odoo.base.addons.res;\n\nimport android.content.Context;\nimport android.net.Uri;\n\nimport com.odoo.addons.sale.models.AccountPaymentTerm;\nimport com.odoo.core.orm.ODataRow;\nimport com.odoo.core.orm.OModel;\nimport com.odoo.core.orm.OValues;\nimport com.odoo.core.orm.annotation.Odoo;\nimport com.odoo.core.orm.fields.OColumn;\nimport com.odoo.core.orm.fields.types.OBlob;\nimport com.odoo.core.orm.fields.types.OBoolean;\nimport com.odoo.core.orm.fields.types.OText;\nimport com.odoo.core.orm.fields.types.OVarchar;\nimport com.odoo.core.support.OUser;\n\nimport org.json.JSONArray;\n\npublic class\n        ResPartner extends OModel {\n    public static final String AUTHORITY = \"com.odoo.core.crm.provider.content.sync.res_partner\";\n    OColumn name = new OColumn(\"Name\", OVarchar.class).setSize(100).setRequired();\n    OColumn is_company = new OColumn(\"Is Company\", OBoolean.class).setDefaultValue(false);\n    OColumn image_small = new OColumn(\"Avatar\", OBlob.class).setDefaultValue(false);\n    OColumn street = new OColumn(\"Street\", OVarchar.class).setSize(100);\n    OColumn street2 = new OColumn(\"Street2\", OVarchar.class).setSize(100);\n    OColumn city = new OColumn(\"City\", OVarchar.class);\n    OColumn zip = new OColumn(\"Zip\", OVarchar.class);\n    OColumn website = new OColumn(\"Website\", OVarchar.class).setSize(100);\n    OColumn phone = new OColumn(\"Phone\", OVarchar.class).setSize(15);\n    OColumn mobile = new OColumn(\"Mobile\", OVarchar.class).setSize(15);\n    OColumn email = new OColumn(\"Email\", OVarchar.class);\n    OColumn company_id = new OColumn(\"Company\", ResCompany.class, OColumn.RelationType.ManyToOne);\n    OColumn parent_id = new OColumn(\"Related Company\", ResPartner.class, OColumn.RelationType.ManyToOne)\n            .addDomain(\"is_company\", \"=\", true);\n    OColumn country_id = new OColumn(\"Country\", ResCountry.class, OColumn.RelationType.ManyToOne);\n    OColumn customer = new OColumn(\"Customer\", OBoolean.class).setDefaultValue(\"true\");\n    OColumn comment = new OColumn(\"Internal Note\", OText.class);\n    @Odoo.Functional(store = true, depends = {\"parent_id\"}, method = \"storeCompanyName\")\n    OColumn company_name = new OColumn(\"Company Name\", OVarchar.class).setSize(100)\n            .setLocalColumn();\n    OColumn large_image = new OColumn(\"Image\", OBlob.class).setDefaultValue(\"false\").setLocalColumn();\n\n    OColumn partner_invoice_id = new OColumn(\"partner_invoice_id\", OVarchar.class).setLocalColumn();\n    OColumn partner_shipping_id = new OColumn(\"partner_shipping_id\", OVarchar.class).setLocalColumn();\n    OColumn pricelist_id = new OColumn(\"pricelist_id\", OVarchar.class).setLocalColumn();\n    OColumn fiscal_position = new OColumn(\"fiscal_position\", OVarchar.class).setLocalColumn();\n    OColumn payment_term = new OColumn(\"Payment Term\", AccountPaymentTerm.class, OColumn.RelationType.ManyToOne).setLocalColumn();\n\n    public ResPartner(Context context, OUser user) {\n        super(context, \"res.partner\", user);\n        setHasMailChatter(true);\n    }\n\n    @Override\n    public Uri uri() {\n        return buildURI(AUTHORITY);\n    }\n\n    public String storeCompanyName(OValues value) {\n        try {\n            if (!value.getString(\"parent_id\").equals(\"false\")) {\n                JSONArray parent_id = new JSONArray(value.getString(\"parent_id\"));\n                return parent_id.getString(1);\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return \"\";\n    }\n\n    public static String getContact(Context context, int row_id) {\n        ODataRow row = new ResPartner(context, null).browse(row_id);\n        String contact;\n        if (row.getString(\"mobile\").equals(\"false\")) {\n            contact = row.getString(\"phone\");\n        } else {\n            contact = row.getString(\"mobile\");\n        }\n        return contact;\n    }\n\n    public String getAddress(ODataRow row) {\n        String add = \"\";\n        if (!row.getString(\"street\").equals(\"false\"))\n            add += row.getString(\"street\") + \", \";\n        if (!row.getString(\"street2\").equals(\"false\"))\n            add += \"\\n\" + row.getString(\"street2\") + \", \";\n        if (!row.getString(\"city\").equals(\"false\"))\n            add += row.getString(\"city\");\n        if (!row.getString(\"zip\").equals(\"false\"))\n            add += \" - \" + row.getString(\"zip\") + \" \";\n        return add;\n    }\n\n    public Uri liveSearchURI() {\n        return uri().buildUpon().appendPath(\"live_searchable_customer\").build();\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/base/addons/res/ResUsers.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 13/1/15 10:16 AM\n */\npackage com.odoo.base.addons.res;\n\nimport android.content.Context;\n\nimport com.odoo.core.orm.OModel;\nimport com.odoo.core.orm.fields.OColumn;\nimport com.odoo.core.orm.fields.types.OVarchar;\nimport com.odoo.core.support.OUser;\n\npublic class ResUsers extends OModel {\n    public static final String TAG = ResUsers.class.getSimpleName();\n\n    OColumn name = new OColumn(\"Name\", OVarchar.class);\n    OColumn login = new OColumn(\"User Login name\", OVarchar.class);\n\n    @Override\n    public boolean allowCreateRecordOnServer() {\n        return false;\n    }\n\n    @Override\n    public boolean allowUpdateRecordOnServer() {\n        return false;\n    }\n\n    @Override\n    public boolean allowDeleteRecordInLocal() {\n        return false;\n    }\n\n    public ResUsers(Context context, OUser user) {\n        super(context, \"res.users\", user);\n    }\n\n    public static int myId(Context context) {\n        ResUsers users = new ResUsers(context, null);\n        return users.selectRowId(users.getUser().getUser_id());\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/config/Addons.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 30/12/14 3:11 PM\n */\npackage com.odoo.config;\n\nimport com.odoo.addons.calendar.CalendarDashboard;\nimport com.odoo.addons.crm.CRMLeads;\nimport com.odoo.addons.customers.Customers;\nimport com.odoo.addons.phonecall.PhoneCalls;\nimport com.odoo.addons.sale.Sales;\nimport com.odoo.core.support.addons.AddonsHelper;\nimport com.odoo.core.support.addons.OAddon;\n\npublic class Addons extends AddonsHelper {\n\n    /**\n     * Declare your required module here\n     * NOTE: For maintain sequence use object name in asc order.\n     * Ex.:\n     * OAddon partners = new OAddon(Partners.class).setDefault();\n     */\n    OAddon a_agenda = new OAddon(CalendarDashboard.class).setDefault();\n    OAddon b_partners = new OAddon(Customers.class);\n    OAddon c_crm_leads = new OAddon(CRMLeads.class);\n    OAddon e_sale = new OAddon(Sales.class);\n    OAddon f_phone_calls = new OAddon(PhoneCalls.class);\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/config/BaseConfig.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 5/1/15 5:55 PM\n */\npackage com.odoo.config;\n\npublic class BaseConfig {\n    /**\n     * Do not remove following constants.\n     */\n\n    public static final boolean DEVELOPER_MODE = true;\n}\n\n\n"
  },
  {
    "path": "app/src/main/java/com/odoo/config/IntroSliderItems.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 13/2/15 4:16 PM\n */\npackage com.odoo.config;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\n\nimport com.odoo.core.utils.OControls;\nimport com.odoo.R;\nimport com.odoo.widgets.slider.SliderItem;\nimport com.odoo.widgets.slider.SliderPagerAdapter;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class IntroSliderItems implements SliderPagerAdapter.SliderBuilderListener, View.OnClickListener {\n    public static final String TAG = IntroSliderItems.class.getSimpleName();\n    private Context mContext;\n\n    public List<SliderItem> getItems() {\n        List<SliderItem> items = new ArrayList<>();\n        items.add(new SliderItem(\"Daily Planner\", \"Odoo CRM keeps you organized, focused and more productive\",\n                R.drawable.slide_1, this)\n                .putExtra(\"sub_title\", \"Manage everything in one place\"));\n        items.add(new SliderItem(\"Live caller ID\", \"Get information about customer and recent opportunity before you pickup the phone.\",\n                R.drawable.slide_3, this)\n                .putExtra(\"sub_title\", \"See who's calling\"));\n        items.add(new SliderItem(\"Reminders\", \"Use reminders to make sure no phone-calls, meetings or opportunities forgotten\",\n                R.drawable.slide_4, this)\n                .putExtra(\"sub_title\", \"Reminder with quick actions\"));\n        items.add(new SliderItem(\"Easy actions\", \"Odoo CRM offers simple, quick and easy actions at your fingertips\",\n                R.drawable.slide_5, this)\n                .putExtra(\"sub_title\", \"Getting things done quickly\"));\n        items.add(new SliderItem(\"Manage quotations\", \"Create/Manage quotations and manage order lines easily\",\n                R.drawable.slide_6, this)\n                .putExtra(\"sub_title\", \"Easily manage order lines\"));\n        items.add(new SliderItem(\"\", \"All the data automatically synchronized with server when you re-connect to internet\",\n                R.drawable.no_network, this)\n                .putExtra(\"sub_title\", \"Works offline\"));\n        items.add(new SliderItem(\"\", \"Works with Odoo Saas cloud\",\n                R.drawable.saas_support, this)\n                .putExtra(\"sub_title\", \"Odoo Saas Support\"));\n        items.add(new SliderItem(\"Let's Start\", \"\",\n                R.drawable.odoo_shaded, this)\n                .putExtra(\"sub_title\", \"Start exploring Odoo CRM\"));\n        return items;\n    }\n\n    @Override\n    public View getCustomView(Context context, SliderItem item, ViewGroup parent) {\n        mContext = context;\n        View view = LayoutInflater.from(context).inflate(R.layout.base_intro_slider_view, parent, false);\n        OControls.setText(view, R.id.big_title, item.getTitle());\n        OControls.setImage(view, R.id.slider_image, item.getImagePath());\n        OControls.setText(view, R.id.sub_title, item.getExtras().get(\"sub_title\").toString());\n        OControls.setText(view, R.id.description, item.getContent());\n        if (item.getImagePath() == R.drawable.odoo_shaded) {\n            OControls.setGone(view, R.id.description);\n            OControls.setVisible(view, R.id.btnSliderFinish);\n            OControls.setText(view, R.id.btnSliderFinish, \"GOT IT, LET'S GO!\");\n            view.findViewById(R.id.btnSliderFinish).setOnClickListener(this);\n        } else {\n            OControls.setVisible(view, R.id.description);\n            OControls.setGone(view, R.id.btnSliderFinish);\n        }\n        return view;\n    }\n\n    @Override\n    public void onClick(View v) {\n        if (v.getId() == R.id.btnSliderFinish) {\n            ((Activity) mContext).finish();\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/core/account/About.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 9/1/15 11:33 AM\n */\npackage com.odoo.core.account;\n\nimport android.content.Intent;\nimport android.content.pm.PackageManager;\nimport android.os.Bundle;\nimport android.os.Handler;\nimport android.support.v7.app.ActionBarActivity;\nimport android.text.method.LinkMovementMethod;\nimport android.view.Menu;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.widget.TextView;\nimport android.widget.Toast;\n\nimport com.odoo.R;\nimport com.odoo.base.addons.ir.IrModel;\nimport com.odoo.core.utils.IntentUtils;\nimport com.odoo.core.utils.OActionBarUtils;\nimport com.odoo.core.utils.OPreferenceManager;\nimport com.odoo.datas.OConstants;\n\npublic class About extends ActionBarActivity implements View.OnClickListener {\n    public static final String TAG = About.class.getSimpleName();\n    private final static String DEVELOPER_MODE = \"developer_mode\";\n    private Handler handler = null;\n    private int click_count = 0;\n    private Runnable runnable = null;\n\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.base_about);\n        OActionBarUtils.setActionBar(this, true);\n        setTitle(\"\");\n        findViewById(R.id.abtus_header).setOnClickListener(this);\n        TextView versionName, aboutLine2, aboutLine3, aboutLine4;\n        versionName = (TextView) findViewById(R.id.txvVersionName);\n        handler = new Handler();\n        try {\n            PackageManager packageManager = getPackageManager();\n            // setting version name from manifest file\n            String version = packageManager.getPackageInfo(\n                    getPackageName(), 0).versionName;\n            String versionCode = packageManager.getPackageInfo(\n                    getPackageName(), 0).versionCode + \"\";\n            versionName.setText(getResources()\n                    .getString(R.string.label_version) + \" \" + version + \" (\" + versionCode + \")\");\n\n            // setting link in textView\n            aboutLine2 = (TextView) findViewById(R.id.line2);\n            if (aboutLine2 != null) {\n                aboutLine2.setMovementMethod(LinkMovementMethod.getInstance());\n            }\n            aboutLine3 = (TextView) findViewById(R.id.line3);\n            if (aboutLine3 != null) {\n                aboutLine3.setMovementMethod(LinkMovementMethod.getInstance());\n            }\n            aboutLine4 = (TextView) findViewById(R.id.line4);\n            if (aboutLine4 != null) {\n                aboutLine4.setMovementMethod(LinkMovementMethod.getInstance());\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n\n    @Override\n    public boolean onCreateOptionsMenu(Menu menu) {\n        getMenuInflater().inflate(R.menu.menu_about, menu);\n        OPreferenceManager pref = new OPreferenceManager(this);\n        if (pref.getBoolean(DEVELOPER_MODE, false)) {\n            menu.findItem(R.id.menu_developer_mode).setVisible(true);\n        }\n        return true;\n    }\n\n    @Override\n    public boolean onOptionsItemSelected(MenuItem item) {\n        switch (item.getItemId()) {\n            case android.R.id.home:\n                // app icon in action bar clicked; go home\n                finish();\n                return true;\n            case R.id.menu_about_our_apps:\n                IntentUtils.openURLInBrowser(this, OConstants.URL_ODOO_APPS_ON_PLAY_STORE);\n                return true;\n            case R.id.menu_about_github:\n                IntentUtils.openURLInBrowser(this, OConstants.URL_ODOO_MOBILE_GIT_HUB);\n                return true;\n            case R.id.menu_export_db:\n                IrModel model = new IrModel(this, null);\n                model.exportDB();\n                return true;\n            default:\n                return super.onOptionsItemSelected(item);\n        }\n    }\n\n    @Override\n    public void onClick(View v) {\n        if (runnable == null) {\n            runnable = new Runnable() {\n                public void run() {\n                    click_count = 0;\n                }\n            };\n            handler.postDelayed(runnable, 7000);\n        }\n        click_count = click_count + 1;\n        if (click_count == 3) {\n            Toast.makeText(this, R.string.developer_2_tap, Toast.LENGTH_SHORT).show();\n        }\n        if (click_count == 5) {\n            OPreferenceManager pref = new OPreferenceManager(this);\n            pref.setBoolean(DEVELOPER_MODE, true);\n            Toast.makeText(this, R.string.developer_5_tap, Toast.LENGTH_SHORT).show();\n            finish();\n            startActivity(new Intent(this, About.class));\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/core/account/AppIntro.java",
    "content": "package com.odoo.core.account;\n\nimport android.os.Bundle;\nimport android.support.v7.app.ActionBarActivity;\n\nimport com.odoo.R;\nimport com.odoo.config.IntroSliderItems;\nimport com.odoo.widgets.slider.SliderView;\n\npublic class AppIntro extends ActionBarActivity {\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_app_intro);\n        SliderView sliderView = (SliderView) findViewById(R.id.sliderView);\n        IntroSliderItems sliderItems = new IntroSliderItems();\n        if (!sliderItems.getItems().isEmpty()) {\n            sliderView.setItems(getSupportFragmentManager(), sliderItems.getItems());\n        } else {\n            finish();\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/core/account/BaseSettings.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 9/1/15 11:35 AM\n */\npackage com.odoo.core.account;\n\nimport android.content.Context;\nimport android.net.Uri;\nimport android.os.Bundle;\nimport android.preference.Preference;\nimport android.preference.PreferenceFragment;\nimport android.support.v7.app.ActionBar;\nimport android.support.v7.app.ActionBarActivity;\nimport android.util.Log;\n\nimport com.odoo.core.utils.ODateUtils;\nimport com.odoo.core.utils.OPreferenceManager;\nimport com.odoo.core.utils.OResource;\nimport com.odoo.R;\n\nimport odoo.controls.DateTimePicker;\n\npublic class BaseSettings extends PreferenceFragment implements\n        Preference.OnPreferenceClickListener, DateTimePicker.PickerCallBack {\n    public static final String TAG = BaseSettings.class.getSimpleName();\n    public static final String KEY_ADD_ACCOUNT = \"add_account\";\n    private OPreferenceManager mPref;\n    private Preference mTimePreference;\n\n    // Keys\n    public static final String KEY_LEAD_WORK_DAY_START_TIME = \"lead_work_day_start_time\";\n    public static final String KEY_NOTIFICATION_RING_TONE = \"phonecall_notification_ringtone\";\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        addPreferencesFromResource(R.xml.base_preference);\n        mPref = new OPreferenceManager(getActivity());\n        mTimePreference = findPreference(KEY_LEAD_WORK_DAY_START_TIME);\n        if (mTimePreference != null)\n            mTimePreference.setOnPreferenceClickListener(this);\n    }\n\n    @Override\n    public boolean onPreferenceClick(Preference preference) {\n        if (preference.getKey().equals(KEY_LEAD_WORK_DAY_START_TIME)) {\n            showTimePicker();\n            return true;\n        }\n        return false;\n    }\n\n    private void showTimePicker() {\n        String defaultDayStartTime = OResource.string(getActivity(), R.string.default_day_start_time);\n        String time = mPref.getString(KEY_LEAD_WORK_DAY_START_TIME, defaultDayStartTime);\n        DateTimePicker.Builder builder = new DateTimePicker.Builder(getActivity());\n        builder.setTime(ODateUtils.convertToUTC(time, ODateUtils.DEFAULT_TIME_FORMAT,\n                ODateUtils.DEFAULT_TIME_FORMAT));\n        builder.setType(DateTimePicker.Type.Time);\n        builder.setCallBack(this);\n        builder.build().show();\n    }\n\n    private void finish() {\n        getActivity().finish();\n    }\n\n    private ActionBar getActionBar() {\n        return ((ActionBarActivity) getActivity()).getSupportActionBar();\n    }\n\n    @Override\n    public void onDatePick(String date) {\n\n    }\n\n    @Override\n    public void onTimePick(String time) {\n        Log.i(TAG, \"Working start day time : \" + time);\n        mPref.putString(KEY_LEAD_WORK_DAY_START_TIME, time);\n    }\n\n    public static Uri getNotificationRingTone(Context context) {\n        OPreferenceManager mPref = new OPreferenceManager(context);\n        String defaultUri = OResource.string(context, R.string.notification_default_ring_tone);\n        return Uri.parse(mPref.getString(KEY_NOTIFICATION_RING_TONE, defaultUri));\n    }\n\n    public static String getDayStartTime(Context context) {\n        String defaultDayStartTime = OResource.string(context, R.string.default_day_start_time);\n        OPreferenceManager mPref = new OPreferenceManager(context);\n        return mPref.getString(KEY_LEAD_WORK_DAY_START_TIME, defaultDayStartTime);\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/core/account/ManageAccounts.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 19/12/14 2:30 PM\n */\npackage com.odoo.core.account;\n\nimport android.app.AlertDialog;\nimport android.content.DialogInterface;\nimport android.graphics.Bitmap;\nimport android.os.Bundle;\nimport android.os.Handler;\nimport android.support.v7.app.ActionBarActivity;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.Toast;\n\nimport com.odoo.OdooActivity;\nimport com.odoo.core.auth.OdooAccountManager;\nimport com.odoo.core.support.OUser;\nimport com.odoo.core.utils.BitmapUtils;\nimport com.odoo.core.utils.OActionBarUtils;\nimport com.odoo.core.utils.OControls;\nimport com.odoo.core.utils.OResource;\nimport com.odoo.R;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport odoo.controls.ExpandableListControl;\n\npublic class ManageAccounts extends ActionBarActivity implements View.OnClickListener, ExpandableListControl.ExpandableListAdapterGetViewListener {\n\n    private List<Object> accounts = new ArrayList<>();\n    private ExpandableListControl mList = null;\n    private ExpandableListControl.ExpandableListAdapter mAdapter;\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.base_manage_accounts);\n        setTitle(R.string.label_accounts);\n        OActionBarUtils.setActionBar(this, true);\n        setResult(RESULT_CANCELED);\n        accounts.clear();\n        accounts.addAll(OdooAccountManager.getAllAccounts(this));\n        mList = (ExpandableListControl) findViewById(R.id.accountList);\n        mAdapter = mList.getAdapter(R.layout.base_account_item, accounts, this);\n        mAdapter.notifyDataSetChanged(accounts);\n    }\n\n    private void generateView(View view, OUser user) {\n        OControls.setText(view, R.id.accountName, user.getName());\n        OControls.setText(view, R.id.accountURL, (user.isOAauthLogin()) ? user.getInstanceUrl() : user.getHost());\n        OControls.setImage(view, R.id.profile_image, R.drawable.avatar);\n        if (!user.getAvatar().equals(\"false\")) {\n            Bitmap bmp = BitmapUtils.getBitmapImage(this, user.getAvatar());\n            if (bmp != null)\n                OControls.setImage(view, R.id.profile_image, bmp);\n        }\n        if (user.isIsactive()) {\n            OControls.setVisible(view, R.id.btnLogout);\n            OControls.setGone(view, R.id.btnLogin);\n        } else {\n            OControls.setGone(view, R.id.btnLogout);\n            OControls.setVisible(view, R.id.btnLogin);\n        }\n        view.findViewById(R.id.btnLogin).setTag(user);\n        view.findViewById(R.id.btnLogout).setTag(user);\n        view.findViewById(R.id.btnRemoveAccount).setTag(user);\n        view.findViewById(R.id.btnLogout).setOnClickListener(this);\n        view.findViewById(R.id.btnLogin).setOnClickListener(this);\n        view.findViewById(R.id.btnRemoveAccount).setOnClickListener(this);\n    }\n\n    @Override\n    public boolean onOptionsItemSelected(MenuItem item) {\n        switch (item.getItemId()) {\n            case android.R.id.home:\n                finish();\n                break;\n        }\n        return super.onOptionsItemSelected(item);\n    }\n\n    @Override\n    public void onClick(final View v) {\n        switch (v.getId()) {\n            case R.id.btnLogin:\n                OUser user = (OUser) v.getTag();\n                OdooAccountManager.login(this, user.getAndroidName());\n                new Handler().postDelayed(new Runnable() {\n                    @Override\n                    public void run() {\n                        Toast.makeText(ManageAccounts.this, OResource.string(ManageAccounts.this,\n                                R.string.status_login_success), Toast.LENGTH_LONG).show();\n                        setResult(RESULT_OK);\n                        finish();\n                    }\n                }, OdooActivity.DRAWER_ITEM_LAUNCH_DELAY);\n                break;\n            case R.id.btnLogout:\n                AlertDialog.Builder builder = new AlertDialog.Builder(this);\n                builder.setTitle(R.string.title_confirm);\n                builder.setMessage(R.string.toast_are_you_sure_logout);\n                builder.setPositiveButton(R.string.label_logout, new DialogInterface.OnClickListener() {\n                    @Override\n                    public void onClick(DialogInterface dialog, int which) {\n                        OUser user = (OUser) v.getTag();\n                        OdooAccountManager.logout(ManageAccounts.this, user.getAndroidName());\n\n                        new Handler().postDelayed(new Runnable() {\n                            @Override\n                            public void run() {\n                                Toast.makeText(ManageAccounts.this, OResource.string(ManageAccounts.this,\n                                        R.string.status_logout_success), Toast.LENGTH_LONG).show();\n                                setResult(RESULT_OK);\n                                finish();\n                            }\n                        }, OdooActivity.DRAWER_ITEM_LAUNCH_DELAY);\n\n                    }\n                });\n                builder.setNegativeButton(R.string.label_cancel, new DialogInterface.OnClickListener() {\n                    @Override\n                    public void onClick(DialogInterface dialog, int which) {\n                        dialog.dismiss();\n                    }\n                });\n                builder.show();\n                break;\n            case R.id.btnRemoveAccount:\n                builder = new AlertDialog.Builder(this);\n                builder.setTitle(R.string.title_confirm);\n                builder.setMessage(R.string.toast_are_you_sure_delete_account);\n                builder.setPositiveButton(R.string.label_delete, new DialogInterface.OnClickListener() {\n                    @Override\n                    public void onClick(DialogInterface dialog, int which) {\n                        OUser user = (OUser) v.getTag();\n                        OdooAccountManager.removeAccount(ManageAccounts.this, user.getAndroidName());\n                        new Handler().postDelayed(new Runnable() {\n                            @Override\n                            public void run() {\n                                Toast.makeText(ManageAccounts.this, OResource.string(ManageAccounts.this,\n                                        R.string.toast_account_removed), Toast.LENGTH_LONG).show();\n                                setResult(RESULT_OK);\n                                finish();\n                            }\n                        }, OdooActivity.DRAWER_ITEM_LAUNCH_DELAY);\n\n                    }\n                });\n                builder.setNegativeButton(R.string.label_cancel, new DialogInterface.OnClickListener() {\n                    @Override\n                    public void onClick(DialogInterface dialog, int which) {\n                        dialog.dismiss();\n                    }\n                });\n                builder.show();\n                break;\n        }\n    }\n\n    @Override\n    public View getView(int position, View view, ViewGroup parent) {\n        generateView(view, (OUser) mAdapter.getItem(position));\n        return view;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/core/account/OdooAccountQuickManage.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 16/2/15 12:52 PM\n */\npackage com.odoo.core.account;\n\nimport android.app.AlertDialog;\nimport android.app.ProgressDialog;\nimport android.content.DialogInterface;\nimport android.content.Intent;\nimport android.graphics.Bitmap;\nimport android.os.AsyncTask;\nimport android.os.Bundle;\nimport android.os.Handler;\nimport android.support.v7.app.ActionBarActivity;\nimport android.text.TextUtils;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.EditText;\nimport android.widget.ImageView;\nimport android.widget.TextView;\n\nimport com.odoo.OdooActivity;\nimport com.odoo.R;\nimport com.odoo.core.auth.OdooAccountManager;\nimport com.odoo.core.service.OSyncAdapter;\nimport com.odoo.core.support.OUser;\nimport com.odoo.core.support.OdooLoginHelper;\nimport com.odoo.core.utils.BitmapUtils;\nimport com.odoo.core.utils.OResource;\nimport com.odoo.core.utils.notification.ONotificationBuilder;\n\npublic class OdooAccountQuickManage extends ActionBarActivity implements View.OnClickListener {\n    public static final String TAG = OdooAccountQuickManage.class.getSimpleName();\n    private OUser user = null;\n    private ImageView userAvatar;\n    private TextView txvName;\n    private OdooLoginHelper loginHelper;\n    private LoginProcess loginProcess = null;\n    private EditText edtPassword;\n    private String action;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.base_account_quick_manage);\n        getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);\n        getSupportActionBar().hide();\n        action = getIntent().getAction();\n        // Removing notification\n        ONotificationBuilder.cancelNotification(this, OSyncAdapter.REQUEST_SIGN_IN_ERROR);\n        user = OdooAccountManager.getDetails(this, getIntent().getStringExtra(\"android_name\"));\n        if (action.equals(\"remove_account\")) {\n            findViewById(R.id.layoutSavePassword).setVisibility(View.GONE);\n            removeAccount();\n        } else if (action.equals(\"reset_password\")) {\n            updatePassword();\n            findViewById(R.id.cancel).setOnClickListener(this);\n            findViewById(R.id.save_password).setOnClickListener(this);\n        }\n    }\n\n    private void updatePassword() {\n        userAvatar = (ImageView) findViewById(R.id.userAvatar);\n        Bitmap userImage = BitmapUtils.getAlphabetImage(this, user.getName());\n        if (!user.getAvatar().equals(\"false\")) {\n            userImage = BitmapUtils.getBitmapImage(this, user.getAvatar());\n        }\n        userAvatar.setImageBitmap(userImage);\n        txvName = (TextView) findViewById(R.id.userName);\n        txvName.setText(user.getName());\n    }\n\n    private void removeAccount() {\n        AlertDialog.Builder builder = new AlertDialog.Builder(this);\n        builder.setTitle(R.string.title_confirm);\n        builder.setMessage(R.string.toast_are_you_sure_delete_account);\n        builder.setPositiveButton(R.string.label_delete, new DialogInterface.OnClickListener() {\n            @Override\n            public void onClick(DialogInterface dialog, int which) {\n                if (OdooAccountManager.removeAccount(\n                        OdooAccountQuickManage.this, user.getAndroidName())) {\n                    new Handler().postDelayed(new Runnable() {\n                        @Override\n                        public void run() {\n                            Intent loginActivity = new Intent(OdooAccountQuickManage.this,\n                                    OdooLogin.class);\n                            loginActivity.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);\n                            startActivity(loginActivity);\n                            finish();\n                        }\n                    }, 500);\n                }\n            }\n        });\n        builder.setOnCancelListener(new DialogInterface.OnCancelListener() {\n            @Override\n            public void onCancel(DialogInterface dialog) {\n                dialog.dismiss();\n                finish();\n            }\n        });\n        builder.setNegativeButton(R.string.label_cancel, new DialogInterface.OnClickListener() {\n            @Override\n            public void onClick(DialogInterface dialog, int which) {\n                dialog.dismiss();\n                finish();\n            }\n        });\n        builder.show();\n    }\n\n    @Override\n    public void onClick(View v) {\n        ONotificationBuilder.cancelNotification(this, OSyncAdapter.REQUEST_SIGN_IN_ERROR);\n        switch (v.getId()) {\n            case R.id.cancel:\n                finish();\n                break;\n            case R.id.save_password:\n                savePassword();\n                break;\n        }\n    }\n\n    private void savePassword() {\n        edtPassword = (EditText) findViewById(R.id.newPassword);\n        edtPassword.setError(null);\n        if (TextUtils.isEmpty(edtPassword.getText())) {\n            edtPassword.setError(\"Password required\");\n            edtPassword.requestFocus();\n        }\n        user.setPassword(edtPassword.getText().toString());\n        loginProcess = new LoginProcess();\n        loginHelper = new OdooLoginHelper(getApplicationContext());\n        loginProcess.execute(user.getDBName(), user.getHost());\n    }\n\n    private class LoginProcess extends AsyncTask<String, Void, OUser> {\n\n        private ProgressDialog progressDialog;\n\n        @Override\n        protected void onPreExecute() {\n            super.onPreExecute();\n            progressDialog = new ProgressDialog(OdooAccountQuickManage.this);\n            progressDialog.setTitle(R.string.title_working);\n            progressDialog.setMessage(OResource.string(OdooAccountQuickManage.this,\n                    R.string.toast_updating_password));\n            progressDialog.setCancelable(false);\n            progressDialog.show();\n        }\n\n        @Override\n        protected OUser doInBackground(String... params) {\n\n            try {\n                return loginHelper.login(user.getUsername(), user.getPassword(), user.getDatabase(), params[1], user.isAllowSelfSignedSSL());\n            } catch (Exception e) {\n                e.printStackTrace();\n            }\n            return null;\n        }\n\n        @Override\n        protected void onPostExecute(OUser oUser) {\n            super.onPostExecute(oUser);\n            progressDialog.dismiss();\n            if (oUser != null) {\n                OdooAccountManager.updateUserData(OdooAccountQuickManage.this, user);\n                finish();\n                Intent intent = new Intent(OdooAccountQuickManage.this, OdooActivity.class);\n                intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);\n                intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);\n                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\n                getApplicationContext().startActivity(intent);\n            } else {\n                edtPassword.setText(\"\");\n                edtPassword.setError(\"Password required\");\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/core/account/OdooLogin.java",
    "content": "package com.odoo.core.account;\n\nimport android.app.AlertDialog;\nimport android.content.DialogInterface;\nimport android.content.Intent;\nimport android.os.AsyncTask;\nimport android.os.Bundle;\nimport android.os.Handler;\nimport android.support.v7.app.ActionBarActivity;\nimport android.text.TextUtils;\nimport android.text.method.LinkMovementMethod;\nimport android.util.Log;\nimport android.view.Menu;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.widget.ArrayAdapter;\nimport android.widget.EditText;\nimport android.widget.Spinner;\nimport android.widget.TextView;\nimport android.widget.Toast;\n\nimport com.odoo.OdooActivity;\nimport com.odoo.R;\nimport com.odoo.base.addons.res.ResCompany;\nimport com.odoo.core.auth.OdooAccountManager;\nimport com.odoo.core.auth.OdooAuthenticator;\nimport com.odoo.core.orm.ODataRow;\nimport com.odoo.core.support.OUser;\nimport com.odoo.core.support.OdooInstancesSelectorDialog;\nimport com.odoo.core.support.OdooLoginHelper;\nimport com.odoo.core.support.OdooServerTester;\nimport com.odoo.core.support.OdooUserLoginSelectorDialog;\nimport com.odoo.core.utils.IntentUtils;\nimport com.odoo.core.utils.OAlertDialog;\nimport com.odoo.core.utils.OResource;\nimport com.odoo.datas.OConstants;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport javax.net.ssl.SSLPeerUnverifiedException;\n\nimport odoo.OdooAccountExpireException;\nimport odoo.OdooInstance;\n\npublic class OdooLogin extends ActionBarActivity implements View.OnClickListener, View.OnFocusChangeListener, OdooInstancesSelectorDialog.OnInstanceSelectListener, OdooUserLoginSelectorDialog.IUserLoginSelectListener {\n\n    private EditText edtUsername, edtPassword, edtSelfHosted;\n    private Boolean mCreateAccountRequest = false;\n    private Boolean mSelfHostedURL = false;\n    private Boolean mForceConnect = false;\n    private Boolean mConnectedToServer = false;\n    private Boolean mAutoLogin = false;\n    private Boolean mRequestedForAccount = false;\n    private OdooURLTester odooURLTester = null;\n    private LoginProcess loginProcess = null;\n    private AccountCreater accountCreator = null;\n    private OdooServerTester mServerTester = null;\n    private InstanceGetter instanceGetter = null;\n    private OdooLoginHelper loginHelper = null;\n    private Spinner databaseSpinner = null;\n    private List<String> databases = new ArrayList<String>();\n    private TextView mLoginProcessStatus = null;\n    private TextView mTermsCondition;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.base_login);\n        Bundle extras = getIntent().getExtras();\n        if (extras != null) {\n            if (extras.containsKey(OdooAuthenticator.KEY_NEW_ACCOUNT_REQUEST))\n                mCreateAccountRequest = true;\n            if (extras.containsKey(OdooActivity.KEY_ACCOUNT_REQUEST)) {\n                mRequestedForAccount = true;\n                setResult(RESULT_CANCELED);\n            }\n        }\n        if (!mCreateAccountRequest) {\n            if (OdooAccountManager.anyActiveUser(this)) {\n                startOdooActivity();\n                return;\n            } else if (OdooAccountManager.hasAnyAccount(this)) {\n                onRequestAccountSelect();\n            }\n        }\n        init();\n    }\n\n    private void init() {\n        loginHelper = new OdooLoginHelper(this);\n        mServerTester = new OdooServerTester(this);\n        mLoginProcessStatus = (TextView) findViewById(R.id.login_process_status);\n        mTermsCondition = (TextView) findViewById(R.id.termsCondition);\n        mTermsCondition.setMovementMethod(LinkMovementMethod.getInstance());\n        findViewById(R.id.btnLogin).setOnClickListener(this);\n        findViewById(R.id.forgot_password).setOnClickListener(this);\n        findViewById(R.id.create_account).setOnClickListener(this);\n        findViewById(R.id.txvAddSelfHosted).setOnClickListener(this);\n        edtSelfHosted = (EditText) findViewById(R.id.edtSelfHostedURL);\n    }\n\n    private void startOdooActivity() {\n        startActivity(new Intent(this, OdooActivity.class));\n        finish();\n    }\n\n    @Override\n    public boolean onCreateOptionsMenu(Menu menu) {\n        getMenuInflater().inflate(R.menu.menu_base_login, menu);\n        return true;\n    }\n\n    @Override\n    public boolean onOptionsItemSelected(MenuItem item) {\n        return super.onOptionsItemSelected(item);\n    }\n\n    @Override\n    public void onClick(View v) {\n        switch (v.getId()) {\n            case R.id.txvAddSelfHosted:\n                toggleSelfHostedURL();\n                break;\n            case R.id.btnLogin:\n                loginUser();\n                break;\n            case R.id.forgot_password:\n                IntentUtils.openURLInBrowser(this, OConstants.URL_ODOO_RESET_PASSWORD);\n                break;\n            case R.id.create_account:\n                IntentUtils.openURLInBrowser(this, OConstants.URL_ODOO_SIGN_UP);\n                break;\n        }\n    }\n\n    private void toggleSelfHostedURL() {\n        TextView txvAddSelfHosted = (TextView) findViewById(R.id.txvAddSelfHosted);\n        if (!mSelfHostedURL) {\n            mSelfHostedURL = true;\n            findViewById(R.id.layoutSelfHosted).setVisibility(View.VISIBLE);\n            edtSelfHosted.setOnFocusChangeListener(this);\n            edtSelfHosted.requestFocus();\n            txvAddSelfHosted.setText(R.string.label_login_with_odoo);\n        } else {\n            findViewById(R.id.layoutBorderDB).setVisibility(View.GONE);\n            findViewById(R.id.layoutDatabase).setVisibility(View.GONE);\n            findViewById(R.id.layoutSelfHosted).setVisibility(View.GONE);\n            mSelfHostedURL = false;\n            txvAddSelfHosted.setText(R.string.label_add_self_hosted_url);\n            edtSelfHosted.setText(\"\");\n        }\n    }\n\n    @Override\n    public void onFocusChange(final View v, final boolean hasFocus) {\n        new Handler().postDelayed(new Runnable() {\n            @Override\n            public void run() {\n                if (odooURLTester != null) {\n                    odooURLTester.cancel(true);\n                }\n                if (mSelfHostedURL && v.getId() == R.id.edtSelfHostedURL && !hasFocus) {\n                    if (!TextUtils.isEmpty(edtSelfHosted.getText())\n                            && validateURL(edtSelfHosted.getText().toString())) {\n                        String test_url = createServerURL(edtSelfHosted.getText().toString());\n                        odooURLTester = new OdooURLTester();\n                        odooURLTester.execute(test_url);\n                    }\n                }\n            }\n        }, 500);\n    }\n\n    private boolean validateURL(String url) {\n        return (url.contains(\".\"));\n    }\n\n    private String createServerURL(String server_url) {\n        StringBuilder serverURL = new StringBuilder();\n        if (!server_url.contains(\"http://\") && !server_url.contains(\"https://\")) {\n            serverURL.append(\"http://\");\n        }\n        serverURL.append(server_url);\n        return serverURL.toString();\n    }\n\n    private void showForceConnectDialog() {\n        AlertDialog.Builder builder = new AlertDialog.Builder(this);\n        builder.setTitle(R.string.title_ssl_warning);\n        builder.setMessage(R.string.untrusted_ssl_warning);\n        builder.setPositiveButton(R.string.label_process_anyway,\n                new DialogInterface.OnClickListener() {\n\n                    @Override\n                    public void onClick(DialogInterface dialog, int which) {\n                        if (odooURLTester != null) {\n                            odooURLTester.cancel(true);\n                            odooURLTester = null;\n                        }\n                        mForceConnect = true;\n                        odooURLTester = new OdooURLTester();\n                        odooURLTester.execute(createServerURL(edtSelfHosted.getText().toString()));\n                    }\n                });\n        builder.setNegativeButton(R.string.label_cancel, null);\n        builder.show();\n    }\n\n    // User Login\n    private void loginUser() {\n        String serverURL = createServerURL((mSelfHostedURL) ? edtSelfHosted.getText().toString() : OConstants.URL_ODOO_ACCOUNTS);\n        String databaseName = null;\n        edtUsername = (EditText) findViewById(R.id.edtUserName);\n        edtPassword = (EditText) findViewById(R.id.edtPassword);\n\n        if (mSelfHostedURL) {\n            edtSelfHosted.setError(null);\n            if (TextUtils.isEmpty(edtSelfHosted.getText())) {\n                edtSelfHosted.setError(OResource.string(this, R.string.error_provide_server_url));\n                edtSelfHosted.requestFocus();\n                return;\n            }\n            if (databaseSpinner != null && databases.size() > 1 && databaseSpinner.getSelectedItemPosition() == 0) {\n                Toast.makeText(this, OResource.string(this, R.string.label_select_database), Toast.LENGTH_LONG).show();\n                return;\n            }\n\n        }\n        edtUsername.setError(null);\n        edtPassword.setError(null);\n        if (TextUtils.isEmpty(edtUsername.getText())) {\n            edtUsername.setError(OResource.string(this, R.string.error_provide_username));\n            edtUsername.requestFocus();\n            return;\n        }\n        if (TextUtils.isEmpty(edtPassword.getText())) {\n            edtPassword.setError(OResource.string(this, R.string.error_provide_password));\n            edtPassword.requestFocus();\n            return;\n        }\n\n        if (mConnectedToServer) {\n            databaseName = databases.get(0);\n            if (databaseSpinner != null) {\n                databaseName = databases.get(databaseSpinner.getSelectedItemPosition());\n            }\n            mAutoLogin = false;\n            if (loginProcess != null) {\n                loginProcess.cancel(true);\n            }\n            loginProcess = new LoginProcess();\n            loginProcess.execute(databaseName, serverURL);\n\n        } else {\n            if (odooURLTester != null)\n                odooURLTester.cancel(true);\n            mAutoLogin = true;\n            odooURLTester = new OdooURLTester();\n            odooURLTester.execute(serverURL);\n        }\n    }\n\n    private void showDatabases() {\n        if (databases.size() > 1) {\n            findViewById(R.id.layoutBorderDB).setVisibility(View.VISIBLE);\n            findViewById(R.id.layoutDatabase).setVisibility(View.VISIBLE);\n            databaseSpinner = (Spinner) findViewById(R.id.spinnerDatabaseList);\n            databases.add(0, OResource.string(this, R.string.label_select_database));\n            ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, databases);\n            databaseSpinner.setAdapter(adapter);\n        } else {\n            databaseSpinner = null;\n            findViewById(R.id.layoutBorderDB).setVisibility(View.GONE);\n            findViewById(R.id.layoutDatabase).setVisibility(View.GONE);\n        }\n    }\n\n    @Override\n    public void instanceSelected(OdooInstance instance, OUser user) {\n        OUser userData = user;\n        if (!instance.getInstanceUrl().equals(OConstants.URL_ODOO)) {\n            if (loginProcess != null)\n                loginProcess.cancel(true);\n            loginProcess = new LoginProcess(instance, user);\n            loginProcess.execute();\n            return;\n        }\n        accountCreator = new AccountCreater();\n        accountCreator.execute(userData);\n    }\n\n    @Override\n    public void canceledInstanceSelect() {\n        findViewById(R.id.controls).setVisibility(View.VISIBLE);\n        findViewById(R.id.login_progress).setVisibility(View.GONE);\n    }\n\n    @Override\n    public void onUserSelected(OUser user) {\n        OdooAccountManager.login(this, user.getAndroidName());\n        startOdooActivity();\n    }\n\n    @Override\n    public void onRequestAccountSelect() {\n        OdooUserLoginSelectorDialog dialog = new OdooUserLoginSelectorDialog(this);\n        dialog.setUserLoginSelectListener(this);\n        dialog.show();\n    }\n\n    @Override\n    public void onNewAccountRequest() {\n        init();\n    }\n\n    @Override\n    public void onCancelSelect() {\n    }\n\n    private class LoginProcess extends AsyncTask<String, Void, OUser> {\n\n        private OdooInstance mInstance;\n        private OUser mUser;\n        private String mExpireMessage = null;\n\n        public LoginProcess() {\n\n        }\n\n        public LoginProcess(OdooInstance instance, OUser user) {\n            mInstance = instance;\n            mUser = user;\n        }\n\n        @Override\n        protected void onPreExecute() {\n            super.onPreExecute();\n            findViewById(R.id.controls).setVisibility(View.GONE);\n            findViewById(R.id.login_progress).setVisibility(View.VISIBLE);\n            if (mInstance != null && mUser != null)\n                mLoginProcessStatus.setText(OResource.string(OdooLogin.this, R.string.status_logging_in_with_instance));\n            else\n                mLoginProcessStatus.setText(OResource.string(OdooLogin.this, R.string.status_logging_in));\n        }\n\n        @Override\n        protected OUser doInBackground(String... params) {\n            try {\n                if (mInstance == null && mUser == null) {\n                    String username = edtUsername.getText().toString();\n                    String password = edtPassword.getText().toString();\n                    return loginHelper.login(username, password, params[0], params[1], mForceConnect);\n                } else {\n                    mSelfHostedURL = true;\n                    return loginHelper.instanceLogin(mInstance, mUser);\n                }\n            } catch (OdooAccountExpireException expired) {\n                mExpireMessage = expired.getMessage();\n            } catch (Exception e) {\n                e.printStackTrace();\n            }\n            return null;\n        }\n\n        @Override\n        protected void onPostExecute(OUser user) {\n            super.onPostExecute(user);\n            edtUsername.setError(null);\n            if (user == null) {\n                findViewById(R.id.controls).setVisibility(View.VISIBLE);\n                findViewById(R.id.login_progress).setVisibility(View.GONE);\n                if (mExpireMessage != null) {\n                    mSelfHostedURL = false;\n                    OAlertDialog dialog = new OAlertDialog(OdooLogin.this);\n                    dialog.setTitle(OResource.string(OdooLogin.this, R.string.title_instance_expired));\n                    dialog.setMessage(mExpireMessage);\n                    dialog.show();\n                } else {\n                    edtUsername.setError(OResource.string(OdooLogin.this, R.string.error_invalid_username_or_password));\n                }\n            } else {\n                mLoginProcessStatus.setText(OResource.string(OdooLogin.this, R.string.status_login_success));\n                if (!mSelfHostedURL) {\n                    instanceGetter = new InstanceGetter();\n                    instanceGetter.execute(user);\n                } else {\n                    accountCreator = new AccountCreater();\n                    accountCreator.execute(user);\n                }\n            }\n        }\n    }\n\n    private class InstanceGetter extends AsyncTask<OUser, Void, List<OdooInstance>> {\n\n        private OUser mUser;\n\n        @Override\n        protected void onPreExecute() {\n            super.onPreExecute();\n            mLoginProcessStatus.setText(OResource.string(OdooLogin.this, R.string.status_getting_instances));\n        }\n\n        @Override\n        protected List<OdooInstance> doInBackground(OUser... params) {\n            mUser = params[0];\n            return loginHelper.getOdooInstances(mUser);\n        }\n\n        @Override\n        protected void onPostExecute(List<OdooInstance> odooInstances) {\n            super.onPostExecute(odooInstances);\n            if (odooInstances.size() > 1) {\n                OdooInstancesSelectorDialog instancesSelectorDialog = new OdooInstancesSelectorDialog(OdooLogin.this, mUser);\n                instancesSelectorDialog.setInstances(odooInstances);\n                instancesSelectorDialog.setOnInstanceSelectListener(OdooLogin.this);\n                instancesSelectorDialog.showDialog();\n            } else {\n                // Login to default odoo instance (www.odoo.com)\n                accountCreator = new AccountCreater();\n                accountCreator.execute(mUser);\n            }\n        }\n    }\n\n    private class AccountCreater extends AsyncTask<OUser, Void, Boolean> {\n\n        private OUser mUser;\n\n        @Override\n        protected void onPreExecute() {\n            super.onPreExecute();\n            mLoginProcessStatus.setText(OResource.string(OdooLogin.this, R.string.status_creating_account));\n        }\n\n        @Override\n        protected Boolean doInBackground(OUser... params) {\n            mUser = params[0];\n            if (OdooAccountManager.createAccount(OdooLogin.this, params[0])) {\n                mUser = OdooAccountManager.getDetails(OdooLogin.this, mUser.getAndroidName());\n                try {\n                    // Syncing company details\n                    ODataRow company_details = new ODataRow();\n                    company_details.put(\"id\", mUser.getCompany_id());\n                    ResCompany company = new ResCompany(OdooLogin.this, mUser);\n                    company.quickCreateRecord(company_details);\n\n                    Thread.sleep(500);\n                } catch (Exception e) {\n                    e.printStackTrace();\n                }\n                return true;\n            }\n            return false;\n        }\n\n        @Override\n        protected void onPostExecute(Boolean success) {\n            super.onPostExecute(success);\n            mLoginProcessStatus.setText(OResource.string(OdooLogin.this, R.string.status_redirecting));\n            new Handler().postDelayed(new Runnable() {\n                @Override\n                public void run() {\n                    if (!mRequestedForAccount)\n                        startOdooActivity();\n                    else {\n                        Intent intent = new Intent();\n                        intent.putExtra(OdooActivity.KEY_NEW_USER_NAME, mUser.getAndroidName());\n                        setResult(RESULT_OK, intent);\n                        finish();\n                    }\n                }\n            }, 1500);\n        }\n    }\n\n    private class OdooURLTester extends AsyncTask<String, Void, Boolean> {\n\n        private Boolean mRequiredForceConnect = false;\n\n        @Override\n        protected void onPreExecute() {\n            super.onPreExecute();\n            Log.v(\"OdooURLTester\", \"Connecting to Server\");\n            edtSelfHosted.setError(null);\n            if (mAutoLogin) {\n                findViewById(R.id.controls).setVisibility(View.GONE);\n                findViewById(R.id.login_progress).setVisibility(View.VISIBLE);\n                mLoginProcessStatus.setText(OResource.string(OdooLogin.this, R.string.status_connecting_to_server));\n            }\n            findViewById(R.id.imgValidURL).setVisibility(View.GONE);\n            findViewById(R.id.serverURLCheckProgress).setVisibility(View.VISIBLE);\n            findViewById(R.id.layoutBorderDB).setVisibility(View.GONE);\n            findViewById(R.id.layoutDatabase).setVisibility(View.GONE);\n        }\n\n        @Override\n        protected Boolean doInBackground(String... params) {\n            try {\n                return mServerTester.testConnection(params[0], mForceConnect);\n            } catch (SSLPeerUnverifiedException peer) {\n                mRequiredForceConnect = true;\n            } catch (Exception e) {\n                e.printStackTrace();\n            }\n            return false;\n        }\n\n        @Override\n        protected void onPostExecute(Boolean success) {\n            super.onPostExecute(success);\n            findViewById(R.id.serverURLCheckProgress).setVisibility(View.GONE);\n            edtSelfHosted.setError(null);\n            if (success) {\n                // Connected to server\n                Log.v(\"OdooURLTester\", \"Connected to server.\");\n                mLoginProcessStatus.setText(OResource.string(OdooLogin.this, R.string.status_connected_to_server));\n                databases.clear();\n                databases.addAll(mServerTester.getDatabases());\n                showDatabases();\n                mConnectedToServer = true;\n                findViewById(R.id.imgValidURL).setVisibility(View.VISIBLE);\n                if (mAutoLogin) {\n                    loginUser();\n                }\n            } else if (mRequiredForceConnect) {\n                showForceConnectDialog();\n            } else {\n                edtSelfHosted.setError(OResource.string(OdooLogin.this, R.string.error_invalid_odoo_url));\n                edtSelfHosted.requestFocus();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/core/account/OdooUserAskPassword.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 8/4/15 12:06 PM\n */\npackage com.odoo.core.account;\n\nimport android.app.AlertDialog;\nimport android.content.Context;\nimport android.content.DialogInterface;\nimport android.graphics.Bitmap;\nimport android.text.TextUtils;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.widget.EditText;\nimport android.widget.Toast;\n\nimport com.odoo.R;\nimport com.odoo.core.support.OUser;\nimport com.odoo.core.utils.BitmapUtils;\nimport com.odoo.core.utils.OControls;\n\npublic class OdooUserAskPassword {\n\n    public static final String TAG = OdooUserAskPassword.class.getSimpleName();\n    private Context mContext;\n    private OUser mUser;\n    private OnUserPasswordValidateListener mOnUserPasswordValidateListener;\n    private AlertDialog.Builder builder;\n    private EditText edtPassword;\n\n    public OdooUserAskPassword(Context context, OUser user) {\n        mContext = context;\n        mUser = user;\n        builder = new AlertDialog.Builder(context);\n    }\n\n    public static OdooUserAskPassword get(Context context, OUser user) {\n        return new OdooUserAskPassword(context, user);\n    }\n\n    public void show() {\n        builder.setView(getView());\n        builder.setPositiveButton(R.string.label_login, new DialogInterface.OnClickListener() {\n            @Override\n            public void onClick(DialogInterface dialog, int which) {\n\n                String password = edtPassword.getText().toString();\n                if (TextUtils.isEmpty(password)) {\n                    Toast.makeText(mContext, R.string.error_provide_password, Toast.LENGTH_LONG).show();\n                    show();\n                } else {\n                    if (password.equals(mUser.getPassword())) {\n                        mOnUserPasswordValidateListener.onSuccess();\n                    } else {\n                        mOnUserPasswordValidateListener.onFail();\n                    }\n                }\n                dialog.dismiss();\n            }\n        });\n        builder.setNegativeButton(R.string.label_cancel, new DialogInterface.OnClickListener() {\n            @Override\n            public void onClick(DialogInterface dialog, int which) {\n                dialog.dismiss();\n                mOnUserPasswordValidateListener.onCancel();\n            }\n        });\n        builder.create().show();\n    }\n\n    private View getView() {\n        View view = LayoutInflater.from(mContext)\n                .inflate(R.layout.base_account_ask_pass, null, false);\n        String avatar = mUser.getAvatar();\n        Bitmap bitmap;\n        if (avatar.equals(\"false\")) {\n            bitmap = BitmapUtils.getAlphabetImage(mContext, mUser.getName());\n        } else {\n            bitmap = BitmapUtils.getBitmapImage(mContext, avatar);\n        }\n        OControls.setImage(view, R.id.userAvatar, bitmap);\n        OControls.setText(view, R.id.txvUsername, mUser.getName());\n        edtPassword = (EditText) view.findViewById(R.id.edtPassword);\n        return view;\n    }\n\n    public OdooUserAskPassword setOnUserPasswordValidateListener(OnUserPasswordValidateListener listener) {\n        mOnUserPasswordValidateListener = listener;\n        return this;\n    }\n\n    public interface OnUserPasswordValidateListener {\n        public void onSuccess();\n\n        public void onCancel();\n\n        public void onFail();\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/core/account/Profile.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 9/1/15 11:54 AM\n */\npackage com.odoo.core.account;\n\nimport android.graphics.Bitmap;\nimport android.graphics.Color;\nimport android.graphics.drawable.ColorDrawable;\nimport android.os.Bundle;\nimport android.os.Handler;\nimport android.support.v7.app.ActionBarActivity;\nimport android.view.View;\nimport android.widget.ImageView;\nimport android.widget.TextView;\n\nimport com.odoo.R;\nimport com.odoo.core.orm.ODataRow;\nimport com.odoo.core.support.OUser;\nimport com.odoo.core.utils.BitmapUtils;\nimport com.odoo.core.utils.OActionBarUtils;\nimport com.odoo.core.utils.OStringColorUtil;\nimport com.odoo.widgets.parallax.ParallaxScrollView;\n\nimport odoo.controls.OField;\nimport odoo.controls.OForm;\n\npublic class Profile extends ActionBarActivity implements View.OnClickListener {\n    public static final String TAG = Profile.class.getSimpleName();\n    private OUser user;\n    private OForm form;\n    private ParallaxScrollView parallaxScrollView;\n    private TextView title;\n    private Handler handler = null;\n    private int click_count = 0;\n    public static String CONNECT_WITH_ODOO = \"enable_connect_with_odoo\";\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.base_profile);\n        OActionBarUtils.setActionBar(this, false);\n        user = OUser.current(this);\n        form = (OForm) findViewById(R.id.profileDetails);\n        OField user_login = (OField) findViewById(R.id.user_login);\n        parallaxScrollView = (ParallaxScrollView) findViewById(R.id.parallaxScrollView);\n        parallaxScrollView.setActionBar(getSupportActionBar());\n        setTitle(\"\");\n        getSupportActionBar().setBackgroundDrawable(new ColorDrawable((Color.parseColor(\"#00000000\"))));\n        title = (TextView) findViewById(android.R.id.title);\n        int color = OStringColorUtil.getStringColor(this, user.getName());\n        parallaxScrollView.setParallaxOverLayColor(color);\n        form.setIconTintColor(color);\n        ODataRow userData = new ODataRow();\n        userData.put(\"name\", user.getName());\n        userData.put(\"user_login\", user.getUsername());\n        userData.put(\"server_url\", (user.isOAauthLogin()) ? user.getInstanceUrl() : user.getHost());\n        userData.put(\"database\", (user.isOAauthLogin()) ? user.getInstanceDatabase() : user.getDatabase());\n        userData.put(\"version\", user.getVersion_serie());\n        userData.put(\"timezone\", user.getTimezone());\n        form.initForm(userData);\n        title.setText(userData.getString(\"name\"));\n\n        Bitmap avatar;\n        if (user.getAvatar().equals(\"false\")) {\n            avatar = BitmapUtils.getAlphabetImage(this, user.getName());\n        } else {\n            avatar = BitmapUtils.getBitmapImage(this, user.getAvatar());\n        }\n        ImageView imageView = (ImageView) findViewById(android.R.id.icon);\n        imageView.setImageBitmap(avatar);\n        user_login.setOnClickListener(this);\n\n    }\n\n    @Override\n    public void onClick(View v) {\n//        FIXME:\n//\n//          handler = getWindow().getDecorView().getHandler();\n//        click_count = click_count + 1;\n//        Runnable r = new Runnable() {\n//            public void run() {\n//                click_count = 0;\n//            }\n//        };\n//        handler.postDelayed(r, 7000);\n//\n//        if (click_count == 3) {\n//            Toast.makeText(this, \"Need 2 Tap to connect with odoo\", Toast.LENGTH_SHORT).show();\n//        }\n//        if (click_count == 5) {\n//            OPreferenceManager pref = new OPreferenceManager(this);\n//            pref.setBoolean(CONNECT_WITH_ODOO, true);\n//        }\n    }\n}\n\n"
  },
  {
    "path": "app/src/main/java/com/odoo/core/auth/OdooAccountManager.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 17/12/14 6:21 PM\n */\npackage com.odoo.core.auth;\n\nimport android.accounts.Account;\nimport android.accounts.AccountManager;\nimport android.content.Context;\nimport android.util.Log;\n\nimport com.odoo.App;\nimport com.odoo.core.orm.OModelRegistry;\nimport com.odoo.core.support.OUser;\nimport com.odoo.core.utils.sys.OCacheUtils;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class OdooAccountManager {\n\n    public static final String TAG = OdooAccountManager.class.getSimpleName();\n    public static final String KEY_ACCOUNT_TYPE = \"com.odoo.auth\";\n\n    /**\n     * Gets all the account related Odoo Auth\n     *\n     * @param context\n     * @return List of OUser instances if any\n     */\n    public static List<OUser> getAllAccounts(Context context) {\n        List<OUser> users = new ArrayList<OUser>();\n        AccountManager aManager = AccountManager.get(context);\n        for (Account account : aManager.getAccountsByType(KEY_ACCOUNT_TYPE)) {\n            OUser user = new OUser();\n            user.fillFromAccount(aManager, account);\n            user.setAccount(account);\n            users.add(user);\n        }\n        return users;\n    }\n\n    /**\n     * Check for any account availability\n     *\n     * @param context\n     * @return true, if any account found\n     */\n    public static boolean hasAnyAccount(Context context) {\n        if (getAllAccounts(context).size() > 0)\n            return true;\n        return false;\n    }\n\n    /**\n     * Creates Odoo account for app\n     *\n     * @param context\n     * @param user    user instance (OUser)\n     * @return true, if account created successfully\n     */\n    public static boolean createAccount(Context context, OUser user) {\n        AccountManager accountManager = AccountManager.get(context);\n        Account account = new Account(user.getAndroidName(), KEY_ACCOUNT_TYPE);\n        return accountManager.addAccountExplicitly(account, String.valueOf(user.getPassword()), \n                user.getAsBundle());\n    }\n\n    /**\n     * Remove account from device\n     *\n     * @param context\n     * @param username\n     * @return true, if account removed successfully\n     */\n    public static boolean removeAccount(Context context, String username) {\n        OUser user = getDetails(context, username);\n        if (user != null) {\n            AccountManager accountManager = AccountManager.get(context);\n            accountManager.removeAccount(user.getAccount(), null, null);\n            return true;\n        }\n        return false;\n    }\n\n    /**\n     * Updates user bundle data in accounts\n     *\n     * @param context\n     * @param newData instance of OUser class\n     * @return new user object with updated values\n     */\n    public static OUser updateUserData(Context context, OUser newData) {\n        OUser user = getDetails(context, newData.getAndroidName());\n        if (user != null) {\n            AccountManager accountManager = AccountManager.get(context);\n            for (String key : newData.getAsBundle().keySet()) {\n                accountManager.setUserData(user.getAccount(), key, newData.getAsBundle().getString(key));\n            }\n        }\n        return newData;\n    }\n\n    /**\n     * Finds any active user for application\n     *\n     * @param context\n     * @return true, if there is any active user for app\n     */\n    public static boolean anyActiveUser(Context context) {\n        for (OUser user : getAllAccounts(context)) {\n            if (user.isIsactive()) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    /**\n     * Gets active user object\n     *\n     * @param context\n     * @return user object (Instance of OUser class)\n     */\n    public static OUser getActiveUser(Context context) {\n        for (OUser user : getAllAccounts(context)) {\n            if (user.isIsactive()) {\n                return user;\n            }\n        }\n        return null;\n    }\n\n    /**\n     * Returns OUser object with username\n     *\n     * @param context\n     * @param username\n     * @return instance for OUser class or null\n     */\n    public static OUser getDetails(Context context, String username) {\n        for (OUser user : getAllAccounts(context))\n            if (user.getAndroidName().equals(username)) {\n                return user;\n            }\n        return null;\n    }\n\n    /**\n     * Login to user account. changes active state for user.\n     * Other users will be automatically logged out\n     *\n     * @param context\n     * @param username\n     * @return new user object\n     */\n    public static OUser login(Context context, String username) {\n\n        // Setting odoo instance to null\n        App app = (App) context.getApplicationContext();\n        app.setOdoo(null, null);\n        // Clearing models registry\n        OModelRegistry registry = new OModelRegistry();\n        registry.clearAll();\n        OUser activeUser = getActiveUser(context);\n        // Logging out user if any\n        if (activeUser != null) {\n            logout(context, activeUser.getAndroidName());\n        }\n\n        OUser newUser = getDetails(context, username);\n        if (newUser != null) {\n            AccountManager accountManager = AccountManager.get(context);\n            accountManager.setUserData(newUser.getAccount(), \"isactive\", \"true\");\n            Log.i(TAG, newUser.getName() + \" Logged in successfully\");\n            return newUser;\n        }\n        // Clearing old cache of the system\n        OCacheUtils.clearSystemCache(context);\n        return null;\n    }\n\n    /**\n     * Logout user\n     *\n     * @param context\n     * @param username\n     * @return true, if successfully logged out\n     */\n    public static boolean logout(Context context, String username) {\n        OUser user = getDetails(context, username);\n        if (user != null) {\n            if (cancelUserSync(user.getAccount())) {\n                AccountManager accountManager = AccountManager.get(context);\n                accountManager.setUserData(user.getAccount(), \"isactive\", \"false\");\n                Log.i(TAG, user.getName() + \" Logged out successfully\");\n                return true;\n            }\n        }\n        return false;\n    }\n\n    private static boolean cancelUserSync(Account account) {\n        //Cancel user's sync services. if any.\n        return true;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/core/auth/OdooAuthService.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 17/12/14 6:20 PM\n */\npackage com.odoo.core.auth;\n\nimport android.accounts.AccountManager;\nimport android.app.Service;\nimport android.content.Intent;\nimport android.os.IBinder;\n\npublic class OdooAuthService extends Service {\n    private OdooAuthenticator mAuthenticator;\n\n    @Override\n    public IBinder onBind(Intent intent) {\n        IBinder binder = null;\n        if (intent.getAction().equals(AccountManager.ACTION_AUTHENTICATOR_INTENT)) {\n            mAuthenticator = new OdooAuthenticator(this);\n            binder = mAuthenticator.getIBinder();\n        }\n        return binder;\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/core/auth/OdooAuthenticator.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 17/12/14 6:21 PM\n */\npackage com.odoo.core.auth;\n\nimport android.accounts.AbstractAccountAuthenticator;\nimport android.accounts.Account;\nimport android.accounts.AccountAuthenticatorResponse;\nimport android.accounts.AccountManager;\nimport android.accounts.NetworkErrorException;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.support.annotation.NonNull;\n\nimport com.odoo.core.account.OdooLogin;\nimport com.odoo.core.orm.OSQLite;\nimport com.odoo.core.support.OUser;\n\npublic class OdooAuthenticator extends AbstractAccountAuthenticator {\n\n    public static final String TAG = OdooAuthenticator.class.getSimpleName();\n    public static final String KEY_NEW_ACCOUNT_REQUEST = \"create_new_account\";\n    private Context mContext;\n\n    public OdooAuthenticator(Context context) {\n        super(context);\n        mContext = context;\n    }\n\n    @Override\n    public Bundle addAccount(AccountAuthenticatorResponse response, String accountType, String authTokenType, String[] requiredFeatures, Bundle options) throws NetworkErrorException {\n        final Bundle result;\n        final Intent intent;\n\n        intent = new Intent(mContext, OdooLogin.class);\n        result = new Bundle();\n        intent.putExtra(KEY_NEW_ACCOUNT_REQUEST, true);\n        result.putParcelable(AccountManager.KEY_INTENT, intent);\n\n        return result;\n    }\n\n    @NonNull\n    @Override\n    public Bundle getAccountRemovalAllowed(AccountAuthenticatorResponse response, Account account) throws NetworkErrorException {\n        Bundle result = super.getAccountRemovalAllowed(response, account);\n        if (result != null\n                && result.containsKey(AccountManager.KEY_BOOLEAN_RESULT)\n                && !result.containsKey(AccountManager.KEY_INTENT)) {\n            final boolean removalAllowed = result\n                    .getBoolean(AccountManager.KEY_BOOLEAN_RESULT);\n\n            if (removalAllowed) {\n                OUser user = OdooAccountManager.getDetails(mContext, account.name);\n                OSQLite sqLite = new OSQLite(mContext, user);\n                sqLite.dropDatabase();\n            }\n        }\n        return result;\n    }\n\n    @Override\n    public Bundle editProperties(AccountAuthenticatorResponse response, String accountType) {\n        return null;\n    }\n\n\n    @Override\n    public Bundle confirmCredentials(AccountAuthenticatorResponse response, Account account, Bundle options) throws NetworkErrorException {\n        return null;\n    }\n\n    @Override\n    public Bundle getAuthToken(AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options) throws NetworkErrorException {\n        return null;\n    }\n\n    @Override\n    public String getAuthTokenLabel(String authTokenType) {\n        return null;\n    }\n\n    @Override\n    public Bundle updateCredentials(AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options) throws NetworkErrorException {\n        return null;\n    }\n\n    @Override\n    public Bundle hasFeatures(AccountAuthenticatorResponse response, Account account, String[] features) throws NetworkErrorException {\n        return null;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/core/orm/ODataRow.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 31/12/14 6:47 PM\n */\npackage com.odoo.core.orm;\n\nimport android.os.Bundle;\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\nimport com.odoo.core.orm.fields.OColumn;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\n\npublic class ODataRow implements Parcelable {\n    public static final String TAG = ODataRow.class.getSimpleName();\n\n    HashMap<String, Object> _data = new HashMap<>();\n\n    public void put(String key, Object value) {\n        _data.put(key, value);\n    }\n\n    public Object get(String key) {\n        return _data.get(key);\n    }\n\n    public Integer getInt(String key) {\n        if (_data.get(key).toString().equals(\"false\"))\n            return 0;\n        else\n            return Integer.parseInt(_data.get(key).toString());\n    }\n\n    public Float getFloat(String key) {\n        if (_data.get(key).toString().equals(\"false\")) {\n            _data.put(key, 0);\n        }\n        return Float.parseFloat(_data.get(key).toString());\n    }\n\n    public String getString(String key) {\n        if (_data.containsKey(key) && _data.get(key) != null)\n            return _data.get(key).toString();\n        else\n            return \"false\";\n    }\n\n    public Boolean getBoolean(String key) {\n        return Boolean.parseBoolean(_data.get(key).toString());\n    }\n\n\n    public OM2ORecord getM2ORecord(String key) {\n        return (OM2ORecord) _data.get(key);\n    }\n\n    public OM2MRecord getM2MRecord(String key) {\n        return (OM2MRecord) _data.get(key);\n    }\n\n    public OO2MRecord getO2MRecord(String key) {\n        return (OO2MRecord) _data.get(key);\n    }\n\n    public List<Object> values() {\n        List<Object> values = new ArrayList<>();\n        values.addAll(_data.values());\n        return values;\n    }\n\n    public List<String> keys() {\n        List<String> list = new ArrayList<>();\n        list.addAll(_data.keySet());\n        return list;\n    }\n\n    public boolean contains(String key) {\n        return _data.containsKey(key);\n    }\n\n    public int size() {\n        return _data.size();\n    }\n\n    @Override\n    public String toString() {\n        return _data.toString();\n    }\n\n    @Override\n    public int describeContents() {\n        return 0;\n    }\n\n    @Override\n    public void writeToParcel(Parcel dest, int flags) {\n\n    }\n\n    public void remove(String key) {\n        _data.remove(key);\n    }\n\n    public class IdName {\n        Integer id;\n        String name;\n\n        public IdName(Integer id, String name) {\n            super();\n            this.id = id;\n            this.name = name;\n        }\n\n        public Integer getId() {\n            return id;\n        }\n\n        public void setId(Integer id) {\n            this.id = id;\n        }\n\n        public String getName() {\n            return name;\n        }\n\n        public void setName(String name) {\n            this.name = name;\n        }\n\n    }\n\n    public void addAll(HashMap<String, Object> data) {\n        _data.putAll(data);\n    }\n\n    public void addAll(ODataRow row) {\n        _data.putAll(row.getAll());\n    }\n\n    public HashMap<String, Object> getAll() {\n        return _data;\n    }\n\n    public OValues toValues() {\n        OValues values = new OValues();\n        values.addAll(getAll());\n        return values;\n    }\n\n    public Bundle getPrimaryBundleData() {\n        Bundle bundle = new Bundle();\n        bundle.putInt(\"id\", getInt(\"id\"));\n        bundle.putInt(OColumn.ROW_ID, getInt(OColumn.ROW_ID));\n        return bundle;\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/core/orm/OM2MRecord.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 31/12/14 6:51 PM\n */\npackage com.odoo.core.orm;\n\nimport com.odoo.core.orm.fields.OColumn;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class OM2MRecord {\n    public static final String TAG = OM2MRecord.class.getSimpleName();\n    private OColumn mCol = null;\n    private int mId = 0;\n    private OModel mDatabase = null;\n\n    public OM2MRecord(OModel model, OColumn col, int id) {\n        mDatabase = model;\n        mCol = col;\n        mId = id;\n    }\n\n    public List<Integer> getRelIds() {\n        List<Integer> ids = new ArrayList<>();\n        for (ODataRow row : mDatabase.selectManyToManyRecords(new String[]{OColumn.ROW_ID},\n                mCol.getName(), mId)) {\n            ids.add(row.getInt(OColumn.ROW_ID));\n        }\n        return ids;\n    }\n\n    public List<ODataRow> browseEach() {\n        return mDatabase.selectManyToManyRecords(null, mCol.getName(), mId);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/core/orm/OM2ORecord.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 31/12/14 6:50 PM\n */\npackage com.odoo.core.orm;\n\nimport com.odoo.core.orm.fields.OColumn;\n\npublic class OM2ORecord {\n    public static final String TAG = OM2ORecord.class.getSimpleName();\n    private OColumn mCol = null;\n    private Integer record_id = 0;\n    private OModel base_model = null;\n    private OModel rel_model = null;\n\n    public OM2ORecord(OModel base, OColumn col, Integer rec_id) {\n        base_model = base;\n        mCol = col;\n        record_id = rec_id;\n    }\n\n    public Integer getId() {\n        return record_id;\n    }\n\n    public String getName() {\n        rel_model = base_model.createInstance(mCol.getType());\n        return rel_model.browse(new String[]{\"name\"}, OColumn.ROW_ID + \"=?\",\n                new String[]{record_id + \"\"}).getString(\"name\");\n    }\n\n    public ODataRow browse(OModel rel_model) {\n        if (record_id != null) {\n            return rel_model.browse(record_id);\n        }\n        return null;\n    }\n\n    public ODataRow browse() {\n        rel_model = base_model.createInstance(mCol.getType());\n        return browse(rel_model);\n    }\n\n    @Override\n    public String toString() {\n        return record_id + \"\";\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/core/orm/OModel.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 30/12/14 3:31 PM\n */\npackage com.odoo.core.orm;\n\nimport android.content.ContentValues;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.SyncResult;\nimport android.database.Cursor;\nimport android.database.sqlite.SQLiteDatabase;\nimport android.net.Uri;\nimport android.util.Log;\n\nimport com.odoo.App;\nimport com.odoo.base.addons.ir.IrModel;\nimport com.odoo.core.auth.OdooAccountManager;\nimport com.odoo.core.orm.annotation.Odoo;\nimport com.odoo.core.orm.fields.OColumn;\nimport com.odoo.core.orm.fields.types.OBoolean;\nimport com.odoo.core.orm.fields.types.ODateTime;\nimport com.odoo.core.orm.fields.types.OInteger;\nimport com.odoo.core.orm.fields.types.OSelection;\nimport com.odoo.core.orm.provider.BaseModelProvider;\nimport com.odoo.core.service.ISyncServiceListener;\nimport com.odoo.core.service.OSyncAdapter;\nimport com.odoo.core.support.OUser;\nimport com.odoo.core.support.OdooFields;\nimport com.odoo.core.utils.OCursorUtils;\nimport com.odoo.core.utils.ODateUtils;\nimport com.odoo.core.utils.OListUtils;\nimport com.odoo.core.utils.OPreferenceManager;\nimport com.odoo.core.utils.OStorageUtils;\nimport com.odoo.core.utils.StringUtils;\n\nimport org.json.JSONArray;\nimport org.json.JSONObject;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InvalidObjectException;\nimport java.lang.annotation.Annotation;\nimport java.lang.reflect.Constructor;\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Method;\nimport java.nio.channels.FileChannel;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Calendar;\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Locale;\n\nimport odoo.ODomain;\nimport odoo.OdooVersion;\n\npublic class OModel implements ISyncServiceListener {\n\n    public static final String TAG = OModel.class.getSimpleName();\n    public String BASE_AUTHORITY = \"com.odoo.crm.core.provider.content\";\n    public static final String KEY_UPDATE_IDS = \"key_update_ids\";\n    public static final String KEY_INSERT_IDS = \"key_insert_ids\";\n    public static final int INVALID_ROW_ID = -1;\n    public static OSQLite sqLite = null;\n    private Context mContext;\n    private OUser mUser;\n    private String model_name = null;\n    private List<OColumn> mColumns = new ArrayList<>();\n    private List<OColumn> mRelationColumns = new ArrayList<>();\n    private List<OColumn> mFunctionalColumns = new ArrayList<>();\n    private HashMap<String, Field> mDeclaredFields = new HashMap<>();\n    private OdooVersion mOdooVersion = null;\n    private String default_name_column = \"name\";\n    public static OModelRegistry modelRegistry = new OModelRegistry();\n    private boolean hasMailChatter = false;\n\n    // Relation record command\n    public enum Command {\n        Add(0), Update(1), Delete(2), Replace(6);\n\n        int type;\n\n        Command(int type) {\n            this.type = type;\n        }\n\n        public int getValue() {\n            return type;\n        }\n    }\n\n    // Base Columns\n    OColumn id = new OColumn(\"ID\", OInteger.class).setDefaultValue(0);\n    @Odoo.api.v8\n    @Odoo.api.v9alpha\n    public OColumn create_date = new OColumn(\"Created On\", ODateTime.class);\n\n    @Odoo.api.v8\n    @Odoo.api.v9alpha\n    public OColumn write_date = new OColumn(\"Last Updated On\", ODateTime.class);\n\n    // Local Base columns\n    OColumn _id = new OColumn(\"_ID\", OInteger.class).setAutoIncrement().setLocalColumn();\n    OColumn _write_date = new OColumn(\"Local Write Date\", ODateTime.class).setLocalColumn();\n    OColumn _is_dirty = new OColumn(\"Dirty record\", OBoolean.class).setDefaultValue(false).setLocalColumn();\n    OColumn _is_active = new OColumn(\"Active Record\", OBoolean.class).setDefaultValue(true).setLocalColumn();\n\n    public OModel(Context context, String model_name, OUser user) {\n        mContext = context;\n        mUser = (user == null) ? OUser.current(context) : user;\n        this.model_name = model_name;\n        if (mUser != null) {\n            mOdooVersion = new OdooVersion();\n            mOdooVersion.setVersion_number(mUser.getVersion_number());\n            mOdooVersion.setServer_serie(mUser.getVersion_serie());\n            if (sqLite == null) {\n                sqLite = new OSQLite(mContext, mUser);\n            }\n        }\n    }\n\n    public SQLiteDatabase getReadableDatabase() {\n        return sqLite.getReadableDatabase();\n    }\n\n    public SQLiteDatabase getWritableDatabase() {\n        return sqLite.getWritableDatabase();\n    }\n\n    public String getDatabaseName() {\n        return sqLite.getDatabaseName();\n    }\n\n    public void close() {\n        // Any operation when closing database\n    }\n\n    public void setDefaultNameColumn(String nameColumn) {\n        default_name_column = nameColumn;\n    }\n\n    public String getDefaultNameColumn() {\n        return default_name_column;\n    }\n\n    public OModel setModelName(String model_name) {\n        this.model_name = model_name;\n        return this;\n    }\n\n    public boolean hasMailChatter() {\n        return hasMailChatter;\n    }\n\n    public void setHasMailChatter(boolean hasMailChatter) {\n        this.hasMailChatter = hasMailChatter;\n    }\n\n    public OUser getUser() {\n        return mUser;\n    }\n\n    public OdooVersion getOdooVersion() {\n        return mOdooVersion;\n    }\n\n    public List<OColumn> getColumns() {\n        if (mColumns.size() == 0) {\n            prepareFields();\n        }\n        return mColumns;\n    }\n\n    public List<OColumn> getColumns(Boolean local) {\n        if (local != null) {\n            List<OColumn> cols = new ArrayList<>();\n            for (OColumn column : getColumns())\n                if (local == column.isLocal())\n                    cols.add(column);\n            return cols;\n        } else {\n            return mColumns;\n        }\n    }\n\n    public List<OColumn> getRelationColumns() {\n        if (mColumns.size() <= 0)\n            prepareFields();\n        return mRelationColumns;\n    }\n\n    public OColumn getColumn(String column_name) {\n        if (mDeclaredFields.size() <= 0)\n            prepareFields();\n        Field filed = mDeclaredFields.get(column_name);\n        return getColumn(filed);\n    }\n\n    private OColumn getColumn(Field field) {\n        OColumn column = null;\n        if (field != null) {\n            try {\n                field.setAccessible(true);\n                column = (OColumn) field.get(this);\n                if (column.getName() == null)\n                    column.setName(field.getName());\n                Boolean validField = compatibleField(field);\n                if (validField) {\n                    // Functional Method\n                    Method method = checkForFunctionalColumn(field);\n                    if (method != null) {\n                        column.setIsFunctionalColumn(true);\n                        column.setFunctionalMethod(method);\n                        column.setFunctionalStore(checkForFunctionalStore(field));\n                        column.setFunctionalStoreDepends(getFunctionalDepends(field));\n                        if (!column.canFunctionalStore()) {\n                            column.setLocalColumn();\n                        }\n                    }\n\n                    // Onchange method for column\n                    Method onChangeMethod = checkForOnChangeMethod(field);\n                    if (onChangeMethod != null) {\n                        column.setOnChangeMethod(onChangeMethod);\n                        column.setOnChangeBGProcess(checkForOnChangeBGProcess(field));\n                    }\n\n                    // domain filter on column\n                    column.setHasDomainFilterColumn(isDomainFilterColumn(field));\n                    return column;\n                }\n            } catch (Exception e) {\n                e.printStackTrace();\n                Log.e(TAG, e.getMessage());\n            }\n        }\n        return null;\n    }\n\n    private boolean isDomainFilterColumn(Field field) {\n        Annotation annotation = field.getAnnotation(Odoo.hasDomainFilter.class);\n        if (annotation != null) {\n            Odoo.hasDomainFilter domainFilter = (Odoo.hasDomainFilter) annotation;\n            return domainFilter.checkDomainRuntime();\n        }\n        return false;\n    }\n\n    private Boolean checkForOnChangeBGProcess(Field field) {\n        Annotation annotation = field.getAnnotation(Odoo.onChange.class);\n        if (annotation != null) {\n            Odoo.onChange onChange = (Odoo.onChange) annotation;\n            return onChange.bg_process();\n        }\n        return false;\n    }\n\n    private Method checkForOnChangeMethod(Field field) {\n        Annotation annotation = field.getAnnotation(Odoo.onChange.class);\n        if (annotation != null) {\n            Odoo.onChange onChange = (Odoo.onChange) annotation;\n            String method_name = onChange.method();\n            try {\n                return getClass().getMethod(method_name, ODataRow.class);\n            } catch (NoSuchMethodException e) {\n                Log.e(TAG, \"No Such Method: \" + e.getMessage());\n            }\n        }\n        return null;\n    }\n\n    /**\n     * Check for functional store.\n     *\n     * @param field the field\n     * @return the boolean\n     */\n    public Boolean checkForFunctionalStore(Field field) {\n        Annotation annotation = field.getAnnotation(Odoo.Functional.class);\n        if (annotation != null) {\n            Odoo.Functional functional = (Odoo.Functional) annotation;\n            return functional.store();\n        }\n        return false;\n    }\n\n\n    /**\n     * Gets the functional depends.\n     *\n     * @param field the field\n     * @return the functional depends\n     */\n    public String[] getFunctionalDepends(Field field) {\n        Annotation annotation = field.getAnnotation(Odoo.Functional.class);\n        if (annotation != null) {\n            Odoo.Functional functional = (Odoo.Functional) annotation;\n            return functional.depends();\n        }\n        return null;\n    }\n\n    private Method checkForFunctionalColumn(Field field) {\n        Annotation annotation = field.getAnnotation(Odoo.Functional.class);\n        if (annotation != null) {\n            Odoo.Functional functional = (Odoo.Functional) annotation;\n            String method_name = functional.method();\n            try {\n                if (functional.store())\n                    return getClass().getMethod(method_name, OValues.class);\n                else\n                    return getClass().getMethod(method_name, ODataRow.class);\n            } catch (NoSuchMethodException e) {\n                Log.e(TAG, \"No Such Method: \" + e.getMessage());\n            }\n        }\n        return null;\n    }\n\n    private boolean compatibleField(Field field) {\n        if (mOdooVersion != null) {\n            Annotation[] annotations = field.getDeclaredAnnotations();\n            if (annotations.length > 0) {\n                int version = 0;\n                for (Annotation annotation : annotations) {\n                    // Check for odoo api annotation\n                    Class<? extends Annotation> type = annotation.annotationType();\n                    if (type.getDeclaringClass().isAssignableFrom(Odoo.api.class)) {\n                        switch (mOdooVersion.getVersion_number()) {\n                            case 9:\n                                if (type.isAssignableFrom(Odoo.api.v9alpha.class)) {\n                                    version++;\n                                }\n                                break;\n                            case 8:\n                                if (type.isAssignableFrom(Odoo.api.v8.class)) {\n                                    version++;\n                                }\n                                break;\n                            case 7:\n                                if (type.isAssignableFrom(Odoo.api.v7.class)) {\n                                    version++;\n                                }\n                                break;\n                        }\n                    }\n                    // Check for functional annotation\n                    if (type.isAssignableFrom(Odoo.Functional.class)\n                            || type.isAssignableFrom(Odoo.onChange.class)\n                            || type.isAssignableFrom(Odoo.hasDomainFilter.class)) {\n                        version++;\n                    }\n                }\n                return (version > 0) ? true : false;\n            }\n            return true;\n        }\n        return false;\n    }\n\n    private void prepareFields() {\n        mColumns.clear();\n        mRelationColumns.clear();\n        List<Field> fields = new ArrayList<>();\n        fields.addAll(Arrays.asList(getClass().getSuperclass().getDeclaredFields()));\n        fields.addAll(Arrays.asList(getClass().getDeclaredFields()));\n        mDeclaredFields.clear();\n        for (Field field : fields) {\n            if (field.getType().isAssignableFrom(OColumn.class)) {\n                String name = field.getName();\n                try {\n                    OColumn column = getColumn(field);\n                    if (column != null) {\n                        name = column.getName();\n                        if (column.getRelationType() != null) {\n                            mRelationColumns.add(column);\n                        }\n                        if (column.isFunctionalColumn()) {\n                            if (column.canFunctionalStore()) {\n                                mColumns.add(column);\n                            }\n                            mFunctionalColumns.add(column);\n                        } else {\n                            mColumns.add(column);\n                        }\n                    }\n                } catch (Exception e) {\n                    e.printStackTrace();\n                }\n                mDeclaredFields.put(name, field);\n            }\n        }\n    }\n\n    public List<OColumn> getFunctionalColumns() {\n        if (mColumns.size() <= 0)\n            prepareFields();\n        return mFunctionalColumns;\n    }\n\n    public String getModelName() {\n        return model_name;\n    }\n\n    public List<OColumn> getManyToManyColumns(OModel relation_model) {\n        List<OColumn> cols = new ArrayList<OColumn>();\n        _write_date.setName(\"_write_date\");\n        cols.add(_write_date);\n        _is_dirty.setName(\"_is_dirty\");\n        cols.add(_is_dirty);\n        _is_active.setName(\"_is_active\");\n        cols.add(_is_active);\n\n        OColumn base_id = new OColumn(\"Base Id\", OInteger.class);\n        base_id.setName(getTableName() + \"_id\");\n        cols.add(base_id);\n        OColumn relation_id = new OColumn(\"Relation Id\", OInteger.class);\n        relation_id.setName(relation_model.getTableName() + \"_id\");\n        cols.add(relation_id);\n        return cols;\n    }\n\n    public OModel createInstance(Class<?> type) {\n        try {\n            Constructor<?> constructor = type.getConstructor(Context.class, OUser.class);\n            return (OModel) constructor.newInstance(mContext, mUser);\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return null;\n    }\n\n    public String getTableName() {\n        return getModelName().replaceAll(\"\\\\.\", \"_\");\n    }\n\n    public String toString() {\n        return getModelName();\n    }\n\n    public static OModel get(Context context, String model_name, String username) {\n        OModel model = modelRegistry.getModel(model_name, username);\n        OUser user = OdooAccountManager.getDetails(context, username);\n        if (model == null) {\n            try {\n                OPreferenceManager pfManager = new OPreferenceManager(context);\n                Class<?> model_class = Class.forName(pfManager.getString(model_name, null));\n                if (model_class != null) {\n                    model = new OModel(context, model_name, user).createInstance(model_class);\n                    if (model != null) {\n                        modelRegistry.register(model);\n                    }\n                }\n            } catch (Exception e) {\n                e.printStackTrace();\n            }\n        }\n        return model;\n    }\n\n    public String authority() {\n        return BASE_AUTHORITY;\n    }\n\n    public Uri buildURI(String authority) {\n        BASE_AUTHORITY = authority;\n        String path = getModelName().toLowerCase(Locale.getDefault());\n        return BaseModelProvider.buildURI(BASE_AUTHORITY, path, mUser.getAndroidName());\n    }\n\n    public Uri uri() {\n        String path = getModelName().toLowerCase(Locale.getDefault());\n        return BaseModelProvider.buildURI(BASE_AUTHORITY, path, mUser.getAndroidName());\n    }\n\n    public ODomain defaultDomain() {\n        return new ODomain();\n    }\n\n    private String[] updateProjection(String[] projection) {\n        HashSet<String> names = new HashSet<>();\n        String[] allProjection = projection;\n        if (allProjection == null) {\n            allProjection = projection();\n        } else {\n            for (String col : projection) {\n                OColumn column = getColumn(col);\n                if (column.isFunctionalColumn() && column.canFunctionalStore()) {\n                    names.add(column.getName());\n                }\n            }\n        }\n        names.addAll(Arrays.asList(allProjection));\n        names.addAll(Arrays.asList(new String[]{OColumn.ROW_ID, \"id\", \"_write_date\", \"_is_dirty\", \"_is_active\"}));\n        return names.toArray(new String[names.size()]);\n    }\n\n    public String[] projection(Boolean onlyServerColumns) {\n        List<String> names = new ArrayList<>();\n        for (OColumn column : getColumns(false)) {\n            if (column.getRelationType() == null || column.canFunctionalStore()) {\n                names.add(column.getName());\n            } else if (column.getRelationType() == OColumn.RelationType.ManyToOne) {\n                names.add(column.getName());\n            }\n        }\n        return names.toArray(new String[names.size()]);\n    }\n\n    public String[] projection() {\n        List<String> names = new ArrayList<>();\n        for (OColumn column : getColumns()) {\n            if (column.getRelationType() == null || column.canFunctionalStore()) {\n                names.add(column.getName());\n            } else if (column.getRelationType() == OColumn.RelationType.ManyToOne) {\n                names.add(column.getName());\n            }\n        }\n        return names.toArray(new String[names.size()]);\n    }\n\n    // Sync default methods\n    public boolean checkForCreateDate() {\n        return true;\n    }\n\n    public boolean checkForWriteDate() {\n        return true;\n    }\n\n    public boolean allowUpdateRecordOnServer() {\n        return true;\n    }\n\n    public boolean allowCreateRecordOnServer() {\n        return true;\n    }\n\n    public boolean allowDeleteRecordOnServer() {\n        return true;\n    }\n\n    public boolean allowDeleteRecordInLocal() {\n        return true;\n    }\n\n    // Database Operations\n\n    public String getLabel(String column, String key) {\n        OColumn col = getColumn(column);\n        if (col.getType().isAssignableFrom(OSelection.class)) {\n            return col.getSelectionMap().get(key);\n        }\n        return \"false\";\n    }\n\n    public ODataRow browse(int row_id) {\n        return browse(null, row_id);\n    }\n\n    public ODataRow browse(String[] projection, int row_id) {\n        List<ODataRow> rows = select(projection, OColumn.ROW_ID + \" = ?\", new String[]{row_id + \"\"});\n        if (rows.size() > 0) {\n            return rows.get(0);\n        }\n        return null;\n    }\n\n    public ODataRow browse(String[] projection, String selection, String[] args) {\n        List<ODataRow> rows = select(updateProjection(projection), selection, args);\n        if (rows.size() > 0) {\n            return rows.get(0);\n        }\n        return null;\n    }\n\n    public List<Integer> getServerIds() {\n        List<Integer> ids = new ArrayList<>();\n        for (ODataRow row : select(new String[]{\"id\"})) {\n            if (row.getInt(\"id\") != 0) {\n                ids.add(row.getInt(\"id\"));\n            }\n        }\n        return ids;\n    }\n\n    public boolean isEmptyTable() {\n        return (count(null, null) <= 0);\n    }\n\n    public String getLastSyncDateTime() {\n        IrModel model = new IrModel(mContext, mUser);\n        List<ODataRow> records = model.select(null, \"model = ?\", new String[]{getModelName()});\n        if (records.size() > 0) {\n            String date = records.get(0).getString(\"last_synced\");\n            Date write_date = ODateUtils.createDateObject(date, ODateUtils.DEFAULT_FORMAT, true);\n            Calendar cal = Calendar.getInstance();\n            cal.setTime(write_date);\n            /*\n                Fixed for Postgres SQL\n                It stores milliseconds so comparing date wrong. \n             */\n            cal.set(Calendar.SECOND, cal.get(Calendar.SECOND) + 2);\n            write_date = cal.getTime();\n            return ODateUtils.getDate(write_date, ODateUtils.DEFAULT_FORMAT);\n        }\n        return null;\n    }\n\n    public List<ODataRow> select() {\n        return select(null, null, null, null);\n    }\n\n    public List<ODataRow> select(String[] projection) {\n        return select(projection, null, null, null);\n    }\n\n    public List<ODataRow> select(String[] projection, String where, String[] args) {\n        return select(projection, where, args, null);\n    }\n\n    public List<ODataRow> select(String[] projection, String where, String[] args, String sortOrder) {\n        Cursor cr = mContext.getContentResolver().query(uri(),\n                updateProjection(projection), where, args, sortOrder);\n        List<ODataRow> rows = new ArrayList<>();\n        try {\n            if (cr != null && cr.moveToFirst()) {\n                do {\n                    ODataRow row = OCursorUtils.toDatarow(cr);\n                    for (OColumn column : getRelationColumns(projection)) {\n                        if (!row.getString(column.getName()).equals(\"false\")\n                                || column.getRelationType() == OColumn.RelationType.OneToMany\n                                || column.getRelationType() == OColumn.RelationType.ManyToMany) {\n                            switch (column.getRelationType()) {\n                                case ManyToMany:\n                                    OM2MRecord m2mRecords = new OM2MRecord(this, column, row.getInt(OColumn.ROW_ID));\n                                    row.put(column.getName(), m2mRecords);\n                                    break;\n                                case ManyToOne:\n                                    OM2ORecord m2ORecord = new OM2ORecord(this, column, row.getInt(column.getName()));\n                                    row.put(column.getName(), m2ORecord);\n                                    break;\n                                case OneToMany:\n                                    OO2MRecord o2MRecord = new OO2MRecord(this, column, row.getInt(OColumn.ROW_ID));\n                                    row.put(column.getName(), o2MRecord);\n                                    break;\n                            }\n                        }\n                    }\n                    for (OColumn column : getFunctionalColumns(projection)) {\n                        List<String> depends = column.getFunctionalStoreDepends();\n                        if (depends != null && depends.size() > 0) {\n                            ODataRow values = new ODataRow();\n                            for (String depend : depends) {\n                                if (row.contains(depend)) {\n                                    values.put(depend, row.get(depend));\n                                }\n                            }\n                            if (values.size() == depends.size()) {\n                                Object value = getFunctionalMethodValue(column, values);\n                                row.put(column.getName(), value);\n                            }\n                        }\n                    }\n                    rows.add(row);\n                } while (cr.moveToNext());\n            }\n        } finally {\n            cr.close();\n        }\n        return rows;\n    }\n\n    public Object getFunctionalMethodValue(OColumn column, Object record) {\n        if (column.isFunctionalColumn()) {\n            Method method = column.getFunctionalMethod();\n            OModel model = this;\n            try {\n                return method.invoke(model, new Object[]{record});\n            } catch (Exception e) {\n                e.printStackTrace();\n            }\n        }\n        return false;\n    }\n\n    public Object getOnChangeMethodValue(OColumn column, Object record) {\n        Method method = column.getOnChangeMethod();\n        OModel model = this;\n        try {\n            return method.invoke(model, new Object[]{record});\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return false;\n    }\n\n    private List<OColumn> getFunctionalColumns(String[] projection) {\n        List<OColumn> cols = new ArrayList<>();\n        if (projection != null) {\n            for (String key : projection) {\n                OColumn column = getColumn(key);\n                if (column.isFunctionalColumn() && !column.canFunctionalStore()) {\n                    cols.add(column);\n                }\n            }\n        } else {\n            for (OColumn column : getFunctionalColumns()) {\n                if (!column.canFunctionalStore())\n                    cols.add(column);\n            }\n        }\n        return cols;\n    }\n\n    private List<OColumn> getRelationColumns(String[] projection) {\n        List<OColumn> cols = new ArrayList<>();\n        if (projection != null) {\n            for (String key : projection) {\n                OColumn column = getColumn(key);\n                if (column.getRelationType() != null) {\n                    cols.add(column);\n                }\n            }\n        } else {\n            cols.addAll(getRelationColumns());\n        }\n        return cols;\n    }\n\n    public int insertOrUpdate(int serverId, OValues values) {\n        if (hasServerRecord(serverId)) {\n            int row_id = selectRowId(serverId);\n            update(row_id, values);\n            return row_id;\n        } else {\n            return insert(values);\n        }\n    }\n\n    public int insertOrUpdate(String selection, String[] args, OValues values) {\n        int count = update(selection, args, values);\n        if (count <= 0) {\n            return insert(values);\n        } else {\n            return selectRowId(selection, args);\n        }\n    }\n\n    public int selectRowId(String selection, String[] args) {\n        int row_id = INVALID_ROW_ID;\n        SQLiteDatabase db = getReadableDatabase();\n        Cursor cr = db.query(getTableName(), new String[]{OColumn.ROW_ID}, selection, args, null, null, null);\n        try {\n            if (cr.moveToFirst()) {\n                row_id = cr.getInt(0);\n            }\n        } finally {\n            cr.close();\n        }\n        return row_id;\n    }\n\n    public int selectServerId(int row_id) {\n        return browse(row_id).getInt(\"id\");\n    }\n\n    public int selectRowId(int server_id) {\n        List<ODataRow> rows = select(new String[]{OColumn.ROW_ID}, \"id = ?\", new String[]{server_id + \"\"});\n        if (rows.size() > 0) {\n            return rows.get(0).getInt(OColumn.ROW_ID);\n        }\n        return INVALID_ROW_ID;\n    }\n\n    public int insert(OValues values) {\n        Uri uri = mContext.getContentResolver().insert(uri(), values.toContentValues());\n        if (uri != null) {\n            return Integer.parseInt(uri.getLastPathSegment());\n        }\n        return INVALID_ROW_ID;\n    }\n\n\n    public boolean hasServerRecord(int server_id) {\n        int count = count(\"id = ? \", new String[]{server_id + \"\"});\n        return (count > 0);\n    }\n\n    public boolean isServerRecordDirty(int server_id) {\n        int count = count(\"id = ? and _is_dirty = ?\", new String[]{server_id + \"\", \"true\"});\n        return (count > 0);\n    }\n\n    public boolean hasRecord(int row_id) {\n        int count = count(OColumn.ROW_ID + \" = ? \", new String[]{row_id + \"\"});\n        return (count > 0);\n    }\n\n\n    public int deleteRecords(List<Integer> serverIds, boolean permanently) {\n        String selection = \"id IN (\" + StringUtils.repeat(\"?, \", serverIds.size() - 1) + \" ?)\";\n        String[] args = OListUtils.toStringList(serverIds).toArray(new String[serverIds.size()]);\n        if (permanently) {\n            return delete(selection, args, true);\n        } else {\n            OValues values = new OValues();\n            values.put(\"_is_active\", \"false\");\n            return update(selection, args, values);\n        }\n    }\n\n    public int delete(String selection, String[] args) {\n        return delete(selection, args, false);\n    }\n\n    public int delete(String selection, String[] args, boolean permanently) {\n        int count = 0;\n        if (permanently) {\n            count = mContext.getContentResolver().delete(uri(), selection, args);\n        } else {\n            List<ODataRow> records = select(new String[]{\"_is_active\"}, selection, args);\n            for (ODataRow row : records) {\n                if (row.getBoolean(\"_is_active\")) {\n                    OValues values = new OValues();\n                    values.put(\"_is_active\", \"false\");\n                    update(row.getInt(OColumn.ROW_ID), values);\n                }\n                count++;\n            }\n        }\n        return count;\n    }\n\n    public boolean delete(int row_id) {\n        return delete(row_id, false);\n    }\n\n    public boolean delete(int row_id, boolean permanently) {\n        int count = 0;\n        if (permanently)\n            count = mContext.getContentResolver().delete(uri().withAppendedPath(uri(), row_id + \"\"), null, null);\n        else {\n            OValues values = new OValues();\n            values.put(\"_is_active\", \"false\");\n            update(row_id, values);\n            count++;\n        }\n        return (count > 0) ? true : false;\n    }\n\n    public int update(String selection, String[] args, OValues values) {\n        return mContext.getContentResolver().update(uri(), values.toContentValues(), selection, args);\n    }\n\n    public boolean update(int row_id, OValues values) {\n        int count = mContext.getContentResolver().update(uri().withAppendedPath(uri(), row_id + \"\"),\n                values.toContentValues(), null, null);\n        return (count > 0) ? true : false;\n    }\n\n\n    public List<ODataRow> query(String query) {\n        return query(query, null);\n    }\n\n    public List<ODataRow> query(String query, String[] args) {\n        List<ODataRow> rows = new ArrayList<>();\n        SQLiteDatabase db = getReadableDatabase();\n        Cursor cr = db.rawQuery(query, args);\n        try {\n            if (cr.moveToFirst()) {\n                do {\n                    rows.add(OCursorUtils.toDatarow(cr));\n                } while (cr.moveToNext());\n            }\n        } finally {\n            cr.close();\n        }\n        return rows;\n\n    }\n\n    public int count(String selection, String[] args) {\n        int count = 0;\n        SQLiteDatabase db = getReadableDatabase();\n        Cursor cr = db.query(getTableName(), new String[]{\"count(*)\"}, selection, args, null, null, null);\n        try {\n            cr.moveToFirst();\n            count = cr.getInt(0);\n        } finally {\n            cr.close();\n        }\n        return count;\n    }\n\n\n    public void storeManyToManyRecord(String column_name, int row_id, List<Integer> relationIds,\n                                      Command command)\n            throws InvalidObjectException {\n        OColumn column = getColumn(column_name);\n        if (column != null) {\n            OModel rel_model = createInstance(column.getType());\n            String table = getTableName() + \"_\" + rel_model.getTableName() + \"_rel\";\n            String base_column = getTableName() + \"_id\";\n            String rel_column = rel_model.getTableName() + \"_id\";\n\n            SQLiteDatabase db = getWritableDatabase();\n            try {\n                switch (command) {\n                    case Add:\n                        if (relationIds.size() > 0) {\n                            for (int id : relationIds) {\n                                ContentValues values = new ContentValues();\n                                values.put(base_column, row_id);\n                                values.put(rel_column, id);\n                                values.put(\"_write_date\", ODateUtils.getDate());\n                                db.insert(table, null, values);\n                            }\n                        }\n                        break;\n                    case Update:\n                        break;\n                    case Delete:\n                        // Deleting records to relation model\n                        if (relationIds.size() > 0) {\n                            for (int id : relationIds) {\n                                db.delete(table, base_column + \" = ? AND  \" + rel_column\n                                        + \" = ?\", new String[]{row_id + \"\", id + \"\"});\n                            }\n                        }\n                        break;\n                    case Replace:\n                        // Removing old entries\n                        db.delete(table, base_column + \" = ?\", new String[]{row_id + \"\"});\n                        // Creating new entries\n                        storeManyToManyRecord(column_name, row_id, relationIds, Command.Add);\n                        break;\n                }\n            } finally {\n                db.close();\n                rel_model.close();\n            }\n        } else {\n            throw new InvalidObjectException(\"Column [\" + column_name + \"] not found in \" + getModelName() + \" model.\");\n\n        }\n    }\n\n    public List<ODataRow> selectManyToManyRecords(String[] projection, String column_name, int row_id) {\n        OColumn column = getColumn(column_name);\n        OModel rel_model = createInstance(column.getType());\n        String table = getTableName() + \"_\" + rel_model.getTableName() + \"_rel\";\n        String base_column = getTableName() + \"_id\";\n        String rel_column = rel_model.getTableName() + \"_id\";\n\n        // Getting relation table ids\n        List<String> ids = new ArrayList<>();\n        SQLiteDatabase db = getReadableDatabase();\n        Cursor cr = null;\n        try {\n            cr = db.query(table, new String[]{rel_column}, base_column + \"=?\",\n                    new String[]{row_id + \"\"}, null, null, null);\n            if (cr.moveToFirst()) {\n                do {\n                    ids.add(cr.getInt(0) + \"\");\n                } while (cr.moveToNext());\n            }\n        } finally {\n            if (cr != null) {\n                cr.close();\n            }\n        }\n        List<ODataRow> data = rel_model.select(projection, OColumn.ROW_ID + \" IN (\" + StringUtils.repeat(\" ?, \", ids.size() - 1) + \" ?)\",\n                ids.toArray(new String[ids.size()]));\n        rel_model.close();\n        return data;\n    }\n\n    public ServerDataHelper getServerDataHelper() {\n        return new ServerDataHelper(mContext, this, getUser());\n    }\n\n    public String getName(int row_id) {\n        ODataRow row = browse(row_id);\n        if (row != null) {\n            return row.getString(\"name\");\n        }\n        return \"false\";\n    }\n\n    public void quickSyncRecords(ODomain domain) {\n        OSyncAdapter syncAdapter = new OSyncAdapter(mContext, getClass(), null, true);\n        syncAdapter.setModel(this);\n        syncAdapter.setDomain(domain);\n        syncAdapter.checkForWriteCreateDate(false);\n        syncAdapter.onPerformSync(getUser().getAccount(), null, authority(), null, new SyncResult());\n    }\n\n    public ODataRow quickCreateRecord(ODataRow record) {\n        OSyncAdapter syncAdapter = new OSyncAdapter(mContext, getClass(), null, true);\n        syncAdapter.setModel(this);\n        ODomain domain = new ODomain();\n        domain.add(\"id\", \"=\", record.getInt(\"id\"));\n        syncAdapter.setDomain(domain);\n        syncAdapter.checkForWriteCreateDate(false);\n        syncAdapter.onPerformSync(getUser().getAccount(), null, authority(), null, new SyncResult());\n        return browse(null, \"id = ?\", new String[]{record.getString(\"id\")});\n    }\n\n    public ODataRow countGroupBy(String column, String group_by, String having, String[] args) {\n        String sql = \"select count(*) as total, \" + column;\n        sql += \" from \" + getTableName() + \" group by \" + group_by + \" having \" + having;\n        List<ODataRow> data = query(sql, args);\n        if (data.size() > 0) {\n            return data.get(0);\n        } else {\n            ODataRow row = new ODataRow();\n            row.put(\"total\", 0);\n            return row;\n        }\n    }\n\n    public boolean isInstalledOnServer(String module_name) {\n        try {\n            App app = (App) mContext.getApplicationContext();\n            IrModel model = new IrModel(mContext, getUser());\n            List<ODataRow> modules = model.select(null, \"name = ?\", new String[]{module_name.trim()});\n            if (modules.size() > 0) {\n                if (modules.get(0).getString(\"state\").equals(\"installed\")) {\n                    return true;\n                }\n            }\n            if (app.inNetwork()) {\n                odoo.Odoo odoo = app.getOdoo(getUser());\n                OdooFields fields = new OdooFields(new String[]{\"state\", \"name\"});\n                ODomain domain = new ODomain();\n                domain.add(\"name\", \"=\", module_name);\n                JSONArray result = odoo.search_read(\"ir.module.module\", fields.get(), domain.get())\n                        .getJSONArray(\"records\");\n                if (result.length() > 0) {\n                    JSONObject record = result.getJSONObject(0);\n                    if (record.getString(\"state\").equals(\"installed\")) {\n                        OValues values = new OValues();\n                        values.put(\"id\", record.getInt(\"id\"));\n                        values.put(\"name\", record.getString(\"name\"));\n                        values.put(\"state\", record.getString(\"state\"));\n                        model.insertOrUpdate(record.getInt(\"id\"), values);\n                        return true;\n                    }\n                }\n\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return false;\n    }\n\n    public String getDatabaseLocalPath() {\n        return sqLite.databaseLocalPath();\n    }\n\n    public void exportDB() {\n        FileChannel source;\n        FileChannel destination;\n        String currentDBPath = getDatabaseLocalPath();\n        String backupDBPath = OStorageUtils.getDirectoryPath(\"file\")\n                + \"/\" + getDatabaseName();\n        File currentDB = new File(currentDBPath);\n        File backupDB = new File(backupDBPath);\n        try {\n            source = new FileInputStream(currentDB).getChannel();\n            destination = new FileOutputStream(backupDB).getChannel();\n            destination.transferFrom(source, 0, source.size());\n            source.close();\n            destination.close();\n            String subject = \"Database Export: \" + getDatabaseName();\n            Uri uri = Uri.fromFile(backupDB);\n            Intent intent = new Intent(Intent.ACTION_SEND);\n            intent.putExtra(Intent.EXTRA_STREAM, uri);\n            intent.putExtra(Intent.EXTRA_SUBJECT, subject);\n            intent.setType(\"message/rfc822\");\n            mContext.startActivity(intent);\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n    }\n\n    @Override\n    public void onSyncStarted() {\n        // Will be over ride by extending model\n    }\n\n    @Override\n    public void onSyncFinished() {\n        // Will be over ride by extending model\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/core/orm/OModelRegistry.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 20/1/15 3:49 PM\n */\npackage com.odoo.core.orm;\n\nimport java.util.HashMap;\n\npublic class OModelRegistry {\n    public static final String TAG = OModelRegistry.class.getSimpleName();\n    private HashMap<String, OModel> modelRegistry = new HashMap<>();\n\n    public void register(OModel model) {\n        if (model != null && model.getModelName() != null) {\n            modelRegistry.put(getKey(model), model);\n        }\n    }\n\n    public OModel getModel(String model, String user) {\n        if (modelRegistry.containsKey(model)) {\n            String key = model + \"_\" + user;\n            return modelRegistry.get(key);\n        }\n        return null;\n    }\n\n    public void unRegister(String model, String user) {\n        if (modelRegistry.containsKey(model)) {\n            String key = model + \"_\" + user;\n            modelRegistry.remove(key);\n        }\n    }\n\n    public void clearAll() {\n        modelRegistry.clear();\n    }\n\n    public int count() {\n        return modelRegistry.size();\n    }\n\n    private String getKey(OModel model) {\n        return model.getModelName() + \"_\" + model.getUser().getAndroidName();\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/core/orm/OO2MRecord.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 31/12/14 6:51 PM\n */\npackage com.odoo.core.orm;\n\nimport com.odoo.core.orm.fields.OColumn;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class OO2MRecord {\n    public static final String TAG = OO2MRecord.class.getSimpleName();\n    private OColumn mCol = null;\n    private int mRecordId = 0;\n    private OModel mDatabase = null;\n    private OModel rel_model = null;\n    private String mOrderBy = null;\n\n    public OO2MRecord(OModel oModel, OColumn col, int id) {\n        mDatabase = oModel;\n        mCol = col;\n        mRecordId = id;\n    }\n\n    public OO2MRecord setOrder(String order_by) {\n        mOrderBy = order_by;\n        return this;\n    }\n\n    public List<Integer> getIds() {\n        rel_model = mDatabase.createInstance(mCol.getType());\n        return getIds(rel_model);\n    }\n\n    public List<Integer> getIds(OModel rel_model) {\n        List<Integer> ids = new ArrayList<>();\n        List<ODataRow> records = rel_model.select(new String[]{OColumn.ROW_ID},\n                mCol.getRelatedColumn() + \" = ?\", new String[]{mRecordId + \"\"});\n        for (ODataRow record : records) {\n            ids.add(record.getInt(OColumn.ROW_ID));\n        }\n        return ids;\n    }\n\n    public List<ODataRow> browseEach() {\n        rel_model = mDatabase.createInstance(mCol.getType());\n        return rel_model.select(null,\n                mCol.getRelatedColumn() + \" = ?\", new String[]{mRecordId + \"\"}, mOrderBy);\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/core/orm/OSQLHelper.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 31/12/14 3:11 PM\n */\npackage com.odoo.core.orm;\n\nimport android.content.Context;\nimport android.util.Log;\n\nimport com.odoo.core.orm.fields.OColumn;\nimport com.odoo.core.orm.fields.types.OInteger;\nimport com.odoo.core.orm.fields.types.OTypeHelper;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\n\npublic class OSQLHelper {\n    public static final String TAG = OSQLHelper.class.getSimpleName();\n    private Context mContext = null;\n    private List<String> mModels = new ArrayList<>();\n    private HashMap<String, String> mSQLStatements = new HashMap<>();\n\n    public OSQLHelper(Context context) {\n        mContext = context;\n    }\n\n    public List<String> getModels() {\n        return mModels;\n    }\n\n    public void createStatements(OModel model) {\n        StringBuffer sql = null;\n        if (!mModels.contains(model.getModelName())) {\n            mModels.add(model.getModelName());\n            sql = new StringBuffer();\n            sql.append(\"CREATE TABLE IF NOT EXISTS \");\n            sql.append(model.getTableName());\n            sql.append(\" (\");\n            List<OColumn> columns = model.getColumns();\n            sql.append(generateColumnStatement(model, columns));\n            sql.deleteCharAt(sql.lastIndexOf(\",\"));\n            sql.append(\")\");\n            mSQLStatements.put(model.getTableName(), sql.toString());\n        }\n    }\n\n    private String generateColumnStatement(OModel model, List<OColumn> columns) {\n        StringBuffer column_statement = new StringBuffer();\n        List<String> finishedColumns = new ArrayList<>();\n        for (OColumn column : columns) {\n            if (!finishedColumns.contains(column.getName())) {\n                finishedColumns.add(column.getName());\n                String type = getType(column);\n                if (type != null) {\n                    column_statement.append(column.getName());\n                    column_statement.append(\" \" + type + \" \");\n                    if (column.isAutoIncrement()) {\n                        column_statement.append(\" PRIMARY KEY \");\n                        column_statement.append(\" AUTOINCREMENT \");\n                    }\n                    Object default_value = column.getDefaultValue();\n                    if (default_value != null) {\n                        column_statement.append(\" DEFAULT \");\n                        if (default_value instanceof String) {\n                            column_statement.append(\"'\" + default_value + \"'\");\n                        } else {\n                            column_statement.append(default_value);\n                        }\n                    }\n                    column_statement.append(\", \");\n                }\n                if (column.getRelationType() != null) {\n                    createRelationTable(model, column);\n                }\n            }\n        }\n        return column_statement.toString();\n    }\n\n    private void createRelationTable(OModel base_model, OColumn column) {\n        try {\n            OModel rel_model = base_model.createInstance(column.getType());\n            switch (column.getRelationType()) {\n                case ManyToOne:\n                case OneToMany:\n                    createStatements(rel_model);\n                    break;\n                case ManyToMany:\n                    manyToManyTable(column, base_model);\n                    // Creating master table for related column\n                    createStatements(base_model.createInstance(column.getType()));\n                    break;\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n\n    }\n\n    private void manyToManyTable(OColumn column, OModel model) {\n        StringBuffer sql = null;\n        try {\n            OModel relation_model = model.createInstance(column.getType());\n            List<OColumn> m2mCols = model.getManyToManyColumns(relation_model);\n            String table_name = model.getTableName() + \"_\"\n                    + relation_model.getTableName() + \"_rel\";\n            if (!mModels.contains(table_name)) {\n                sql = new StringBuffer();\n                mModels.add(table_name);\n                String col_statement = generateColumnStatement(model, m2mCols);\n                sql.append(\"CREATE TABLE IF NOT EXISTS \");\n                sql.append(table_name);\n                sql.append(\" (\");\n                sql.append(col_statement);\n                sql.deleteCharAt(sql.lastIndexOf(\",\"));\n                sql.append(\")\");\n                mSQLStatements.put(table_name, sql.toString());\n                Log.v(TAG, \"Table Created : \" + table_name);\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n\n    private String getType(OColumn column) {\n        try {\n            if (column.getRelationType() == null) {\n                if (column.getType().getSuperclass().isAssignableFrom(OTypeHelper.class)) {\n                    OTypeHelper type = (OTypeHelper) column.getType().newInstance();\n                    type.setSize(column.getSize());\n                    return type.getType();\n                }\n            } else if (column.getRelationType() == OColumn.RelationType.ManyToOne) {\n                return new OInteger().getType();\n            }\n        } catch (Exception e) {\n            Log.e(TAG, e.getMessage());\n            e.printStackTrace();\n        }\n        return null;\n    }\n\n    public HashMap<String, String> getStatements() {\n        return mSQLStatements;\n    }\n\n    public void createDropStatements(OModel model) {\n        StringBuffer sql = null;\n        try {\n            if (!mModels.contains(model.getTableName())) {\n                mModels.add(model.getTableName());\n                sql = new StringBuffer();\n                sql.append(\"DROP TABLE IF EXISTS \");\n                sql.append(model.getTableName());\n                mSQLStatements.put(model.getTableName(), sql.toString());\n                Log.v(TAG, \"Table Dropped : \" + model.getTableName());\n                for (OColumn col : model.getColumns()) {\n                    if (col.getRelationType() != null) {\n                        switch (col.getRelationType()) {\n                            case ManyToMany:\n                                OModel rel = model.createInstance(col.getType());\n                                String table_name = model.getTableName() + \"_\"\n                                        + rel.getTableName() + \"_rel\";\n                                sql = new StringBuffer();\n                                sql.append(\"DROP TABLE IF EXISTS \");\n                                sql.append(table_name);\n                                mModels.add(table_name);\n                                mSQLStatements.put(table_name, sql.toString());\n                                Log.v(TAG, \"Table Dropped : \" + table_name);\n                                break;\n                            case ManyToOne:\n                            case OneToMany:\n                                createDropStatements(model.createInstance(col\n                                        .getType()));\n                                break;\n                        }\n                    }\n                }\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n\n    public List<OModel> getAllModels(List<OModel> models) {\n        mModels.clear();\n        List<OModel> all_models = new ArrayList<>();\n        for (OModel model : models) {\n            if (!mModels.contains(model.getModelName())) {\n                mModels.add(model.getModelName());\n                all_models.add(model);\n                // Checks for relation models\n                List<OModel> relModels = getRelationModels(model, model.getRelationColumns());\n                all_models.addAll(relModels);\n            }\n        }\n        mModels.clear();\n        return all_models;\n    }\n\n    private List<OModel> getRelationModels(OModel model, List<OColumn> cols) {\n        List<OModel> models = new ArrayList<>();\n        for (OColumn col : cols) {\n            OModel rel_model = model.createInstance(col.getType());\n            if (rel_model != null && !mModels.contains(rel_model.getModelName())) {\n                mModels.add(rel_model.getModelName());\n                models.add(rel_model);\n                models.addAll(getRelationModels(rel_model, rel_model.getRelationColumns()));\n            }\n        }\n        return models;\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/odoo/core/orm/OSQLite.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 30/12/14 3:31 PM\n */\npackage com.odoo.core.orm;\n\nimport android.content.Context;\nimport android.database.sqlite.SQLiteDatabase;\nimport android.database.sqlite.SQLiteOpenHelper;\nimport android.os.Environment;\nimport android.util.Log;\n\nimport com.odoo.addons.crm.models.CRMCaseCateg;\nimport com.odoo.addons.crm.models.CRMCaseStage;\nimport com.odoo.App;\nimport com.odoo.base.addons.BaseModels;\nimport com.odoo.base.addons.mail.MailMessage;\nimport com.odoo.base.addons.mail.MailMessageSubType;\nimport com.odoo.config.Addons;\nimport com.odoo.core.orm.fields.OColumn;\nimport com.odoo.core.support.OUser;\nimport com.odoo.core.support.addons.OAddon;\nimport com.odoo.core.support.addons.fragment.IBaseFragment;\nimport com.odoo.core.utils.OPreferenceManager;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class OSQLite extends SQLiteOpenHelper {\n    public static final String TAG = OSQLite.class.getSimpleName();\n    public static final String KEY_MODEL_CLASS_REGISTER = \"key_model_class_register\";\n    public static final int DATABASE_VERSION = 2;\n    private Context mContext;\n    private OUser mUser = null;\n    private Addons mAddons;\n    private OPreferenceManager mPref;\n\n    public OSQLite(Context context, OUser user) {\n        super(context, (user != null) ? user.getDBName() : OUser.current(context).getDBName(), null\n                , DATABASE_VERSION);\n        mContext = context;\n        mAddons = new Addons();\n        mUser = (user != null) ? user : OUser.current(context);\n        mPref = new OPreferenceManager(mContext);\n        synchronized (this) {\n            if (!mPref.getBoolean(KEY_MODEL_CLASS_REGISTER, false)) {\n                mPref.setBoolean(KEY_MODEL_CLASS_REGISTER, true);\n                // Registering model class paths\n                registerModelsClassPath();\n            }\n        }\n    }\n\n    private List<OModel> getModels() {\n        List<OModel> models = new ArrayList<>();\n        models.addAll(BaseModels.baseModels(mContext, mUser));\n        for (OAddon addon : mAddons.getAddons()) {\n            IBaseFragment fragment = (IBaseFragment) addon.get();\n            try {\n                Class<Object> model = fragment.database();\n                if (model != null) {\n                    OModel dbModel = (OModel) model.getConstructor(Context.class, OUser.class)\n                            .newInstance(mContext, mUser);\n                    models.add(dbModel);\n                }\n            } catch (Exception e) {\n                Log.e(TAG, e.getMessage());\n            }\n        }\n        return models;\n    }\n\n    @Override\n    public void onCreate(SQLiteDatabase db) {\n        Log.i(TAG, \"creating database.\");\n        OSQLHelper sqlHelper = new OSQLHelper(mContext);\n        // Creating tables\n        for (OModel model : getModels()) {\n            sqlHelper.createStatements(model);\n        }\n        for (String key : sqlHelper.getStatements().keySet()) {\n            String query = sqlHelper.getStatements().get(key);\n            db.execSQL(query);\n            Log.i(TAG, \"Table Created : \" + key);\n        }\n        registerModels(sqlHelper.getModels());\n    }\n\n    private void registerModels(List<String> models) {\n        OPreferenceManager mPref = new OPreferenceManager(mContext);\n        if (mPref.putStringSet(\"models\", models)) {\n            Log.i(TAG, models.size() + \" Models registered.\");\n        } else {\n            Log.e(TAG, \"Unable to register models\");\n        }\n    }\n\n    private synchronized void registerModelsClassPath() {\n        OSQLHelper sqlHelper = new OSQLHelper(mContext);\n        List<OModel> modelsClassPath = sqlHelper.getAllModels(getModels());\n        for (OModel model : modelsClassPath) {\n            String key = model.getModelName();\n            String path = model.getClass().getName();\n            // Setting class path\n            mPref.putString(key, path);\n        }\n        Log.i(TAG, modelsClassPath.size() + \" models path registered.\");\n    }\n\n    private List<String> getColumns(String model_class, boolean server_columns) {\n        List<String> cols = new ArrayList<String>();\n        try {\n            OModel m = new OModel(mContext, null, null);\n            Class<?> cls = Class.forName(model_class);\n            OModel model = m.createInstance(cls);\n            for (OColumn col : model.getColumns(!server_columns)) {\n                cols.add(col.getName());\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return cols;\n    }\n\n    @Override\n    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {\n        Log.i(TAG, \"upgrading database.\");\n        // Updates in mail messages. added subtype_id\n        MailMessageSubType subType = new MailMessageSubType(mContext, mUser);\n        MailMessage mailMessage = new MailMessage(mContext, mUser);\n\n        OSQLHelper osqlHelper;\n        // Dropping mail message\n        db.execSQL(\"DROP TABLE IF EXISTS mail_message \");\n        // re-creating mail message and sub type\n        osqlHelper = new OSQLHelper(mContext);\n        osqlHelper.createStatements(subType);\n        osqlHelper.createStatements(mailMessage);\n        for (String key : osqlHelper.getStatements().keySet()) {\n            String query = osqlHelper.getStatements().get(key);\n            db.execSQL(query);\n        }\n        registerModelsClassPath();\n        registerModels(osqlHelper.getModels());\n\n        // Updating crm case stage model name for saas-6\n        if (mUser.getVersion_serie().equals(\"8.saas~6\")) {\n            osqlHelper = new OSQLHelper(mContext);\n            CRMCaseCateg caseCateg = new CRMCaseCateg(mContext, mUser);\n            CRMCaseStage caseStage = new CRMCaseStage(mContext, mUser);\n            osqlHelper.createStatements(caseCateg);\n            osqlHelper.createStatements(caseStage);\n            registerModels(osqlHelper.getModels());\n            db.execSQL(\"ALTER TABLE crm_case_stage RENAME TO crm_stage\");\n            db.execSQL(\"ALTER TABLE crm_case_categ RENAME TO crm_lead_tag\");\n        }\n\n//            OSQLHelper sqlHelper = new OSQLHelper(mContext);\n//            for (OModel model : getModels()) {\n//                sqlHelper.createDropStatements(model);\n//            }\n//            for (String key : sqlHelper.getStatements().keySet()) {\n//                String query = sqlHelper.getStatements().get(key);\n//                db.execSQL(query);\n//                Log.i(TAG, \"Table dropped \" + key);\n//            }\n//            onCreate(db);\n    }\n\n    public void dropDatabase() {\n        if (mContext.deleteDatabase(getDatabaseName())) {\n            Log.i(TAG, getDatabaseName() + \" database dropped.\");\n        }\n    }\n\n    public String databaseLocalPath() {\n        App app = (App) mContext.getApplicationContext();\n        return Environment.getDataDirectory().getPath() +\n                \"/data/\" + app.getPackageName() + \"/databases/\" + getDatabaseName();\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/core/orm/OValues.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 31/12/14 6:49 PM\n */\npackage com.odoo.core.orm;\n\nimport android.content.ContentValues;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\n\npublic class OValues {\n    public static final String TAG = OValues.class.getSimpleName();\n    private HashMap<String, Object> _values = new HashMap<String, Object>();\n\n    public OValues() {\n        _values.clear();\n        _values = new HashMap<String, Object>();\n    }\n\n    public void put(String key, Object value) {\n        _values.put(key, value);\n    }\n\n    public Object get(String key) {\n        return _values.get(key);\n    }\n\n    public long getLong(String key) {\n        if (_values.get(key).toString().equals(\"false\")) {\n            return -1;\n        }\n        return Long.parseLong(_values.get(key).toString());\n    }\n\n    public Integer getInt(String key) {\n        if (_values.get(key).toString().equals(\"false\")) {\n            return -1;\n        }\n        return Integer.parseInt(_values.get(key).toString());\n    }\n\n    public String getString(String key) {\n        return _values.get(key).toString();\n    }\n\n    public Boolean getBoolean(String key) {\n        return Boolean.parseBoolean(_values.get(key).toString());\n    }\n\n    public boolean contains(String key) {\n        return _values.containsKey(key);\n    }\n\n    public List<String> keys() {\n        List<String> list = new ArrayList<>();\n        list.addAll(_values.keySet());\n        return list;\n    }\n\n    public void setAll(OValues values) {\n        for (String key : values.keys())\n            _values.put(key, values.get(key));\n    }\n\n    public int size() {\n        return _values.size();\n    }\n\n    @Override\n    public String toString() {\n        return _values.toString();\n    }\n\n    public ODataRow toDataRow() {\n        ODataRow row = new ODataRow();\n        row.addAll(_values);\n        return row;\n    }\n\n    public ContentValues toContentValues() {\n        ContentValues values = new ContentValues();\n        for (String key : _values.keySet()) {\n            Object val = _values.get(key);\n            val = (val == null) ? \"false\" : val;\n            values.put(key, val.toString());\n        }\n        return values;\n    }\n\n    public void addAll(HashMap<String, Object> data) {\n        _values.putAll(data);\n    }\n\n    public static OValues from(ContentValues contentValues) {\n        OValues values = new OValues();\n        for (String key : contentValues.keySet()) {\n            values.put(key, contentValues.get(key));\n        }\n        return values;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/core/orm/ServerDataHelper.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 7/1/15 6:23 PM\n */\npackage com.odoo.core.orm;\n\nimport android.content.Context;\n\nimport com.odoo.App;\nimport com.odoo.core.service.OSyncAdapter;\nimport com.odoo.core.support.OUser;\nimport com.odoo.core.support.OdooFields;\nimport com.odoo.core.utils.JSONUtils;\n\nimport org.json.JSONArray;\nimport org.json.JSONObject;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport odoo.OArguments;\nimport odoo.ODomain;\nimport odoo.Odoo;\n\npublic class ServerDataHelper {\n    public static final String TAG = ServerDataHelper.class.getSimpleName();\n    private OModel mModel;\n    private Context mContext;\n    private Odoo mOdoo;\n    private App mApp;\n\n    public ServerDataHelper(Context context, OModel model, OUser user) {\n        mContext = context;\n        mModel = model;\n        mApp = (App) mContext.getApplicationContext();\n        mOdoo = mApp.getOdoo(user);\n        if (mOdoo == null)\n            mOdoo = OSyncAdapter.createOdooInstance(mContext, model.getUser());\n    }\n\n    public List<ODataRow> nameSearch(String name, ODomain domain, int limit) {\n        List<ODataRow> items = new ArrayList<>();\n        try {\n            if (mApp.inNetwork()) {\n                JSONObject kwargs = new JSONObject();\n                kwargs.put(\"name\", name);\n                kwargs.put(\"args\", domain.getArray());\n                kwargs.put(\"operator\", \"ilike\");\n                JSONArray records = (JSONArray) callMethod(\"name_search\", new OArguments(),\n                        null, kwargs);\n                if (records.length() > 0) {\n                    for (int i = 0; i < records.length(); i++) {\n                        ODataRow row = new ODataRow();\n                        JSONArray record = records.getJSONArray(i);\n                        row.put(\"id\", record.get(0));\n                        row.put(mModel.getDefaultNameColumn(), record.get(1));\n                        items.add(row);\n                    }\n                }\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return items;\n    }\n\n    public List<ODataRow> searchRecords(OdooFields fields, ODomain domain, int limit) {\n        List<ODataRow> items = new ArrayList<>();\n        try {\n            if (mApp.inNetwork()) {\n                JSONObject result = mOdoo.search_read(mModel.getModelName(),\n                        fields.get(), domain.get(), 0, limit, null, null);\n                JSONArray records = result.getJSONArray(\"records\");\n                if (records.length() > 0) {\n                    for (int i = 0; i < records.length(); i++) {\n                        items.add(JSONUtils.toDataRow(records.getJSONObject(i)));\n                    }\n                }\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return items;\n    }\n\n    public Odoo getOdoo() {\n        return mOdoo;\n    }\n\n    public Object executeWorkFlow(int server_id, String signal) {\n        try {\n            return mOdoo.exec_workflow(mModel.getModelName(), server_id, signal);\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return null;\n    }\n\n    public Object callMethod(String method, OArguments args) {\n        return callMethod(method, args, null, null);\n    }\n\n    public Object callMethod(String method, OArguments args, JSONObject context) {\n        return callMethod(mModel.getModelName(), method, args, context, null);\n    }\n\n    public Object callMethod(String method, OArguments args,\n                             JSONObject context, JSONObject kwargs) {\n        return callMethod(mModel.getModelName(), method, args, context, kwargs);\n    }\n\n    public Object callMethod(String model, String method, OArguments args,\n                             JSONObject context, JSONObject kwargs) {\n        try {\n            if (kwargs == null)\n                kwargs = new JSONObject();\n            if (context != null) {\n                args.add(mOdoo.updateContext(context));\n            }\n            JSONObject result = mOdoo.call_kw(model, method, args.getArray(),\n                    kwargs);\n            if (result.has(\"result\")) {\n                return result.get(\"result\");\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return false;\n    }\n\n\n    public int createOnServer(JSONObject data) {\n        try {\n            JSONObject result = mOdoo.createNew(mModel.getModelName(), data);\n            return result.getInt(\"result\");\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return OModel.INVALID_ROW_ID;\n    }\n\n    public int updateOnServer(JSONObject data, Integer id) {\n        try {\n            if (mOdoo.updateValues(mModel.getModelName(), data, id)) {\n                return mModel.selectRowId(id);\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return OModel.INVALID_ROW_ID;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/core/orm/annotation/Odoo.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 31/12/14 6:32 PM\n */\npackage com.odoo.core.orm.annotation;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n@Retention(RetentionPolicy.RUNTIME)\npublic @interface Odoo {\n\n\n    /**\n     * The Interface Functional.\n     */\n    @Retention(RetentionPolicy.RUNTIME)\n    @Target(ElementType.FIELD)\n    public @interface Functional {\n\n        /**\n         * Method.\n         *\n         * @return the string\n         */\n        String method() default \"\";\n\n        /**\n         * If true, system create column for this functional field and store\n         * value (on create and update) given by this function\n         *\n         * @return true, if successful\n         */\n        boolean store() default false;\n\n        /**\n         * Depends.\n         *\n         * @return the string[]\n         */\n        String[] depends() default {};\n\n    }\n\n    @Retention(RetentionPolicy.RUNTIME)\n    public @interface api {\n\n        @Retention(RetentionPolicy.RUNTIME)\n        @Target({ElementType.FIELD, ElementType.METHOD})\n        public @interface v7 {\n            String[] versions() default {};\n\n            String[] exclude() default {};\n        }\n\n        @Retention(RetentionPolicy.RUNTIME)\n        @Target({ElementType.FIELD, ElementType.METHOD})\n        public @interface v8 {\n            String[] versions() default {};\n\n            String[] exclude() default {};\n        }\n\n        @Retention(RetentionPolicy.RUNTIME)\n        @Target({ElementType.FIELD, ElementType.METHOD})\n        public @interface v9alpha {\n            String[] versions() default {};\n\n            String[] exclude() default {};\n        }\n    }\n\n    @Retention(RetentionPolicy.RUNTIME)\n    @Target({ElementType.FIELD, ElementType.METHOD})\n    public @interface onChange {\n        String method();\n\n        /**\n         * Background process If true, method block executed in background\n         * thread. default false\n         *\n         * @return\n         */\n        boolean bg_process() default false;\n    }\n\n    @Retention(RetentionPolicy.RUNTIME)\n    @Target({ElementType.FIELD, ElementType.METHOD})\n    public @interface hasDomainFilter {\n        boolean checkDomainRuntime() default true;\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/core/orm/fields/OColumn.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 31/12/14 11:20 AM\n */\npackage com.odoo.core.orm.fields;\n\nimport java.lang.reflect.Method;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.LinkedHashMap;\nimport java.util.List;\n\npublic class OColumn {\n    public static final String TAG = OColumn.class.getSimpleName();\n    public static final String ROW_ID = \"_id\";\n    private LinkedHashMap<String, String> mSelectionMap = new LinkedHashMap<>();\n\n    public static enum RelationType {\n        OneToMany,\n        ManyToOne,\n        ManyToMany\n    }\n\n    private String name, label, related_column;\n    private Integer size;\n    private Class<?> type;\n    private RelationType relationType;\n    private Object defaultValue;\n    private Boolean autoIncrement = false, required = false;\n    private Boolean isLocalColumn = false;\n    private LinkedHashMap<String, ColumnDomain> columnDomains = new LinkedHashMap<>();\n    private Integer condition_operator_index = 0;\n    private Integer recordSyncLimit = 0;\n\n    //Annotation properties\n    private Method mOnChangeMethod = null;\n    private Boolean mOnChangeBGProcess = false;\n    private Boolean mHasDomainFilterColumn = false;\n    private Boolean is_functional_column = false;\n    private Method functional_method = null;\n    private Boolean use_annotation = true;\n    private Boolean functional_store = false;\n    private String[] functional_store_depends = null;\n\n    public OColumn(String label, Class<?> type) {\n        this.label = label;\n        this.type = type;\n    }\n\n    public OColumn(String label, Class<?> type, RelationType relationType) {\n        this(label, type);\n        this.relationType = relationType;\n    }\n\n    public OColumn setName(String name) {\n        this.name = name;\n        return this;\n    }\n\n    public Integer getRecordSyncLimit() {\n        return recordSyncLimit;\n    }\n\n    public OColumn setRecordSyncLimit(Integer recordSyncLimit) {\n        this.recordSyncLimit = recordSyncLimit;\n        return this;\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public OColumn setLabel(String label) {\n        this.label = label;\n        return this;\n    }\n\n    public String getLabel() {\n        return label;\n    }\n\n    public RelationType getRelationType() {\n        return relationType;\n    }\n\n    public OColumn setRelatedColumn(String column) {\n        related_column = column;\n        return this;\n    }\n\n    public OColumn setSize(Integer size) {\n        this.size = size;\n        return this;\n    }\n\n    public Integer getSize() {\n        return size;\n    }\n\n    public OColumn setDefaultValue(Object defValue) {\n        defaultValue = defValue;\n        return this;\n    }\n\n    public OColumn setRequired() {\n        required = true;\n        return this;\n    }\n\n    public boolean isRequired() {\n        return required;\n    }\n\n    public OColumn setAutoIncrement() {\n        autoIncrement = true;\n        return this;\n    }\n\n    public OColumn setLocalColumn() {\n        isLocalColumn = true;\n        return this;\n    }\n\n    public OColumn setType(Class<?> type) {\n        this.type = type;\n        return this;\n    }\n\n    public Class<?> getType() {\n        return type;\n    }\n\n    public Object getDefaultValue() {\n        return defaultValue;\n    }\n\n    public Boolean isAutoIncrement() {\n        return autoIncrement;\n    }\n\n    public Boolean isLocal() {\n        return isLocalColumn;\n    }\n\n    public String getRelatedColumn() {\n        return related_column;\n    }\n\n    public OColumn addDomain(String column_name, String operator, Object value) {\n        columnDomains.put(column_name, new ColumnDomain(column_name, operator,\n                value));\n        return this;\n    }\n\n    public OColumn addDomain(String condition_operator) {\n        columnDomains.put(\"condition_operator_\" + (condition_operator_index++)\n                + condition_operator, new ColumnDomain(condition_operator));\n        return this;\n    }\n\n    public LinkedHashMap<String, ColumnDomain> getDomains() {\n        if (hasDomainFilterColumn()) {\n            return new LinkedHashMap<>();\n        }\n        return columnDomains;\n    }\n\n    public boolean hasDomainFilterColumn() {\n        return mHasDomainFilterColumn;\n    }\n\n    public OColumn setHasDomainFilterColumn(Boolean domainFilterColumn) {\n        mHasDomainFilterColumn = domainFilterColumn;\n        return this;\n    }\n\n    public boolean hasOnChange() {\n        return (mOnChangeMethod != null);\n    }\n\n    public Method getOnChangeMethod() {\n        return mOnChangeMethod;\n    }\n\n    public void setOnChangeMethod(Method method) {\n        mOnChangeMethod = method;\n    }\n\n    public Boolean isOnChangeBGProcess() {\n        return mOnChangeBGProcess;\n    }\n\n    public void setOnChangeBGProcess(Boolean process) {\n        mOnChangeBGProcess = process;\n    }\n\n    public void cleanDomains() {\n        columnDomains.clear();\n    }\n\n    public LinkedHashMap<String, ColumnDomain> getFilterDomains() {\n        return columnDomains;\n    }\n\n    /**\n     * Clone domain.\n     *\n     * @param domains the domains\n     * @return the o column\n     */\n    public OColumn cloneDomain(LinkedHashMap<String, ColumnDomain> domains) {\n        columnDomains.putAll(domains);\n        return this;\n    }\n\n    /**\n     * Sets the functional store.\n     *\n     * @param store the new functional store\n     */\n    public void setFunctionalStore(Boolean store) {\n        functional_store = store;\n    }\n\n    /**\n     * Gets the functional store.\n     *\n     * @return the functional store\n     */\n    public Boolean canFunctionalStore() {\n        return functional_store;\n    }\n\n    /**\n     * Sets the functional store depends.\n     *\n     * @param depends the depends\n     * @return the o column\n     */\n    public OColumn setFunctionalStoreDepends(String[] depends) {\n        functional_store_depends = depends;\n        return this;\n    }\n\n    public Boolean isFunctionalColumn() {\n        return is_functional_column;\n    }\n\n    public OColumn setIsFunctionalColumn(Boolean is_functional_column) {\n        this.is_functional_column = is_functional_column;\n        return this;\n    }\n\n    public Method getFunctionalMethod() {\n        return functional_method;\n    }\n\n    public OColumn setFunctionalMethod(Method functional_method) {\n        this.functional_method = functional_method;\n        return this;\n    }\n\n    /**\n     * Gets the functional store depends.\n     *\n     * @return the functional store depends\n     */\n    public List<String> getFunctionalStoreDepends() {\n        if (functional_store_depends != null)\n            return Arrays.asList(functional_store_depends);\n        return new ArrayList<String>();\n    }\n\n    public HashMap<String, String> getSelectionMap() {\n        return mSelectionMap;\n    }\n\n    public OColumn addSelection(String key, String value) {\n        mSelectionMap.put(key, value);\n        return this;\n    }\n\n    @Override\n    public String toString() {\n        return \"OColumn{\" +\n                \"name='\" + name + '\\'' +\n                \", label='\" + label + '\\'' +\n                \", related_column='\" + related_column + '\\'' +\n                \", size=\" + size +\n                \", type=\" + type +\n                \", relationType=\" + relationType +\n                \", defaultValue=\" + defaultValue +\n                \", autoIncrement=\" + autoIncrement +\n                \", required=\" + required +\n                \", isLocalColumn=\" + isLocalColumn +\n                \", columnDomains=\" + columnDomains +\n                \", condition_operator_index=\" + condition_operator_index +\n                \", recordSyncLimit=\" + recordSyncLimit +\n                \", mOnChangeMethod=\" + mOnChangeMethod +\n                \", mOnChangeBGProcess=\" + mOnChangeBGProcess +\n                \", mHasDomainFilterColumn=\" + mHasDomainFilterColumn +\n                \", is_functional_column=\" + is_functional_column +\n                \", functional_method=\" + functional_method +\n                \", use_annotation=\" + use_annotation +\n                \", functional_store=\" + functional_store +\n                \", functional_store_depends=\" + Arrays.toString(functional_store_depends) +\n                '}';\n    }\n\n    public class ColumnDomain {\n\n        private String column = null;\n        private String operator = null;\n        private Object value = null;\n        private String conditional_operator = null;\n\n        public ColumnDomain(String conditional_operator) {\n            this.conditional_operator = conditional_operator;\n        }\n\n        public ColumnDomain(String column, String operator, Object value) {\n            this.column = column;\n            this.operator = operator;\n            this.value = value;\n        }\n\n        public String getColumn() {\n            return column;\n        }\n\n        public void setColumn(String column) {\n            this.column = column;\n        }\n\n        public String getOperator() {\n            return operator;\n        }\n\n        public void setOperator(String operator) {\n            this.operator = operator;\n        }\n\n        public Object getValue() {\n            return value;\n        }\n\n        public void setValue(Object value) {\n            this.value = value;\n        }\n\n        public String getConditionalOperator() {\n            return conditional_operator;\n        }\n\n        public void setConditionalOperator(String conditional_operator) {\n            this.conditional_operator = conditional_operator;\n        }\n\n\n        @Override\n        public String toString() {\n            StringBuffer domain = new StringBuffer();\n            domain.append(\"[\");\n            if (this.conditional_operator == null) {\n                domain.append(this.column);\n                domain.append(\", \");\n                domain.append(this.operator);\n                domain.append(\", \");\n                domain.append(this.value);\n            } else {\n                domain.append(this.conditional_operator);\n            }\n            domain.append(\"]\");\n            return domain.toString();\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/core/orm/fields/types/OBlob.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 31/12/14 11:29 AM\n */\npackage com.odoo.core.orm.fields.types;\n\npublic class OBlob extends OTypeHelper {\n    public static final String TAG = OBlob.class.getSimpleName();\n\n    @Override\n    public String getFieldType() {\n        return \"BLOB\";\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/core/orm/fields/types/OBoolean.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 31/12/14 11:29 AM\n */\npackage com.odoo.core.orm.fields.types;\n\npublic class OBoolean extends OTypeHelper {\n    public static final String TAG = OBoolean.class.getSimpleName();\n\n    @Override\n    public String getFieldType() {\n        return \"VARCHAR\";\n    }\n\n    @Override\n    public Integer getFieldSize() {\n        return 10;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/core/orm/fields/types/ODate.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 31/12/14 11:29 AM\n */\npackage com.odoo.core.orm.fields.types;\n\nimport com.odoo.core.utils.ODateUtils;\n\npublic class ODate extends OTypeHelper {\n    public static final String TAG = ODate.class.getSimpleName();\n\n    @Override\n    public String getFieldType() {\n        return \"VARCHAR\";\n    }\n\n    @Override\n    public String getDataFormat() {\n        return ODateUtils.DEFAULT_DATE_FORMAT;\n    }\n\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/core/orm/fields/types/ODateTime.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 31/12/14 11:29 AM\n */\npackage com.odoo.core.orm.fields.types;\n\nimport com.odoo.core.utils.ODateUtils;\n\npublic class ODateTime extends OTypeHelper {\n    public static final String TAG = ODateTime.class.getSimpleName();\n\n    @Override\n    public String getFieldType() {\n        return \"VARCHAR\";\n    }\n\n    @Override\n    public String getDataFormat() {\n        return ODateUtils.DEFAULT_FORMAT;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/core/orm/fields/types/OFloat.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 31/12/14 11:29 AM\n */\npackage com.odoo.core.orm.fields.types;\n\npublic class OFloat extends OTypeHelper {\n    public static final String TAG = OFloat.class.getSimpleName();\n\n    @Override\n    public String getFieldType() {\n        return \"REAL\";\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/core/orm/fields/types/OHtml.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 31/12/14 11:29 AM\n */\npackage com.odoo.core.orm.fields.types;\n\npublic class OHtml extends OTypeHelper {\n    public static final String TAG = OHtml.class.getSimpleName();\n\n    @Override\n    public String getFieldType() {\n        return \"TEXT\";\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/core/orm/fields/types/OInteger.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 31/12/14 11:29 AM\n */\npackage com.odoo.core.orm.fields.types;\n\npublic class OInteger extends OTypeHelper {\n    public static final String TAG = OInteger.class.getSimpleName();\n\n    @Override\n    public String getFieldType() {\n        return \"INTEGER\";\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/core/orm/fields/types/OSelection.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 31/12/14 11:30 AM\n */\npackage com.odoo.core.orm.fields.types;\n\npublic class OSelection extends OTypeHelper {\n    public static final String TAG = OSelection.class.getSimpleName();\n\n    @Override\n    public String getFieldType() {\n        return \"VARCHAR\";\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/core/orm/fields/types/OText.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 31/12/14 11:29 AM\n */\npackage com.odoo.core.orm.fields.types;\n\npublic class OText extends OTypeHelper {\n    public static final String TAG = OText.class.getSimpleName();\n\n    @Override\n    public String getFieldType() {\n        return \"TEXT\";\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/core/orm/fields/types/OTimestamp.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 31/12/14 11:30 AM\n */\npackage com.odoo.core.orm.fields.types;\n\npublic class OTimestamp extends ODateTime {\n    public static final String TAG = OTimestamp.class.getSimpleName();\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/core/orm/fields/types/OTypeHelper.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 31/12/14 11:30 AM\n */\npackage com.odoo.core.orm.fields.types;\n\npublic abstract class OTypeHelper {\n    public Integer field_size = 0;\n\n    public final boolean equals(String type) {\n        return getFieldType().equals(type);\n    }\n\n    public final String getType() {\n        String type = getFieldType();\n        if (field_size > 0) {\n            type += \"(\" + field_size + \")\";\n        }\n        return type;\n    }\n\n    public void setSize(Integer size) {\n        if (size != null)\n            field_size = size;\n    }\n\n    public abstract String getFieldType();\n\n    public Integer getFieldSize() {\n        return field_size;\n    }\n\n    public String getDataFormat() {\n        return null;\n    }\n\n    @Override\n    public String toString() {\n        return \"OTypeHelper{\" +\n                \"field_type='\" + getFieldType() + '\\'' +\n                \", field_size=\" + field_size +\n                '}';\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/core/orm/fields/types/OVarchar.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 31/12/14 11:30 AM\n */\npackage com.odoo.core.orm.fields.types;\n\npublic class OVarchar extends OTypeHelper {\n    public static final String TAG = OVarchar.class.getSimpleName();\n\n    @Override\n    public String getFieldType() {\n        return \"VARCHAR\";\n    }\n\n    @Override\n    public Integer getFieldSize() {\n        return 64;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/core/orm/provider/BaseModelProvider.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 31/12/14 6:54 PM\n */\npackage com.odoo.core.orm.provider;\n\nimport android.content.ContentProvider;\nimport android.content.ContentValues;\nimport android.content.Context;\nimport android.content.UriMatcher;\nimport android.database.Cursor;\nimport android.database.sqlite.SQLiteDatabase;\nimport android.database.sqlite.SQLiteQueryBuilder;\nimport android.net.Uri;\n\nimport com.odoo.core.auth.OdooAccountManager;\nimport com.odoo.core.orm.OModel;\nimport com.odoo.core.orm.OValues;\nimport com.odoo.core.orm.fields.OColumn;\nimport com.odoo.core.support.OUser;\nimport com.odoo.core.utils.JSONUtils;\nimport com.odoo.core.utils.ODateUtils;\n\nimport java.io.InvalidObjectException;\nimport java.util.Arrays;\nimport java.util.HashSet;\n\npublic class BaseModelProvider extends ContentProvider {\n    public static final String TAG = BaseModelProvider.class.getSimpleName();\n    public final static String KEY_MODEL = \"key_model\";\n    public final static String KEY_USERNAME = \"key_username\";\n    private final int COLLECTION = 1;\n    private final int SINGLE_ROW = 2;\n    protected OModel mModel = null;\n    public UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);\n\n    public static Uri buildURI(String authority, String model, String username) {\n        Uri.Builder uriBuilder = new Uri.Builder();\n        uriBuilder.authority(authority);\n        uriBuilder.appendPath(model);\n        uriBuilder.appendQueryParameter(KEY_MODEL, model);\n        uriBuilder.appendQueryParameter(KEY_USERNAME, username);\n        uriBuilder.scheme(\"content\");\n        return uriBuilder.build();\n    }\n\n    @Override\n    public boolean onCreate() {\n        return true;\n    }\n\n    public String authority() {\n        return null;\n    }\n\n    public OUser getUser(Uri uri) {\n        String username = uri.getQueryParameter(KEY_USERNAME);\n        return OdooAccountManager.getDetails(getContext(), username);\n    }\n\n    public void setModel(Uri uri) {\n        String path = uri.getQueryParameter(KEY_MODEL);\n        String username = uri.getQueryParameter(KEY_USERNAME);\n        mModel = OModel.get(getContext(), path, username);\n        assert mModel != null;\n    }\n\n    private void setMatcher(Uri uri) {\n        String authority = (authority() != null) ? authority() : uri.getAuthority();\n        matcher.addURI(authority, mModel.getModelName(), COLLECTION);\n        matcher.addURI(authority, mModel.getModelName() + \"/#\", SINGLE_ROW);\n    }\n\n    @Override\n    public Cursor query(Uri uri, String[] base_projection, String selection, String[] selectionArgs, String sortOrder) {\n        setModel(uri);\n        setMatcher(uri);\n        if (mModel == null)\n            return null;\n        String[] projection = removeRelationColumns(base_projection);\n        int match = matcher.match(uri);\n        SQLiteQueryBuilder builder = new SQLiteQueryBuilder();\n        builder.setTables(mModel.getTableName());\n\n        // If selection not null and does not contain _is_active\n        if ((selection != null && !selection.contains(\"_is_active\")) || selection == null) {\n            builder.appendWhere(\"_is_active = 'true'\");\n        }\n        Cursor cr = null;\n        switch (match) {\n            case COLLECTION:\n                cr = builder.query(mModel.getReadableDatabase(), projection,\n                        selection, selectionArgs, null, null, sortOrder);\n                break;\n            case SINGLE_ROW:\n                int row_id = Integer.parseInt(uri.getLastPathSegment());\n                cr = builder.query(mModel.getReadableDatabase(), projection,\n                        OColumn.ROW_ID + \" = ? \", new String[]{row_id + \"\"}, null, null, null);\n            case UriMatcher.NO_MATCH:\n                break;\n            default:\n                throw new UnsupportedOperationException(\"Unknown uri: \" + uri);\n        }\n        Context ctx = getContext();\n        assert ctx != null;\n        if (cr != null)\n            cr.setNotificationUri(ctx.getContentResolver(), uri);\n        return cr;\n    }\n\n    private String[] removeRelationColumns(String[] projection) {\n        HashSet<String> columns = new HashSet<>();\n        if (projection != null && projection.length > 0 && mModel != null) {\n            for (String key : projection) {\n                OColumn column = mModel.getColumn(key);\n                if (column != null && column.getRelationType() == null) {\n                    columns.add(key);\n                } else if (column != null && column.getRelationType() == OColumn.RelationType.ManyToOne) {\n                    columns.add(key);\n                }\n            }\n            columns.addAll(Arrays.asList(new String[]{OColumn.ROW_ID, \"id\", \"_is_active\", \"_write_date\"}));\n            return columns.toArray(new String[columns.size()]);\n        }\n        return null;\n    }\n\n    @Override\n    public String getType(Uri uri) {\n        return uri.toString();\n    }\n\n    @Override\n    public Uri insert(Uri uri, ContentValues all_values) {\n        setModel(uri);\n        setMatcher(uri);\n        ContentValues[] values = generateValues(all_values);\n        ContentValues value_to_insert = values[0];\n        value_to_insert.put(\"_write_date\", ODateUtils.getUTCDate());\n        if (!value_to_insert.containsKey(\"_is_active\"))\n            value_to_insert.put(\"_is_active\", \"true\");\n        if (!value_to_insert.containsKey(\"_is_dirty\"))\n            value_to_insert.put(\"_is_dirty\", \"false\");\n        int match = matcher.match(uri);\n        switch (match) {\n            case COLLECTION:\n                SQLiteDatabase db = mModel.getWritableDatabase();\n                long new_id = 0;\n                new_id = db.insert(mModel.getTableName(), null, value_to_insert);\n                // Updating relation columns for record\n                if (values[1].size() > 0) {\n                    storeUpdateRelationRecords(values[1], OColumn.ROW_ID + \"  = ?\", new String[]{new_id + \"\"});\n                }\n\n                return uri.withAppendedPath(uri, new_id + \"\");\n            case SINGLE_ROW:\n                throw new UnsupportedOperationException(\n                        \"Insert not supported on URI: \" + uri);\n            case UriMatcher.NO_MATCH:\n                break;\n            default:\n                throw new UnsupportedOperationException(\"Unknown uri: \" + uri);\n        }\n        notifyDataChange(uri);\n        return null;\n    }\n\n    @Override\n    public int delete(Uri uri, String selection, String[] selectionArgs) {\n        int count = 0;\n        setModel(uri);\n        setMatcher(uri);\n        int match = matcher.match(uri);\n        switch (match) {\n            case COLLECTION:\n                SQLiteDatabase db = mModel.getWritableDatabase();\n                count = db.delete(mModel.getTableName(), selection, selectionArgs);\n                break;\n            case SINGLE_ROW:\n                db = mModel.getWritableDatabase();\n                String row_id = uri.getLastPathSegment();\n                count = db.delete(mModel.getTableName(), OColumn.ROW_ID + \"  = ?\", new String[]{row_id});\n                break;\n            case UriMatcher.NO_MATCH:\n                break;\n            default:\n                throw new UnsupportedOperationException(\"Unknown uri: \" + uri);\n        }\n        notifyDataChange(uri);\n        return count;\n    }\n\n    @Override\n    public int update(Uri uri, ContentValues all_values, String selection, String[] selectionArgs) {\n        setModel(uri);\n        setMatcher(uri);\n        ContentValues[] values = generateValues(all_values);\n        ContentValues value_to_update = values[0];\n        if (!value_to_update.containsKey(\"_write_date\")) {\n            value_to_update.put(\"_write_date\", ODateUtils.getUTCDate());\n        }\n        if (!value_to_update.containsKey(\"_is_dirty\")) {\n            value_to_update.put(\"_is_dirty\", \"true\");\n        }\n        int count = 0;\n        int match = matcher.match(uri);\n        switch (match) {\n            case COLLECTION:\n                SQLiteDatabase db = mModel.getWritableDatabase();\n                count = db.update(mModel.getTableName(), value_to_update, selection, selectionArgs);\n                // Updating relation columns\n                if (values[1].size() > 0) {\n                    storeUpdateRelationRecords(values[1], selection, selectionArgs);\n                }\n\n                break;\n            case SINGLE_ROW:\n                String row_id = uri.getLastPathSegment();\n                db = mModel.getWritableDatabase();\n                count = db.update(mModel.getTableName(), value_to_update, OColumn.ROW_ID + \"  = ?\", new String[]{row_id});\n                // Updating relation columns for record\n                if (values[1].size() > 0) {\n                    storeUpdateRelationRecords(values[1], OColumn.ROW_ID + \"  = ?\", new String[]{row_id});\n                }\n                break;\n            case UriMatcher.NO_MATCH:\n                break;\n            default:\n                throw new UnsupportedOperationException(\"Unknown uri: \" + uri);\n        }\n        notifyDataChange(uri);\n        return count;\n    }\n\n    private void storeUpdateRelationRecords(ContentValues values, String selection, String[] args) {\n        int row_id = mModel.selectRowId(selection, args);\n        for (String key : values.keySet()) {\n            try {\n                mModel.storeManyToManyRecord(key,\n                        row_id, JSONUtils.<Integer>toList(values.getAsString(key)),\n                        OModel.Command.Replace);\n            } catch (InvalidObjectException e) {\n                e.printStackTrace();\n            }\n        }\n    }\n\n    private ContentValues[] generateValues(ContentValues values) {\n        OValues data_value = new OValues();\n        OValues rel_value = new OValues();\n        for (String key : values.keySet()) {\n            OColumn column = mModel.getColumn(key);\n            if (column != null) {\n                if (column.getRelationType() == null) {\n                    data_value.put(key, values.get(key));\n                } else {\n                    if (column.getRelationType() == OColumn.RelationType.ManyToOne) {\n                        data_value.put(key, values.get(key));\n                    } else {\n                        rel_value.put(key, values.get(key).toString());\n                    }\n                }\n            }\n        }\n        return new ContentValues[]{data_value.toContentValues(), rel_value.toContentValues()};\n    }\n\n    private void notifyDataChange(Uri uri) {\n        // Send broadcast to registered ContentObservers, to refresh UI.\n        Context ctx = getContext();\n        assert ctx != null;\n        ctx.getContentResolver().notifyChange(uri, null);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/core/service/ISyncFinishListener.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 1/1/15 3:16 PM\n */\npackage com.odoo.core.service;\n\nimport android.content.SyncResult;\n\nimport com.odoo.core.support.OUser;\n\npublic interface ISyncFinishListener {\n    public OSyncAdapter performNextSync(OUser user, SyncResult syncResult);\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/core/service/ISyncServiceListener.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 10/4/15 3:49 PM\n */\npackage com.odoo.core.service;\n\npublic interface ISyncServiceListener {\n    public void onSyncStarted();\n\n    public void onSyncFinished();\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/core/service/OSyncAdapter.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 1/1/15 3:17 PM\n */\npackage com.odoo.core.service;\n\nimport android.accounts.Account;\nimport android.content.AbstractThreadedSyncAdapter;\nimport android.content.ContentProviderClient;\nimport android.content.Context;\nimport android.content.SyncResult;\nimport android.os.Bundle;\nimport android.util.Log;\n\nimport com.odoo.App;\nimport com.odoo.R;\nimport com.odoo.base.addons.ir.IrModel;\nimport com.odoo.base.addons.res.ResCompany;\nimport com.odoo.core.account.OdooAccountQuickManage;\nimport com.odoo.core.auth.OdooAccountManager;\nimport com.odoo.core.orm.ODataRow;\nimport com.odoo.core.orm.OModel;\nimport com.odoo.core.orm.OValues;\nimport com.odoo.core.orm.fields.OColumn;\nimport com.odoo.core.support.OUser;\nimport com.odoo.core.utils.JSONUtils;\nimport com.odoo.core.utils.ODateUtils;\nimport com.odoo.core.utils.OPreferenceManager;\nimport com.odoo.core.utils.OResource;\nimport com.odoo.core.utils.notification.ONotificationBuilder;\n\nimport org.json.JSONArray;\nimport org.json.JSONObject;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\n\nimport odoo.ODomain;\nimport odoo.Odoo;\nimport odoo.OdooInstance;\nimport odoo.OdooSessionExpiredException;\n\npublic class OSyncAdapter extends AbstractThreadedSyncAdapter {\n    public static final String TAG = OSyncAdapter.class.getSimpleName();\n    public static final Integer REQUEST_SIGN_IN_ERROR = 11244;\n    public static final String KEY_AUTH_ERROR = \"key_authentication_error\";\n    private Context mContext;\n    private Class<? extends OModel> mModelClass;\n    private OModel mModel;\n    private OSyncService mService;\n    private OUser mUser;\n    private Boolean checkForWriteCreateDate = true;\n    private Integer mSyncDataLimit = 0;\n    private HashMap<String, ODomain> mDomain = new HashMap<>();\n    private OPreferenceManager preferenceManager;\n    private Odoo mOdoo;\n    private HashMap<String, ISyncFinishListener> mSyncFinishListeners = new HashMap<>();\n    private App app = null;\n\n    public OSyncAdapter(Context context, Class<? extends OModel> model, OSyncService service,\n                        boolean autoInitialize) {\n        super(context, autoInitialize);\n        init(context, model, service);\n    }\n\n    public OSyncAdapter(Context context, Class<? extends OModel> model, OSyncService service,\n                        boolean autoInitialize, boolean allowParallelSyncs) {\n        super(context, autoInitialize, allowParallelSyncs);\n        init(context, model, service);\n    }\n\n    private void init(Context context, Class<? extends OModel> model, OSyncService service) {\n        mContext = context;\n        mModelClass = model;\n        mService = service;\n        preferenceManager = new OPreferenceManager(mContext);\n        app = (App) context.getApplicationContext();\n    }\n\n    public OSyncAdapter setDomain(ODomain domain) {\n        mDomain.put(mModel.getModelName(), domain);\n        return this;\n    }\n\n    public OSyncAdapter checkForWriteCreateDate(Boolean check) {\n        checkForWriteCreateDate = check;\n        return this;\n    }\n\n    public OSyncAdapter syncDataLimit(Integer dataLimit) {\n        mSyncDataLimit = dataLimit;\n        return this;\n    }\n\n    @Override\n    public void onPerformSync(Account account, Bundle extras, String authority,\n                              ContentProviderClient provider, SyncResult syncResult) {\n        // Creating model Object\n        mModel = new OModel(mContext, null, OdooAccountManager.getDetails(mContext, account.name))\n                .createInstance(mModelClass);\n        mUser = mModel.getUser();\n        // Creating Odoo instance\n        mOdoo = createOdooInstance(mContext, mUser);\n        Log.i(TAG, \"User        : \" + mModel.getUser().getAndroidName());\n        Log.i(TAG, \"Model       : \" + mModel.getModelName());\n        Log.i(TAG, \"Database    : \" + mModel.getDatabaseName());\n        Log.i(TAG, \"Odoo Version: \" + mUser.getVersion_number());\n        // Calling service callback\n        if (mService != null)\n            mService.performDataSync(this, extras, mUser);\n\n        //Creating domain\n        ODomain domain = (mDomain.containsKey(mModel.getModelName())) ?\n                mDomain.get(mModel.getModelName()) : null;\n\n        // Ready for sync data from server\n        syncData(mModel, mUser, domain, syncResult, true, true);\n    }\n\n\n    private void syncData(OModel model, OUser user, ODomain domain_filter,\n                          SyncResult result, Boolean checkForDataLimit, Boolean createRelationRecords) {\n        Log.v(TAG, \"Sync for (\" + model.getModelName() + \") Started at \" + ODateUtils.getDate());\n        model.onSyncStarted();\n        try {\n            ODomain domain = new ODomain();\n            domain.append(model.defaultDomain());\n            if (domain_filter != null) {\n                domain.append(domain_filter);\n            }\n\n            if (checkForWriteCreateDate) {\n                List<Integer> serverIds = model.getServerIds();\n                // Model Create date domain filters\n                if (model.checkForCreateDate() && checkForDataLimit) {\n                    if (serverIds.size() > 0) {\n                        if (model.checkForWriteDate()\n                                && !model.isEmptyTable()) {\n                            domain.add(\"|\");\n                        }\n                        if (model.checkForWriteDate() && !model.isEmptyTable()\n                                && createRelationRecords && model.getLastSyncDateTime() != null)\n                            domain.add(\"&\");\n                    }\n                    int data_limit = preferenceManager.getInt(\"sync_data_limit\", 60);\n                    domain.add(\"create_date\", \">=\", ODateUtils.getDateBefore(data_limit));\n                    if (serverIds.size() > 0) {\n                        domain.add(\"id\", \"not in\", new JSONArray(serverIds.toString()));\n                    }\n                }\n                // Model write date domain filters\n                if (model.checkForWriteDate() && !model.isEmptyTable() && createRelationRecords) {\n                    String last_sync_date = model.getLastSyncDateTime();\n                    if (last_sync_date != null) {\n                        domain.add(\"write_date\", \">\", last_sync_date);\n                    }\n                }\n            }\n            // Getting data\n            JSONObject response = mOdoo.search_read(model.getModelName(),\n                    getFields(model), domain.get(), 0, mSyncDataLimit, \"create_date\", \"DESC\");\n            OSyncDataUtils dataUtils = new OSyncDataUtils(mContext, mOdoo, model, user, response,\n                    result, createRelationRecords);\n            // Updating records on server if local are latest updated.\n            // if model allowed update record to server\n            if (model.allowUpdateRecordOnServer()) {\n                dataUtils.updateRecordsOnServer(this);\n            }\n\n            // Creating or updating relation records\n            handleRelationRecords(user, dataUtils.getRelationRecordsHashMap(), result);\n\n            // If model allowed to create record on server\n            if (model.allowCreateRecordOnServer()) {\n                createRecordsOnServer(model);\n            }\n\n            // If model allowed to delete record on server\n            if (model.allowDeleteRecordOnServer()) {\n                removeRecordOnServer(model);\n            }\n\n            // If model allowed to delete server removed record from local database\n            if (model.allowDeleteRecordInLocal()) {\n                removeNonExistRecordFromLocal(model);\n            }\n\n            Log.v(TAG, \"Sync for (\" + model.getModelName() + \") finished at \" + ODateUtils.getDate());\n            if (createRelationRecords) {\n                IrModel irModel = new IrModel(mContext, user);\n                irModel.setLastSyncDateTimeToNow(model);\n            }\n            model.onSyncFinished();\n        } catch (OdooSessionExpiredException odooSession) {\n            app.setOdoo(null, user);\n            if (user.isOAauthLogin()) {\n                // FIXME: Saas not working with multi login. Facing issue of session expired.\n            } else {\n                showSignInErrorNotification(user);\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        // Performing next sync if any in service\n        if (mSyncFinishListeners.containsKey(model.getModelName())) {\n            OSyncAdapter adapter = mSyncFinishListeners.get(model.getModelName())\n                    .performNextSync(user, result);\n            mSyncFinishListeners.remove(model.getModelName());\n            if (adapter != null) {\n                SyncResult syncResult = new SyncResult();\n                OModel syncModel = model.createInstance(adapter.getModelClass());\n                ContentProviderClient contentProviderClient =\n                        mContext.getContentResolver().acquireContentProviderClient(syncModel.authority());\n                adapter.onPerformSync(user.getAccount(), null, syncModel.authority(),\n                        contentProviderClient, syncResult);\n            }\n        }\n        model.close();\n    }\n\n    private void showSignInErrorNotification(OUser user) {\n        ONotificationBuilder builder = new ONotificationBuilder(mContext,\n                REQUEST_SIGN_IN_ERROR);\n        builder.setTitle(\"Odoo authentication problem\");\n        builder.setBigText(\"May be you have changed your account \" +\n                \"password or your account does not exists\");\n        builder.setIcon(R.drawable.ic_action_alert_warning);\n        builder.setText(user.getAndroidName());\n        builder.allowVibrate(true);\n        builder.withRingTone(false);\n        builder.setOngoing(true);\n        builder.withLargeIcon(false);\n        builder.setColor(OResource.color(mContext, R.color.android_orange_dark));\n        Bundle extra = user.getAsBundle();\n        // Actions\n        ONotificationBuilder.NotificationAction actionReset = new ONotificationBuilder.NotificationAction(\n                R.drawable.ic_action_refresh,\n                \"Reset\",\n                110,\n                \"reset_password\",\n                OdooAccountQuickManage.class,\n                extra\n        );\n        ONotificationBuilder.NotificationAction deleteAccount = new ONotificationBuilder.NotificationAction(\n                R.drawable.ic_action_navigation_close,\n                \"Remove\",\n                111,\n                \"remove_account\",\n                OdooAccountQuickManage.class,\n                extra\n        );\n        builder.addAction(actionReset);\n        builder.addAction(deleteAccount);\n        builder.build().show();\n    }\n\n    private void handleRelationRecords(OUser user,\n                                       HashMap<String, OSyncDataUtils.SyncRelationRecords> relationRecords,\n                                       SyncResult result) {\n        for (String key : relationRecords.keySet()) {\n            OSyncDataUtils.SyncRelationRecords record = relationRecords.get(key);\n            OModel model = record.getBaseModel();\n            OModel rel_model = model.createInstance(record.getRelationModel());\n            model.close();\n            ODomain domain = new ODomain();\n            domain.add(\"id\", \"in\", record.getUniqueIds());\n            syncData(rel_model, user, domain, result, false, false);\n            // Updating manyToOne record with their relation record row_id\n            switch (record.getRelationType()) {\n                case ManyToOne:\n                    // Nothing to do. Already added link with record relation\n                    break;\n                case OneToMany:\n                    // Update related_column with base id's row_id for each of record ids\n                    String related_column = record.getRelatedColumn();\n                    for (Integer id : record.getUniqueIds()) {\n                        OValues values = new OValues();\n                        ODataRow rec = rel_model.browse(rel_model.selectRowId(id));\n                        values.put(related_column, rec.getInt(related_column));\n                        values.put(\"_is_dirty\", \"false\");\n                        rel_model.update(rel_model.selectRowId(id), values);\n                    }\n                    break;\n                case ManyToMany:\n                    // Nothing to do. Already added relation records links\n                    break;\n            }\n            rel_model.close();\n        }\n    }\n\n    public static Odoo createOdooInstance(Context context, OUser user) {\n        try {\n            App app = (App) context.getApplicationContext();\n            Odoo odoo = app.getOdoo(user);\n            if (odoo == null) {\n                if (user.isOAauthLogin()) {\n                    odoo = new Odoo(context, user.getInstanceUrl(), user.isAllowSelfSignedSSL());\n                    OdooInstance instance = new OdooInstance();\n                    instance.setInstanceUrl(user.getInstanceUrl());\n                    instance.setDatabaseName(user.getInstanceDatabase());\n                    instance.setClientId(user.getClientId());\n                    odoo.oauth_authenticate(instance, user.getUsername(), user.getPassword());\n                } else {\n                    odoo = new Odoo(context, user.getHost(), user.isAllowSelfSignedSSL());\n                    odoo.authenticate(user.getUsername(), user.getPassword(), user.getDatabase());\n                }\n                app.setOdoo(odoo, user);\n\n                ResCompany company = new ResCompany(context, user);\n                if (company.count(\"id = ? \", new String[]{user.getCompany_id()}) <= 0) {\n                    ODataRow company_details = new ODataRow();\n                    company_details.put(\"id\", user.getCompany_id());\n                    company.quickCreateRecord(company_details);\n                }\n\n            }\n            return odoo;\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return null;\n    }\n\n    private JSONObject getFields(OModel model) {\n        JSONObject fields = new JSONObject();\n        try {\n            for (OColumn column : model.getColumns(false)) {\n                fields.accumulate(\"fields\", column.getName());\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return fields;\n    }\n\n    /**\n     * Creates locally created record on server (id with zero)\n     *\n     * @param model model object\n     */\n    private void createRecordsOnServer(OModel model) {\n        List<ODataRow> records = model.select(null,\n                \"(id = ? or id = ?)\", new String[]{\"0\", \"false\"});\n        int counter = 0;\n        for (ODataRow record : records) {\n            if (validateRelationRecords(model, record)) {\n                /*\n                 Need to check server id for record.\n                 It is possible that record created on server by validating main record.\n                 */\n                if (model.selectServerId(record.getInt(OColumn.ROW_ID)) == 0) {\n                    int id = createOnServer(model, JSONUtils.createJSONValues(model, record));\n                    if (id != OModel.INVALID_ROW_ID) {\n                        OValues values = new OValues();\n                        values.put(\"id\", id);\n                        values.put(\"_is_dirty\", \"false\");\n                        values.put(\"_write_date\", ODateUtils.getUTCDate());\n                        model.update(record.getInt(OColumn.ROW_ID), values);\n                        counter++;\n                    } else {\n                        Log.e(TAG, \"Unable to create record on server.\");\n                    }\n                }\n            }\n        }\n        if (counter == records.size()) {\n            Log.i(TAG, counter + \" records created on server.\");\n        }\n    }\n\n    /**\n     * Validate relation record for the record. And if relation record not created on server.\n     * It will be created on server before syncing original record\n     *\n     * @param model\n     * @param row\n     * @return updatedRow\n     */\n    public boolean validateRelationRecords(OModel model, ODataRow row) {\n        Log.d(TAG, \"Validating relation records for record\");\n        // Check for relation local record\n        for (OColumn column : model.getRelationColumns()) {\n            OModel relModel = model.createInstance(column.getType());\n            switch (column.getRelationType()) {\n                case ManyToOne:\n                    if (!row.getString(column.getName()).equals(\"false\")) {\n                        ODataRow m2oRec = row.getM2ORecord(column.getName()).browse();\n                        if (m2oRec.getInt(\"id\") == 0) {\n                            int new_id = relModel.getServerDataHelper().createOnServer(\n                                    JSONUtils.createJSONValues(relModel, m2oRec));\n                            updateRecordServerId(relModel, m2oRec.getInt(OColumn.ROW_ID), new_id);\n                        }\n                    }\n                    break;\n                case ManyToMany:\n                    List<ODataRow> m2mRecs = row.getM2MRecord(column.getName()).browseEach();\n                    if (!m2mRecs.isEmpty()) {\n                        for (ODataRow m2mRec : m2mRecs) {\n                            if (m2mRec.getInt(\"id\") == 0) {\n                                int new_id = relModel.getServerDataHelper().createOnServer(\n                                        JSONUtils.createJSONValues(relModel, m2mRec));\n                                updateRecordServerId(relModel, m2mRec.getInt(OColumn.ROW_ID), new_id);\n                            }\n                        }\n                    }\n                    break;\n                case OneToMany:\n                    List<ODataRow> o2mRecs = row.getM2MRecord(column.getName()).browseEach();\n                    if (!o2mRecs.isEmpty()) {\n                        for (ODataRow o2mRec : o2mRecs) {\n                            if (o2mRec.getInt(\"id\") == 0) {\n                                int new_id = relModel.getServerDataHelper().createOnServer(\n                                        JSONUtils.createJSONValues(relModel, o2mRec));\n                                updateRecordServerId(relModel, o2mRec.getInt(OColumn.ROW_ID), new_id);\n                            }\n                        }\n                    }\n                    break;\n            }\n        }\n        return true;\n    }\n\n    /**\n     * Updating local record with server id\n     *\n     * @param model\n     * @param row_id\n     * @param server_id\n     */\n    private void updateRecordServerId(OModel model, int row_id, int server_id) {\n        OValues values = new OValues();\n        values.put(\"id\", server_id);\n        values.put(\"_is_dirty\", \"false\");\n        model.update(row_id, values);\n    }\n\n    private int createOnServer(OModel model, JSONObject values) {\n        int id = OModel.INVALID_ROW_ID;\n        try {\n            if (values != null) {\n                JSONObject response = mOdoo.createNew(model.getModelName(), values);\n                id = response.getInt(\"result\");\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return id;\n    }\n\n\n    /**\n     * Removes record on server if local record is not active\n     *\n     * @param model\n     */\n    private void removeRecordOnServer(OModel model) {\n        List<ODataRow> records = model.select(new String[]{},\n                \"id != ? and _is_active = ?\", new String[]{\"0\", \"false\"});\n        List<Integer> serverIds = new ArrayList<>();\n        for (ODataRow record : records) {\n            serverIds.add(record.getInt(\"id\"));\n        }\n        if (serverIds.size() > 0) {\n            if (removeRecordsFromServer(model, serverIds)) {\n                int counter = model.deleteRecords(serverIds, true);\n                Log.i(TAG, counter + \" records removed from server and local database\");\n            } else {\n                Log.e(TAG, \"Unable to remove records from server\");\n            }\n        }\n    }\n\n    private boolean removeRecordsFromServer(OModel model, List<Integer> serverIds) {\n        try {\n            mOdoo.unlink(model.getModelName(), serverIds);\n            return true;\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return false;\n    }\n\n    /**\n     * Removes non exist record from local database\n     *\n     * @param model\n     */\n    private void removeNonExistRecordFromLocal(OModel model) {\n        List<Integer> ids = model.getServerIds();\n        try {\n            ODomain domain = new ODomain();\n            domain.add(\"id\", \"in\", new JSONArray(ids.toString()));\n            JSONObject result = mOdoo.search_read(model.getModelName(),\n                    new JSONObject(), domain.get());\n            JSONArray records = result.getJSONArray(\"records\");\n            if (records.length() > 0) {\n                for (int i = 0; i < records.length(); i++) {\n                    JSONObject record = records.getJSONObject(i);\n                    ids.remove(ids.indexOf(record.getInt(\"id\")));\n                }\n            }\n            int removedCounter = 0;\n            if (ids.size() > 0) {\n                removedCounter = model.deleteRecords(ids, true);\n            }\n            Log.i(TAG, removedCounter + \" Records removed from local database.\");\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n\n    public Class<? extends OModel> getModelClass() {\n        return mModelClass;\n    }\n\n    public void setModel(OModel model) {\n        mModel = model;\n    }\n\n    public OModel getModel() {\n        return mModel;\n    }\n\n    public OSyncAdapter onSyncFinish(ISyncFinishListener syncFinish) {\n        mSyncFinishListeners.put(mModel.getModelName(), syncFinish);\n        return this;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/core/service/OSyncDataUtils.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 2/1/15 4:15 PM\n */\npackage com.odoo.core.service;\n\nimport android.content.Context;\nimport android.content.SyncResult;\nimport android.util.Log;\n\nimport com.odoo.core.orm.ODataRow;\nimport com.odoo.core.orm.OModel;\nimport com.odoo.core.orm.OValues;\nimport com.odoo.core.orm.fields.OColumn;\nimport com.odoo.core.support.OUser;\nimport com.odoo.core.support.OdooFields;\nimport com.odoo.core.utils.JSONUtils;\nimport com.odoo.core.utils.ODateUtils;\nimport com.odoo.core.utils.OListUtils;\nimport com.odoo.core.utils.StringUtils;\n\nimport org.json.JSONArray;\nimport org.json.JSONObject;\n\nimport java.util.ArrayList;\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.List;\n\nimport odoo.ODomain;\nimport odoo.Odoo;\n\npublic class OSyncDataUtils {\n    public static final String TAG = OSyncDataUtils.class.getSimpleName();\n    private Context mContext;\n    private OModel mModel;\n    private OUser mUser;\n    private JSONObject response;\n    private HashSet<String> recordsId = new HashSet<>();\n    private HashMap<String, SyncRelationRecords> relationRecordsHashMap = new HashMap<>();\n    private Odoo mOdoo;\n    private SyncResult mResult;\n    private HashMap<String, List<Integer>> updateToServerRecords = new HashMap<>();\n    private Boolean mCreateRelationRecords = true;\n\n    public OSyncDataUtils(Context context, Odoo odoo, OModel model, OUser user, JSONObject response,\n                          SyncResult result, Boolean createRelRecord) {\n        mContext = context;\n        mOdoo = odoo;\n        mModel = model;\n        mUser = user;\n        this.response = response;\n        mResult = result;\n        mCreateRelationRecords = createRelRecord;\n        JSONArray updateInLocal = checkLocalUpdatedRecords();\n        handleResult(updateInLocal);\n    }\n\n\n    private JSONArray checkLocalUpdatedRecords() {\n        // Array of records which are new or need to update in local\n        JSONArray finalRecords = new JSONArray();\n        try {\n            // Getting list of ids which are present in local database\n            List<Integer> serverIds = new ArrayList<>();\n            HashMap<String, JSONObject> serverIdRecords = new HashMap<>();\n            JSONArray records = response.getJSONArray(\"records\");\n            for (int i = 0; i < records.length(); i++) {\n                JSONObject record = records.getJSONObject(i);\n                if (mModel.hasServerRecord(record.getInt(\"id\"))\n                        && mModel.isServerRecordDirty(record.getInt(\"id\"))) {\n                    int server_id = record.getInt(\"id\");\n                    serverIds.add(server_id);\n                    serverIdRecords.put(\"key_\" + server_id, record);\n                } else {\n                    finalRecords.put(record);\n                }\n            }\n\n            // getting local dirty records if server records length = 0\n            if (records.length() <= 0) {\n                for (ODataRow row : mModel.select(new String[]{}, \"_is_dirty = ? and _is_active = ? and id != ?\",\n                        new String[]{\"true\", \"true\", \"0\"})) {\n                    serverIds.add(row.getInt(\"id\"));\n                }\n            }\n            // Comparing dirty (updated) record\n            List<Integer> updateToServerIds = new ArrayList<>();\n            if (serverIds.size() > 0) {\n                HashMap<String, String> write_dates = getWriteDate(mModel, serverIds);\n                for (Integer server_id : serverIds) {\n                    String key = \"key_\" + server_id;\n                    String write_date = write_dates.get(key);\n                    ODataRow record = mModel.browse(new String[]{\"_write_date\"}, \"id = ?\",\n                            new String[]{server_id + \"\"});\n                    if (record != null) {\n                        Date write_date_obj = ODateUtils.createDateObject(write_date,\n                                ODateUtils.DEFAULT_FORMAT, false);\n                        Date _write_date_obj = ODateUtils.createDateObject(record.getString(\"_write_date\"),\n                                ODateUtils.DEFAULT_FORMAT, false);\n                        if (_write_date_obj.compareTo(write_date_obj) > 0) {\n                            // Local record is latest\n                            updateToServerIds.add(server_id);\n                        } else {\n                            if (serverIdRecords.containsKey(key)) {\n                                finalRecords.put(serverIdRecords.get(key));\n                            }\n                        }\n                    }\n                }\n            }\n            if (updateToServerIds.size() > 0) {\n                updateToServerRecords.put(mModel.getModelName(), updateToServerIds);\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return finalRecords;\n    }\n\n    private HashMap<String, String> getWriteDate(OModel model, List<Integer> ids) {\n        HashMap<String, String> map = new HashMap<>();\n        try {\n            JSONArray result;\n            if (model.getColumn(\"write_date\") != null) {\n                OdooFields fields = new OdooFields(new String[]{\"write_date\"});\n                ODomain domain = new ODomain();\n                domain.add(\"id\", \"in\", ids);\n                JSONObject data = mOdoo.search_read(model.getModelName(), fields.get(), domain.get());\n                result = data.getJSONArray(\"records\");\n            } else {\n                JSONObject data = mOdoo.perm_read(model.getModelName(), ids);\n                result = data.getJSONArray(\"result\");\n            }\n\n            if (result.length() > 0) {\n                for (int i = 0; i < result.length(); i++) {\n                    JSONObject obj = result.getJSONObject(i);\n                    map.put(\"key_\" + obj.getInt(\"id\"), obj.getString(\"write_date\"));\n                }\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return map;\n    }\n\n    private void handleResult(JSONArray records) {\n        try {\n            recordsId.clear();\n            int length = records.length();\n            int counter = 0;\n            List<OColumn> columns = mModel.getColumns(false);\n            columns.addAll(mModel.getFunctionalColumns());\n            for (int i = 0; i < length; i++) {\n                JSONObject record = records.getJSONObject(i);\n                OValues values = new OValues();\n                recordsId.add(mModel.getModelName() + \"_\" + record.getInt(\"id\"));\n                for (OColumn column : columns) {\n                    String name = column.getName();\n                    if (column.getRelationType() == null) {\n\n                        // checks for functional store fields\n                        if (column.isFunctionalColumn() && column.canFunctionalStore()) {\n                            List<String> depends = column.getFunctionalStoreDepends();\n                            OValues dependValues = new OValues();\n                            if (!column.isLocal())\n                                dependValues.put(column.getName(), record.get(column.getName()));\n                            for (String depend : depends) {\n                                if (record.has(depend)) {\n                                    dependValues.put(depend, record.get(depend));\n                                }\n                            }\n                            Object value = mModel.getFunctionalMethodValue(column, dependValues);\n                            values.put(column.getName(), value);\n                        } else {\n                            // Normal Columns\n                            values.put(name, record.get(name));\n                        }\n                    } else {\n                        // Relation Columns\n                        if (!(record.get(name) instanceof Boolean)) {\n                            switch (column.getRelationType()) {\n                                case ManyToOne:\n                                    JSONArray m2oData = record.getJSONArray(name);\n                                    OModel m2o_model = mModel.createInstance(column.getType());\n                                    String recKey = m2o_model.getModelName() + \"_\" + m2oData.get(0);\n                                    int m2oRowId;\n                                    if (!recordsId.contains(recKey)) {\n                                        OValues m2oValue = new OValues();\n                                        m2oValue.put(\"id\", m2oData.get(0));\n                                        m2oValue.put(m2o_model.getDefaultNameColumn(), m2oData.get(1));\n                                        m2oValue.put(\"_is_dirty\", \"false\");\n                                        m2oRowId = m2o_model.insertOrUpdate(m2oData.getInt(0),\n                                                m2oValue);\n                                    } else {\n                                        m2oRowId = m2o_model.selectRowId(m2oData.getInt(0));\n                                    }\n\n                                    values.put(name, m2oRowId);\n                                    if (mCreateRelationRecords) {\n                                        // Add id to sync if model contains more than (id,name) columns\n                                        if (m2o_model.getColumns(false).size() > 2\n                                                || (m2o_model.getColumns(false).size() > 4\n                                                && mModel.getOdooVersion().getVersion_number() > 7)) {\n                                            List<Integer> m2oIds = new ArrayList<>();\n                                            m2oIds.add(m2oData.getInt(0));\n                                            addUpdateRelationRecord(mModel, m2o_model.getTableName(),\n                                                    column.getType(), name, null,\n                                                    column.getRelationType(), m2oIds);\n                                        }\n                                    }\n                                    m2o_model.close();\n                                    break;\n                                case ManyToMany:\n                                    OModel m2mModel = mModel.createInstance(column.getType());\n                                    List<Integer> m2mIds = JSONUtils.<Integer>toList(record.getJSONArray(name));\n                                    if (mCreateRelationRecords) {\n                                        addUpdateRelationRecord(mModel, m2mModel.getTableName(), column.getType(),\n                                                name, null, column.getRelationType(),\n                                                (column.getRecordSyncLimit() > 0) ?\n                                                        m2mIds.subList(0, column.getRecordSyncLimit()) : m2mIds);\n                                    }\n                                    List<Integer> m2mRowIds = new ArrayList<>();\n                                    for (Integer id : m2mIds) {\n                                        recKey = m2mModel.getModelName() + \"_\" + id;\n                                        int r_id;\n                                        if (!recordsId.contains(recKey)) {\n                                            OValues m2mValues = new OValues();\n                                            m2mValues.put(\"id\", id);\n                                            m2mValues.put(\"_is_dirty\", \"false\");\n                                            r_id = m2mModel.insertOrUpdate(id, m2mValues);\n                                        } else {\n                                            r_id = m2mModel.selectRowId(id);\n                                        }\n                                        m2mRowIds.add(r_id);\n                                    }\n                                    if (m2mRowIds.size() > 0) {\n                                        // Putting many to many related ids\n                                        // (generated _id for each of server ids)\n                                        values.put(name, m2mRowIds);\n                                    }\n                                    m2mModel.close();\n                                    break;\n                                case OneToMany:\n                                    if (mCreateRelationRecords) {\n                                        OModel o2mModel = mModel.createInstance(column.getType());\n                                        List<Integer> o2mIds = JSONUtils.<Integer>toList(record.getJSONArray(name));\n                                        addUpdateRelationRecord(mModel, o2mModel.getTableName(),\n                                                column.getType(), name, column.getRelatedColumn(),\n                                                column.getRelationType(),\n                                                (column.getRecordSyncLimit() > 0) ?\n                                                        o2mIds.subList(0, column.getRecordSyncLimit()) : o2mIds);\n                                        o2mModel.close();\n                                    }\n                                    break;\n                            }\n                        }\n                    }\n                }\n                // Some default values\n                values.put(\"id\", record.getInt(\"id\"));\n                values.put(\"_write_date\", ODateUtils.getUTCDate());\n                values.put(\"_is_active\", \"true\");\n                values.put(\"_is_dirty\", \"false\");\n                mModel.insertOrUpdate(record.getInt(\"id\"), values);\n                counter++;\n            }\n            Log.i(TAG, counter + \" records affected\");\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n\n\n    public boolean updateRecordsOnServer(OSyncAdapter adapter) {\n        try {\n            // Use key (modal name) from updateToServerRecords\n            // use updateToServerRecords ids\n            int counter = 0;\n            for (String key : updateToServerRecords.keySet()) {\n                OModel model = OModel.get(mContext, key, mUser.getAndroidName());\n                List<String> ids = OListUtils.toStringList(updateToServerRecords.get(key));\n                counter += ids.size();\n                for (ODataRow record : model.select(null,\n                        \"id IN ( \" + StringUtils.repeat(\"?, \", ids.size() - 1) + \" ?)\",\n                        ids.toArray(new String[ids.size()]))) {\n\n                    if (adapter.validateRelationRecords(model, record)) {\n                        mOdoo.updateValues(model.getModelName(),\n                                JSONUtils.createJSONValues(model, record), record.getInt(\"id\"));\n                        OValues value = new OValues();\n                        value.put(\"_is_dirty\", \"false\");\n                        value.put(\"_write_date\", ODateUtils.getUTCDate());\n                        model.update(record.getInt(OColumn.ROW_ID), value);\n                        model.close();\n                    }\n                }\n            }\n            Log.i(TAG, counter + \" records updated on server\");\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return false;\n    }\n\n    private void addUpdateRelationRecord(OModel baseModel, String relTable, Class<?> model,\n                                         String column, String relatedColumn,\n                                         OColumn.RelationType type, List<Integer> ids) {\n        String key = relTable + \"_\" + column;\n        if (relationRecordsHashMap.containsKey(key)) {\n            SyncRelationRecords data = relationRecordsHashMap.get(key);\n            data.updateIds(ids);\n            relationRecordsHashMap.put(key, data);\n        } else {\n            relationRecordsHashMap.put(key,\n                    new SyncRelationRecords(baseModel, model, column, relatedColumn, type, ids));\n        }\n    }\n\n    public HashMap<String, SyncRelationRecords> getRelationRecordsHashMap() {\n        if (mCreateRelationRecords)\n            return relationRecordsHashMap;\n        return new HashMap<>();\n    }\n\n    @Override\n    protected void finalize() throws Throwable {\n        super.finalize();\n        if (mModel != null)\n            mModel.close();\n    }\n\n    public static class SyncRelationRecords {\n        private OModel baseModel;\n        private Class<?> relationModel;\n        private String relationColumn;\n        private String relatedColumn;\n        private OColumn.RelationType relationType;\n        private List<Integer> serverIds = new ArrayList<>();\n\n        public SyncRelationRecords(OModel baseModel, Class<?> relationModel, String relationColumn, String relatedColumn,\n                                   OColumn.RelationType relationType, List<Integer> serverIds) {\n            this.baseModel = baseModel;\n            this.relationModel = relationModel;\n            this.relationColumn = relationColumn;\n            this.relatedColumn = relatedColumn;\n            this.relationType = relationType;\n            this.serverIds.addAll(serverIds);\n        }\n\n        public OModel getBaseModel() {\n            return baseModel;\n        }\n\n        public void setBaseModel(OModel baseModel) {\n            this.baseModel = baseModel;\n        }\n\n        public Class<?> getRelationModel() {\n            return relationModel;\n        }\n\n        public void setRelationModel(Class<?> relationModel) {\n            this.relationModel = relationModel;\n        }\n\n        public String getRelationColumn() {\n            return relationColumn;\n        }\n\n        public void setRelationColumn(String relationColumn) {\n            this.relationColumn = relationColumn;\n        }\n\n\n        public String getRelatedColumn() {\n            return relatedColumn;\n        }\n\n        public void setRelatedColumn(String relatedColumn) {\n            this.relatedColumn = relatedColumn;\n        }\n\n        public OColumn.RelationType getRelationType() {\n            return relationType;\n        }\n\n        public void setRelationType(OColumn.RelationType relationType) {\n            this.relationType = relationType;\n        }\n\n        public List<Integer> getServerIds() {\n            return serverIds;\n        }\n\n        public void setServerIds(List<Integer> serverIds) {\n            this.serverIds.clear();\n            this.serverIds.addAll(serverIds);\n        }\n\n        public void updateIds(List<Integer> ids) {\n            this.serverIds.addAll(ids);\n        }\n\n\n        public List<Integer> getUniqueIds() {\n            List<Integer> ids = new ArrayList<>();\n            HashSet<Integer> uIds = new HashSet<>(serverIds);\n            ids.addAll(uIds);\n            return ids;\n        }\n    }\n\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/core/service/OSyncService.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 1/1/15 3:16 PM\n */\npackage com.odoo.core.service;\n\nimport android.app.Service;\nimport android.content.AbstractThreadedSyncAdapter;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.os.IBinder;\nimport android.util.Log;\n\nimport com.odoo.core.service.receivers.ISyncFinishReceiver;\nimport com.odoo.core.support.OUser;\n\npublic abstract class OSyncService extends Service {\n    public static final String TAG = OSyncService.class.getSimpleName();\n    private static final Object sSyncAdapterLock = new Object();\n    private AbstractThreadedSyncAdapter sSyncAdapter = null;\n    private Context mContext;\n    private OSyncService service;\n\n    @Override\n    public void onCreate() {\n        super.onCreate();\n        mContext = getApplicationContext();\n        service = this;\n        Log.i(TAG, \"Service created\");\n        synchronized (sSyncAdapterLock) {\n            if (sSyncAdapter == null) {\n                sSyncAdapter = getSyncAdapter(service, mContext);\n            }\n        }\n    }\n\n    public void setService(OSyncService service) {\n        this.service = service;\n    }\n\n    public void setContext(Context context) {\n        mContext = context;\n    }\n\n    @Override\n    public void onDestroy() {\n        super.onDestroy();\n        Log.i(TAG, \"Service destroyed\");\n        Intent intent = new Intent();\n        intent.setAction(ISyncFinishReceiver.SYNC_FINISH);\n        getApplicationContext().sendBroadcast(intent);\n    }\n\n    @Override\n    public IBinder onBind(Intent intent) {\n        return sSyncAdapter.getSyncAdapterBinder();\n    }\n\n    public abstract OSyncAdapter getSyncAdapter(OSyncService service, Context context);\n\n    public abstract void performDataSync(OSyncAdapter adapter, Bundle extras, OUser user);\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/core/service/receivers/ISyncFinishReceiver.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 1/1/15 3:18 PM\n */\npackage com.odoo.core.service.receivers;\n\nimport android.content.BroadcastReceiver;\n\npublic abstract class ISyncFinishReceiver extends BroadcastReceiver {\n    public static final String SYNC_FINISH = \"ISyncFinishReceiver.SYNC_FINISH\";\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/core/support/OUser.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 17/12/14 6:19 PM\n */\npackage com.odoo.core.support;\n\nimport android.accounts.Account;\nimport android.accounts.AccountManager;\nimport android.content.Context;\nimport android.os.Bundle;\n\nimport com.odoo.core.auth.OdooAccountManager;\n\npublic class OUser {\n    /**\n     * The username.\n     */\n    private String username;\n\n    /**\n     * The name.\n     */\n    private String name;\n\n    /**\n     * The user_id.\n     */\n    private int user_id;\n\n    /**\n     * The partner_id.\n     */\n    private int partner_id;\n\n    /**\n     * The timezone.\n     */\n    private String timezone;\n\n    /**\n     * The isactive.\n     */\n    private boolean isactive;\n\n    /**\n     * The avatar.\n     */\n    private String avatar;\n\n    /**\n     * The database.\n     */\n    private String database;\n\n    /**\n     * The host.\n     */\n    private String host;\n\n    /**\n     * The android_name.\n     */\n    private String android_name;\n\n    /**\n     * The password.\n     */\n    private String password;\n\n    /**\n     * The company_id.\n     */\n    private String company_id;\n\n    /**\n     * The allow_self_signed_ssl.\n     */\n    private boolean allow_self_signed_ssl = false;\n\n    /**\n     * The oauth_login.\n     */\n    private boolean oauth_login = false;\n\n    /**\n     * The version_number.\n     */\n    private Integer version_number = 0;\n\n    /**\n     * The version_serie.\n     */\n    private String version_serie = null;\n\n    // If oauth login\n    /**\n     * The instance_url.\n     */\n    private String instance_url = null;\n\n    /**\n     * The instance_database.\n     */\n    private String instance_database = null;\n\n    /**\n     * The client_id.\n     */\n    private String client_id = null;\n    /**\n     * Account instance\n     */\n    private Account account = null;\n\n    /**\n     * Current.\n     *\n     * @param context the context\n     * @return the o user\n     */\n    public static OUser current(Context context) {\n        return OdooAccountManager.getActiveUser(context);\n    }\n\n    /**\n     * Gets the name.\n     *\n     * @return the name\n     */\n    public String getName() {\n        return name;\n    }\n\n    /**\n     * Sets the name.\n     *\n     * @param name the new name\n     */\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    /**\n     * Gets the company_id.\n     *\n     * @return the company_id\n     */\n    public String getCompany_id() {\n        return company_id;\n    }\n\n    /**\n     * Sets the company_id.\n     *\n     * @param company_id the new company_id\n     */\n    public void setCompany_id(String company_id) {\n        this.company_id = company_id;\n    }\n\n    /**\n     * Gets the data as bundle.\n     *\n     * @return the as bundle\n     */\n    public Bundle getAsBundle() {\n        Bundle bundle = new Bundle();\n        bundle.putString(\"name\", this.getName());\n        bundle.putString(\"username\", this.getUsername());\n        bundle.putString(\"user_id\", this.getUser_id() + \"\");\n        bundle.putString(\"partner_id\", this.getPartner_id() + \"\");\n        bundle.putString(\"timezone\", this.getTimezone());\n        bundle.putString(\"isactive\", String.valueOf(this.isIsactive()));\n        bundle.putString(\"avatar\", this.getAvatar());\n        bundle.putString(\"database\", this.getDatabase());\n        bundle.putString(\"host\", this.getHost());\n        bundle.putString(\"android_name\", this.getAndroidName());\n        bundle.putString(\"password\", this.getPassword());\n        bundle.putString(\"company_id\", this.getCompany_id());\n        bundle.putString(\"allow_self_signed_ssl\",\n                String.valueOf(this.isAllowSelfSignedSSL()));\n        bundle.putString(\"instance_database\", this.getInstanceDatabase());\n        bundle.putString(\"instance_url\", this.getInstanceUrl());\n        bundle.putString(\"oauth_login\", this.isOAauthLogin() + \"\");\n        bundle.putString(\"client_id\", this.getClientId());\n        bundle.putString(\"odoo_version_number\", getVersion_number() + \"\");\n        bundle.putString(\"odoo_version_serie\", getVersion_serie());\n        return bundle;\n    }\n\n    /**\n     * Sets the data from bundle.\n     *\n     * @param data the new from bundle\n     */\n    public void setFromBundle(Bundle data) {\n        setName(data.getString(\"name\"));\n        setUsername(data.getString(\"username\"));\n        setUser_id(Integer.parseInt(data.getString(\"user_id\")));\n        setPartner_id(Integer.parseInt(data.getString(\"partner_id\")));\n        setTimezone(data.getString(\"timezone\"));\n        setIsactive(Boolean.parseBoolean(data.getString(\"isactive\")));\n        setAvatar(data.getString(\"avatar\"));\n        setDatabase(data.getString(\"database\"));\n        setHost(data.getString(\"host\"));\n        setAndroidName(data.getString(\"android_name\"));\n        setPassword(data.getString(\"password\"));\n        setCompany_id(data.getString(\"company_id\"));\n        setAllowSelfSignedSSL(Boolean.parseBoolean(data\n                .getString(\"allow_self_signed_ssl\")));\n        setVersion_number(Integer.parseInt(data\n                .getString(\"odoo_version_number\")));\n        setVersion_serie(data.getString(\"odoo_version_serie\"));\n        // If oAuth Login\n        setInstanceDatabase(data.getString(\"instance_database\"));\n        setInstanceUrl(data.getString(\"instance_url\"));\n        setOAuthLogin(Boolean.parseBoolean(data.getString(\"oauth_login\")));\n        setClientId(data.getString(\"client_id\"));\n    }\n\n    /**\n     * Fill from account.\n     *\n     * @param accMgr  the acc mgr\n     * @param account the account\n     */\n    public void fillFromAccount(AccountManager accMgr, Account account) {\n\n        setName(accMgr.getUserData(account, \"name\"));\n        setUsername(accMgr.getUserData(account, \"username\"));\n        setUser_id(Integer.parseInt(accMgr.getUserData(account, \"user_id\")));\n        setPartner_id(Integer.parseInt(accMgr\n                .getUserData(account, \"partner_id\")));\n        setTimezone(accMgr.getUserData(account, \"timezone\"));\n        setIsactive(Boolean.parseBoolean(accMgr\n                .getUserData(account, \"isactive\")));\n        try {\n            setAvatar(accMgr.getUserData(account, \"avatar\"));\n        } catch (Exception e) {\n            setAvatar(\"false\");\n        }\n        setDatabase(accMgr.getUserData(account, \"database\"));\n        setHost(accMgr.getUserData(account, \"host\"));\n        setAndroidName(accMgr.getUserData(account, \"android_name\"));\n        setPassword(accMgr.getUserData(account, \"password\"));\n        setCompany_id(accMgr.getUserData(account, \"company_id\"));\n        setAllowSelfSignedSSL(Boolean.parseBoolean(accMgr.getUserData(account, \"allow_self_signed_ssl\")));\n        String odoo_version_number = accMgr.getUserData(account, \"odoo_version_number\");\n        if (odoo_version_number != null && !odoo_version_number.contains(\"null\"))\n            setVersion_number(Integer.parseInt(odoo_version_number));\n        setVersion_serie(accMgr.getUserData(account, \"odoo_version_serie\"));\n        // If oAuth login\n        setOAuthLogin(Boolean.parseBoolean(accMgr.getUserData(account,\n                \"oauth_login\")));\n        setInstanceDatabase(accMgr.getUserData(account, \"instance_database\"));\n        setInstanceUrl(accMgr.getUserData(account, \"instance_url\"));\n        setClientId(accMgr.getUserData(account, \"client_id\"));\n\n    }\n\n\n    /**\n     * Gets the password.\n     *\n     * @return the password\n     */\n    public String getPassword() {\n        return password;\n    }\n\n    /**\n     * Sets the password.\n     *\n     * @param password the new password\n     */\n    public void setPassword(String password) {\n        this.password = password;\n    }\n\n    /**\n     * Gets the android name.\n     *\n     * @return the android name\n     */\n    public String getAndroidName() {\n        return this.android_name;\n    }\n\n    /**\n     * Sets the android name.\n     *\n     * @param android_name the new android name\n     */\n    public void setAndroidName(String android_name) {\n        this.android_name = android_name;\n    }\n\n    /**\n     * Gets the username.\n     *\n     * @return the username\n     */\n    public String getUsername() {\n        return username;\n    }\n\n    /**\n     * Sets the username.\n     *\n     * @param username the new username\n     */\n    public void setUsername(String username) {\n        this.username = username;\n    }\n\n    /**\n     * Gets the user_id.\n     *\n     * @return the user_id\n     */\n    public int getUser_id() {\n        return user_id;\n    }\n\n    /**\n     * Sets the user_id.\n     *\n     * @param user_id the new user_id\n     */\n    public void setUser_id(int user_id) {\n        this.user_id = user_id;\n    }\n\n    /**\n     * Gets the partner_id.\n     *\n     * @return the partner_id\n     */\n    public int getPartner_id() {\n        return partner_id;\n    }\n\n    /**\n     * Sets the partner_id.\n     *\n     * @param partner_id the new partner_id\n     */\n    public void setPartner_id(int partner_id) {\n        this.partner_id = partner_id;\n    }\n\n    /**\n     * Gets the timezone.\n     *\n     * @return the timezone\n     */\n    public String getTimezone() {\n        return timezone;\n    }\n\n    /**\n     * Sets the timezone.\n     *\n     * @param timezone the new timezone\n     */\n    public void setTimezone(String timezone) {\n        this.timezone = timezone;\n    }\n\n    /**\n     * Checks if is isactive.\n     *\n     * @return true, if is isactive\n     */\n    public boolean isIsactive() {\n        return isactive;\n    }\n\n    /**\n     * Sets the isactive.\n     *\n     * @param isactive the new isactive\n     */\n    public void setIsactive(boolean isactive) {\n        this.isactive = isactive;\n    }\n\n    /**\n     * Gets the avatar.\n     *\n     * @return the avatar\n     */\n    public String getAvatar() {\n        return avatar;\n    }\n\n    /**\n     * Sets the avatar.\n     *\n     * @param avatar the new avatar\n     */\n    public void setAvatar(String avatar) {\n        this.avatar = avatar;\n    }\n\n    /**\n     * Gets the database.\n     *\n     * @return the database\n     */\n    public String getDatabase() {\n        return database;\n    }\n\n    /**\n     * Sets the database.\n     *\n     * @param database the new database\n     */\n    public void setDatabase(String database) {\n        this.database = database;\n    }\n\n    /**\n     * Gets the host.\n     *\n     * @return the host\n     */\n    public String getHost() {\n        return host;\n    }\n\n    /**\n     * Sets the host.\n     *\n     * @param host the new host\n     */\n    public void setHost(String host) {\n        this.host = host;\n    }\n\n    /**\n     * Checks if is allow self signed ssl.\n     *\n     * @return true, if is allow self signed ssl\n     */\n    public boolean isAllowSelfSignedSSL() {\n        return allow_self_signed_ssl;\n    }\n\n    /**\n     * Sets the allow self signed ssl.\n     *\n     * @param allow_self_signed_ssl the new allow self signed ssl\n     */\n    public void setAllowSelfSignedSSL(boolean allow_self_signed_ssl) {\n        this.allow_self_signed_ssl = allow_self_signed_ssl;\n    }\n\n    /**\n     * Checks if is o aauth login.\n     *\n     * @return true, if is o aauth login\n     */\n    public boolean isOAauthLogin() {\n        return oauth_login;\n    }\n\n    /**\n     * Sets the o auth login.\n     *\n     * @param oauth_login the new o auth login\n     */\n    public void setOAuthLogin(boolean oauth_login) {\n        this.oauth_login = oauth_login;\n    }\n\n    /**\n     * Gets the instance url.\n     *\n     * @return the instance url\n     */\n    public String getInstanceUrl() {\n        return instance_url;\n    }\n\n    /**\n     * Sets the instance url.\n     *\n     * @param instnace_url the new instance url\n     */\n    public void setInstanceUrl(String instnace_url) {\n        this.instance_url = instnace_url;\n    }\n\n    /**\n     * Gets the instance database.\n     *\n     * @return the instance database\n     */\n    public String getInstanceDatabase() {\n        return instance_database;\n    }\n\n    /**\n     * Sets the instance database.\n     *\n     * @param instance_database the new instance database\n     */\n    public void setInstanceDatabase(String instance_database) {\n        this.instance_database = instance_database;\n    }\n\n    /**\n     * Gets the client id.\n     *\n     * @return the client id\n     */\n    public String getClientId() {\n        return client_id;\n    }\n\n    /**\n     * Sets the client id.\n     *\n     * @param client_id the new client id\n     */\n    public void setClientId(String client_id) {\n        this.client_id = client_id;\n    }\n\n    public Integer getVersion_number() {\n        return version_number;\n    }\n\n    public void setVersion_number(Integer version_number) {\n        this.version_number = version_number;\n    }\n\n    public String getVersion_serie() {\n        return version_serie;\n    }\n\n    public void setVersion_serie(String version_serie) {\n        this.version_serie = version_serie;\n    }\n\n    public String getDBName() {\n        String db_name = \"OdooSQLite\";\n        db_name += \"_\" + getUsername();\n        db_name += \"_\" + getDatabase();\n        return db_name + \".db\";\n    }\n\n    @Override\n    public String toString() {\n        return getAndroidName();\n    }\n\n    public Account getAccount() {\n        return account;\n    }\n\n    public void setAccount(Account account) {\n        this.account = account;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/core/support/OdooFields.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 18/12/14 4:23 PM\n */\npackage com.odoo.core.support;\n\nimport com.odoo.core.orm.fields.OColumn;\n\nimport org.json.JSONObject;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class OdooFields {\n\n    private JSONObject jFields = new JSONObject();\n\n    public OdooFields(List<OColumn> columns) {\n        List<String> fields = new ArrayList<>();\n        if (columns != null) {\n            for (OColumn column : columns) {\n                if (!column.isLocal() && !column.isFunctionalColumn()) {\n                    fields.add(column.getName());\n                }\n            }\n        }\n        addAll(fields.toArray(new String[fields.size()]));\n    }\n\n    public OdooFields(String[] fields) {\n        addAll(fields);\n    }\n\n    public void addAll(String[] fields) {\n        try {\n            for (String field : fields) {\n                jFields.accumulate(\"fields\", field);\n            }\n            if (fields.length == 1) {\n                jFields.accumulate(\"fields\", fields[0]);\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n\n    public JSONObject get() {\n        return jFields;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/core/support/OdooInstancesSelectorDialog.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 18/12/14 5:56 PM\n */\npackage com.odoo.core.support;\n\nimport android.app.AlertDialog;\nimport android.content.Context;\nimport android.content.DialogInterface;\nimport android.graphics.Bitmap;\nimport android.graphics.BitmapFactory;\nimport android.os.AsyncTask;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.AbsListView;\nimport android.widget.AdapterView;\nimport android.widget.ArrayAdapter;\n\nimport com.odoo.core.utils.OControls;\nimport com.odoo.core.utils.OResource;\nimport com.odoo.core.utils.controls.ExpandableHeightGridView;\nimport com.odoo.R;\n\nimport java.net.URL;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport odoo.OdooInstance;\n\npublic class OdooInstancesSelectorDialog implements AdapterView.OnItemClickListener {\n    private Context mContext;\n    private ExpandableHeightGridView mGrid;\n    private ArrayAdapter<OdooInstance> mAdapter;\n    private List<OdooInstance> instances = new ArrayList<OdooInstance>();\n    private AlertDialog dialog;\n    private AlertDialog.Builder builder;\n    private OnInstanceSelectListener mOnInstanceSelectListener = null;\n    private OUser mUser;\n    private List<ImageLoader> imageLoaderLists = new ArrayList<>();\n\n    public OdooInstancesSelectorDialog(Context context, OUser user) {\n        mContext = context;\n        mUser = user;\n        AbsListView.LayoutParams params = new AbsListView.LayoutParams(AbsListView.LayoutParams.MATCH_PARENT,\n                AbsListView.LayoutParams.WRAP_CONTENT);\n        mGrid = new ExpandableHeightGridView(mContext);\n        mGrid.setLayoutParams(params);\n        mAdapter = new ArrayAdapter<OdooInstance>(mContext, R.layout.base_instance_item, instances) {\n            @Override\n            public View getView(int position, View convertView, ViewGroup parent) {\n                if (convertView == null)\n                    convertView = LayoutInflater.from(mContext).inflate(R.layout.base_instance_item, parent, false);\n                generateView(position, convertView, getItem(position));\n                return convertView;\n            }\n        };\n        int padd = OResource.dimen(mContext, R.dimen.activity_horizontal_margin);\n        mGrid.setPadding(padd, padd, padd, padd);\n        mGrid.setNumColumns(2);\n        mGrid.setAdapter(mAdapter);\n        mGrid.setOnItemClickListener(this);\n    }\n\n    public void setInstances(List<OdooInstance> items) {\n        instances.clear();\n        instances.addAll(items);\n        mAdapter.notifyDataSetChanged();\n    }\n\n    private void generateView(int position, View view, OdooInstance instance) {\n        OControls.setText(view, R.id.txvInstanceUrl, instance.getInstanceUrl());\n        OControls.setText(view, R.id.txvInstanceName, instance.getCompanyName());\n        String imageURL = instance.getInstanceUrl() + \"/web/binary/company_logo?dbname=\" + instance.getDatabaseName();\n        ImageLoader imageLoader = new ImageLoader(position, imageURL, R.id.imgInstance);\n        imageLoaderLists.add(imageLoader);\n        imageLoader.execute();\n\n    }\n\n    public void showDialog() {\n        if (dialog != null)\n            dialog.dismiss();\n        dialog = null;\n        builder = new AlertDialog.Builder(mContext);\n        builder.setTitle(R.string.label_select_instance);\n        builder.setView(mGrid);\n        builder.setCancelable(false);\n        builder.setNegativeButton(OResource.string(mContext, R.string.label_cancel),\n                new DialogInterface.OnClickListener() {\n                    @Override\n                    public void onClick(DialogInterface dialog, int which) {\n                        if (mOnInstanceSelectListener != null) {\n                            mOnInstanceSelectListener.canceledInstanceSelect();\n                        }\n                    }\n                });\n        dialog = builder.create();\n        dialog.show();\n    }\n\n    @Override\n    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {\n        OdooInstance instance = mAdapter.getItem(position);\n        if (dialog != null)\n            dialog.dismiss();\n        if (mOnInstanceSelectListener != null) {\n            for (ImageLoader imageLoader : imageLoaderLists) {\n                imageLoader.cancel(true);\n            }\n            mOnInstanceSelectListener.instanceSelected(instance, mUser);\n        }\n    }\n\n    public void setOnInstanceSelectListener(OnInstanceSelectListener listener) {\n        mOnInstanceSelectListener = listener;\n    }\n\n    public interface OnInstanceSelectListener {\n        public void instanceSelected(OdooInstance instance, OUser user);\n\n        public void canceledInstanceSelect();\n    }\n\n    class ImageLoader extends AsyncTask<Void, Void, Void> {\n\n        String image_url = \"\";\n        int image_view = -1;\n        int view_pos = -1;\n        Bitmap bmp = null;\n\n        public ImageLoader(int pos, String url, int image_view) {\n            view_pos = pos;\n            this.image_view = image_view;\n            image_url = url;\n        }\n\n        @Override\n        protected Void doInBackground(Void... params) {\n            try {\n                URL url = new URL(image_url);\n                bmp = BitmapFactory.decodeStream(url.openConnection()\n                        .getInputStream());\n            } catch (Exception e) {\n            }\n            return null;\n        }\n\n        @Override\n        protected void onPostExecute(Void result) {\n            super.onPostExecute(result);\n            if (bmp != null) {\n                View mView = mGrid.getChildAt(view_pos);\n                OControls.setImage(mView, image_view, bmp);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/core/support/OdooLoginHelper.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 18/12/14 3:15 PM\n */\npackage com.odoo.core.support;\n\nimport android.content.Context;\n\nimport com.odoo.App;\nimport com.odoo.datas.OConstants;\n\nimport org.json.JSONObject;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport odoo.OArguments;\nimport odoo.ODomain;\nimport odoo.Odoo;\nimport odoo.OdooAccountExpireException;\nimport odoo.OdooInstance;\nimport odoo.OdooVersion;\n\npublic class OdooLoginHelper {\n    private App mApp;\n    private Odoo mOdoo;\n    private Context mContext;\n\n    public OdooLoginHelper(Context context) {\n        mContext = context;\n        mApp = (App) mContext.getApplicationContext();\n    }\n\n    public OUser login(String username, String password, String database, String serverURL, Boolean forceConnect) {\n        try {\n            mOdoo = new Odoo(mContext, serverURL, forceConnect);\n            JSONObject res = mOdoo.authenticate(username, password, database);\n            int user_id;\n            if (res.get(\"uid\") instanceof Integer) {\n                user_id = res.getInt(\"uid\");\n                OUser user = new OUser();\n                user.setOAuthLogin(false);\n                user.setPassword(password);\n                user.setUsername(username);\n                user.setAllowSelfSignedSSL(forceConnect);\n                user.setHost(serverURL);\n                user.setUser_id(user_id);\n                user.setDatabase(database);\n\n                ODomain domain = new ODomain();\n                domain.add(\"id\", \"=\", user_id);\n                user = getUserDetails(domain, user, null);\n                mApp.setOdoo(mOdoo, user);\n                return user;\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return null;\n    }\n\n    public OUser instanceLogin(OdooInstance instance, OUser uData) throws OdooAccountExpireException {\n        try {\n            JSONObject res = mOdoo.oauth_authenticate(instance, uData.getUsername(), uData.getPassword());\n            int user_id;\n            if (res.get(\"uid\") instanceof Integer) {\n                user_id = res.getInt(\"uid\");\n                ODomain domain = new ODomain();\n                domain.add(\"id\", \"=\", user_id);\n                uData = getUserDetails(domain, uData, instance);\n                mApp.setOdoo(mOdoo, uData);\n                return uData;\n            }\n        } catch (OdooAccountExpireException e) {\n            throw new OdooAccountExpireException(e.getMessage());\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return null;\n    }\n\n    private OUser getUserDetails(ODomain domain, OUser data, OdooInstance instance) {\n        OUser user = data;\n        try {\n            OdooFields fields = new OdooFields(new String[]{\n                    \"name\", \"partner_id\", \"tz\", \"image_medium\", \"company_id\"\n            });\n            JSONObject res = mOdoo.search_read(\"res.users\", fields.get(), domain.get());\n            JSONObject userData = res.getJSONArray(\"records\").getJSONObject(0);\n            String database = user.getDatabase();\n            if (instance != null) {\n                user.setOAuthLogin(true);\n                database = instance.getDatabaseName();\n                user.setInstanceDatabase(instance.getDatabaseName());\n                user.setInstanceUrl(instance.getInstanceUrl());\n                user.setClientId(instance.getClientId());\n            }\n            user.setUser_id(userData.getInt(\"id\"));\n            user.setName(userData.getString(\"name\"));\n            user.setAvatar(userData.getString(\"image_medium\"));\n            user.setIsactive(true);\n            user.setAndroidName(androidName(user.getUsername(), database));\n            user.setPartner_id(userData.getJSONArray(\"partner_id\").getInt(0));\n            user.setTimezone(userData.getString(\"tz\"));\n            user.setCompany_id(userData.getJSONArray(\"company_id\").getInt(0) + \"\");\n\n            OdooVersion version = mOdoo.getOdooVersion();\n            user.setVersion_number(version.getVersion_number());\n            user.setVersion_serie(version.getServer_serie());\n\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return user;\n    }\n\n    public String androidName(String username, String database) {\n        return username + \"[\" + database + \"]\";\n    }\n\n    public List<OdooInstance> getOdooInstances(OUser user) {\n        List<OdooInstance> instances = new ArrayList<OdooInstance>();\n        //Default Instance (www.odoo.com)\n        OdooInstance oInstance = new OdooInstance();\n        oInstance.setCompanyName(OConstants.ODOO_COMPANY_NAME);\n        oInstance.setInstanceUrl(OConstants.URL_ODOO);\n        instances.add(oInstance);\n\n        //Getting user instances\n        try {\n            for (OdooInstance instance : mOdoo.get_instances(new OArguments().get())) {\n                if (instance.isSaas()) {\n                    instances.add(instance);\n                }\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return instances;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/core/support/OdooServerTester.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 18/12/14 12:00 PM\n */\npackage com.odoo.core.support;\n\nimport android.content.Context;\nimport android.text.TextUtils;\n\nimport com.odoo.core.utils.JSONUtils;\n\nimport org.json.JSONArray;\n\nimport java.util.List;\n\nimport javax.net.ssl.SSLPeerUnverifiedException;\n\nimport odoo.OVersionException;\nimport odoo.Odoo;\n\npublic class OdooServerTester {\n    private Context mContext;\n    private Boolean mForceConnect = false;\n    private Odoo mOdoo;\n    private JSONArray mDatabases = null;\n\n    public OdooServerTester(Context context) {\n        mContext = context;\n    }\n\n    public boolean testConnection(String serverURL, Boolean forceConnect) throws SSLPeerUnverifiedException, OVersionException {\n        mForceConnect = forceConnect;\n        if (!TextUtils.isEmpty(serverURL)) {\n            try {\n                mOdoo = new Odoo(mContext, serverURL, forceConnect);\n                mDatabases = mOdoo.getDatabaseList();\n                if (mDatabases == null) {\n                    mDatabases = new JSONArray();\n                    if (mOdoo.getDatabaseName() != null) {\n                        mDatabases.put(mOdoo.getDatabaseName());\n                    }\n                }\n                if (mDatabases.length() > 0)\n                    return true;\n            } catch (SSLPeerUnverifiedException peer) {\n                throw new SSLPeerUnverifiedException(peer.getMessage());\n            } catch (OVersionException version) {\n                throw new OVersionException(version.getMessage());\n            } catch (Exception e) {\n                e.printStackTrace();\n            }\n        }\n        return false;\n    }\n\n    public List<String> getDatabases() {\n        return JSONUtils.toList(mDatabases);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/core/support/OdooUserLoginSelectorDialog.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 19/12/14 1:49 PM\n */\npackage com.odoo.core.support;\n\nimport android.app.AlertDialog;\nimport android.content.Context;\nimport android.content.DialogInterface;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.AbsListView;\nimport android.widget.AdapterView;\nimport android.widget.ArrayAdapter;\nimport android.widget.ImageView;\n\nimport com.odoo.R;\nimport com.odoo.core.account.OdooUserAskPassword;\nimport com.odoo.core.auth.OdooAccountManager;\nimport com.odoo.core.utils.BitmapUtils;\nimport com.odoo.core.utils.OAlert;\nimport com.odoo.core.utils.OControls;\nimport com.odoo.core.utils.OResource;\nimport com.odoo.core.utils.controls.ExpandableHeightGridView;\n\nimport java.util.List;\n\nimport odoo.controls.BezelImageView;\n\npublic class OdooUserLoginSelectorDialog implements AdapterView.OnItemClickListener {\n    private Context mContext;\n    private ExpandableHeightGridView mGrid;\n    private ArrayAdapter<OUser> mAdapter;\n    private AlertDialog dialog;\n    private AlertDialog.Builder builder;\n    private OUser mUser;\n    private IUserLoginSelectListener mIUserLoginSelectListener = null;\n    private OdooUserAskPassword askPassword = null;\n\n    public OdooUserLoginSelectorDialog(Context context) {\n        mContext = context;\n        AbsListView.LayoutParams params = new AbsListView.LayoutParams(AbsListView.LayoutParams.MATCH_PARENT,\n                AbsListView.LayoutParams.WRAP_CONTENT);\n        mGrid = new ExpandableHeightGridView(mContext);\n        mGrid.setLayoutParams(params);\n        List<OUser> accounts = OdooAccountManager.getAllAccounts(mContext);\n        mAdapter = new ArrayAdapter<OUser>(mContext, R.layout.base_instance_item, accounts) {\n            @Override\n            public View getView(int position, View convertView, ViewGroup parent) {\n                if (convertView == null)\n                    convertView = LayoutInflater.from(mContext).inflate(R.layout.base_instance_item, parent, false);\n                generateView(position, convertView, getItem(position));\n                return convertView;\n            }\n        };\n        int padding = OResource.dimen(mContext, R.dimen.activity_horizontal_margin);\n        mGrid.setPadding(padding, padding, padding, padding);\n        if (accounts.size() > 1)\n            mGrid.setNumColumns(2);\n        mGrid.setAdapter(mAdapter);\n        mGrid.setOnItemClickListener(this);\n    }\n\n    private void generateView(int position, View view, OUser user) {\n        BezelImageView imgView = (BezelImageView) view.findViewById(R.id.imgInstance);\n        if (user.getAvatar().equals(\"false\")) {\n            imgView.setImageResource(R.drawable.avatar);\n        } else {\n            imgView.setImageBitmap(BitmapUtils.getBitmapImage(mContext, user.getAvatar()));\n        }\n        imgView.setScaleType(ImageView.ScaleType.CENTER_CROP);\n        imgView.autoSetMaskDrawable();\n        OControls.setText(view, R.id.txvInstanceName, user.getName());\n        OControls.setText(view, R.id.txvInstanceUrl, (user.isOAauthLogin()) ? user.getInstanceUrl() : user.getHost());\n\n    }\n\n    public void setUserLoginSelectListener(IUserLoginSelectListener listener) {\n        mIUserLoginSelectListener = listener;\n    }\n\n\n    public void show() {\n        if (dialog != null)\n            dialog.dismiss();\n        dialog = null;\n        builder = new AlertDialog.Builder(mContext);\n        builder.setTitle(R.string.label_select_user);\n        builder.setView(mGrid);\n        builder.setCancelable(false);\n        builder.setPositiveButton(OResource.string(mContext, R.string.label_drawer_account_add_account),\n                new DialogInterface.OnClickListener() {\n                    @Override\n                    public void onClick(DialogInterface dialog, int which) {\n                        if (mIUserLoginSelectListener != null) {\n                            mIUserLoginSelectListener.onNewAccountRequest();\n                        }\n                        dialog.dismiss();\n                    }\n                });\n        builder.setNegativeButton(OResource.string(mContext, R.string.label_cancel),\n                new DialogInterface.OnClickListener() {\n                    @Override\n                    public void onClick(DialogInterface dialog, int which) {\n                        if (mIUserLoginSelectListener != null) {\n                            mIUserLoginSelectListener.onCancelSelect();\n                        }\n                        dialog.dismiss();\n                    }\n                });\n        dialog = builder.create();\n        dialog.show();\n    }\n\n    @Override\n    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {\n        final OUser user = mAdapter.getItem(position);\n        dialog.dismiss();\n        if (mIUserLoginSelectListener != null) {\n            // Ask for password of account\n            askPassword = OdooUserAskPassword.get(mContext, user);\n            askPassword.setOnUserPasswordValidateListener(new OdooUserAskPassword.OnUserPasswordValidateListener() {\n                @Override\n                public void onSuccess() {\n                    mIUserLoginSelectListener.onUserSelected(user);\n                }\n\n                @Override\n                public void onCancel() {\n                    mIUserLoginSelectListener.onRequestAccountSelect();\n                }\n\n                @Override\n                public void onFail() {\n                    OAlert.showError(mContext, OResource.string(mContext,\n                            R.string.error_invalid_password), new OAlert.OnAlertDismissListener() {\n                        @Override\n                        public void onAlertDismiss() {\n                            onCancel();\n                        }\n                    });\n                }\n            });\n            askPassword.show();\n        }\n    }\n\n\n    public interface IUserLoginSelectListener {\n        public void onUserSelected(OUser user);\n\n        public void onNewAccountRequest();\n\n        public void onCancelSelect();\n\n        public void onRequestAccountSelect();\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/core/support/addons/AddonsHelper.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 30/12/14 3:12 PM\n */\npackage com.odoo.core.support.addons;\n\nimport android.util.Log;\n\nimport java.lang.reflect.Field;\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class AddonsHelper {\n    public static final String TAG = AddonsHelper.class.getSimpleName();\n    private List<OAddon> addons = new ArrayList<OAddon>();\n    private OAddon defaultAddon = null;\n\n\n    public List<OAddon> getAddons() {\n        if (addons.size() <= 0) {\n            prepareAddons();\n        }\n        return addons;\n    }\n\n    private void prepareAddons() {\n        addons.clear();\n        for (Field addon : getClass().getDeclaredFields()) {\n            if (addon.getType().isAssignableFrom(OAddon.class)) {\n                addon.setAccessible(true);\n                try {\n                    OAddon mAddon = (OAddon) addon.get(this);\n                    if (mAddon.isDefault()) {\n                        defaultAddon = mAddon;\n                        addons.add(0, defaultAddon);\n                    } else {\n                        addons.add(mAddon);\n                    }\n                } catch (Exception e) {\n                    Log.e(TAG, e.getMessage());\n                }\n            }\n        }\n    }\n\n    public OAddon getDefaultAddon() {\n        prepareAddons();\n        return defaultAddon;\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/core/support/addons/OAddon.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 30/12/14 3:13 PM\n */\npackage com.odoo.core.support.addons;\n\nimport android.util.Log;\n\npublic class OAddon {\n    public static final String TAG = OAddon.class.getSimpleName();\n    private Class<?> addon = null;\n    private Boolean isDefault = false;\n\n    public OAddon(Class<?> addon_class) {\n        addon = addon_class;\n    }\n\n    public OAddon setDefault() {\n        isDefault = true;\n        return this;\n    }\n\n    public Object get() {\n        try {\n            return addon.newInstance();\n        } catch (Exception e) {\n            Log.i(TAG, e.getMessage());\n        }\n        return null;\n    }\n\n    public Boolean isDefault() {\n        return isDefault;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/core/support/addons/fragment/BaseFragment.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 30/12/14 3:29 PM\n */\npackage com.odoo.core.support.addons.fragment;\n\nimport android.content.ContentResolver;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.IntentFilter;\nimport android.content.SyncStatusObserver;\nimport android.os.Bundle;\nimport android.os.Handler;\nimport android.support.v4.app.Fragment;\nimport android.support.v4.view.MenuItemCompat;\nimport android.support.v4.widget.SwipeRefreshLayout;\nimport android.support.v7.widget.SearchView;\nimport android.text.TextUtils;\nimport android.view.Menu;\nimport android.view.View;\nimport android.widget.ListView;\n\nimport com.odoo.App;\nimport com.odoo.OdooActivity;\nimport com.odoo.R;\nimport com.odoo.core.orm.OModel;\nimport com.odoo.core.service.receivers.ISyncFinishReceiver;\nimport com.odoo.core.support.OUser;\nimport com.odoo.core.utils.OResource;\n\nimport odoo.controls.fab.FloatingActionButton;\n\npublic abstract class BaseFragment extends Fragment implements IBaseFragment {\n    private Context mContext;\n\n    private OModel syncStatusObserverModel = null;\n    private String drawerRefreshTag = null;\n    private Object mSyncObserverHandle;\n    private ISyncStatusObserverListener mSyncStatusObserverListener = null;\n    private SwipeRefreshLayout mSwipeRefresh = null;\n    private IOnSearchViewChangeListener mOnSearchViewChangeListener;\n    private SearchView mSearchView;\n    private FloatingActionButton mFab = null;\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        mContext = getActivity();\n        parent().setHasActionBarSpinner(false);\n    }\n\n    public void setTitle(String title) {\n        getActivity().setTitle(title);\n    }\n\n    public OModel db() {\n        Class<?> model = database();\n        if (model != null) {\n            return new OModel(mContext, null, user()).createInstance(model);\n        }\n        return null;\n    }\n\n    public OUser user() {\n        if (mContext != null)\n            return OUser.current(mContext);\n        return null;\n    }\n\n    public OdooActivity parent() {\n        return (OdooActivity) mContext;\n    }\n\n    public String _s(int res_id) {\n        return OResource.string(mContext, res_id);\n    }\n\n    public int _c(int res_id) {\n        return OResource.color(mContext, res_id);\n    }\n\n    public int _dim(int res_id) {\n        return OResource.dimen(mContext, res_id);\n    }\n\n    // Sync Observer\n    public void setHasSyncStatusObserver(String drawerRefreshTag, ISyncStatusObserverListener syncStatusObserver,\n                                         OModel model) {\n        this.drawerRefreshTag = drawerRefreshTag;\n        mSyncStatusObserverListener = syncStatusObserver;\n        syncStatusObserverModel = model;\n    }\n\n    private SyncStatusObserver mSyncStatusObserver = new SyncStatusObserver() {\n        /** Callback invoked with the sync adapter status changes. */\n        @Override\n        public void onStatusChanged(int which) {\n            boolean refreshing = false;\n            switch (which) {\n                case ContentResolver.SYNC_OBSERVER_TYPE_PENDING:\n                case ContentResolver.SYNC_OBSERVER_TYPE_ACTIVE:\n                    refreshing = true;\n            }\n            final boolean finalRefreshing = refreshing;\n            getActivity().runOnUiThread(new Runnable() {\n                @Override\n                public void run() {\n                    mSyncStatusObserverListener.onStatusChange(finalRefreshing);\n                }\n            });\n        }\n    };\n\n\n    // Swipe refresh view\n    public void setHasSwipeRefreshView(View parent, int resource_id,\n                                       SwipeRefreshLayout.OnRefreshListener listener) {\n        mSwipeRefresh = (SwipeRefreshLayout) parent.findViewById(resource_id);\n        mSwipeRefresh.setOnRefreshListener(listener);\n        mSwipeRefresh.setColorSchemeResources(R.color.android_blue,\n                R.color.android_green,\n                R.color.android_orange_dark,\n                R.color.android_red);\n    }\n\n    public void setSwipeRefreshing(boolean refreshing) {\n        if (mSwipeRefresh != null)\n            mSwipeRefresh.setRefreshing(refreshing);\n    }\n\n    public void hideRefreshingProgress() {\n        if (mSwipeRefresh != null) {\n            new Handler().postDelayed(new Runnable() {\n                @Override\n                public void run() {\n                    mSwipeRefresh.setRefreshing(false);\n                }\n            }, 1000);\n        }\n    }\n\n    public boolean inNetwork() {\n        App app = (App) mContext.getApplicationContext();\n        return app.inNetwork();\n    }\n\n    @Override\n    public void onPause() {\n        super.onPause();\n        if (mSyncObserverHandle != null) {\n            ContentResolver.removeStatusChangeListener(mSyncObserverHandle);\n            mSyncObserverHandle = null;\n        }\n        try {\n            parent().unregisterReceiver(syncFinishReceiver);\n        } catch (Exception e) {\n            // Skipping issue related to unregister receiver\n        }\n    }\n\n    @Override\n    public void onDestroy() {\n        super.onDestroy();\n        onNavSpinnerDestroy();\n    }\n\n    protected void onNavSpinnerDestroy() {\n        if (parent().getActionBarSpinner() != null) {\n            parent().getActionBarSpinner().setAdapter(null);\n            parent().setHasActionBarSpinner(false);\n        }\n    }\n\n    @Override\n    public void onResume() {\n        super.onResume();\n        if (OUser.current(getActivity()) == null)\n            return;\n        if (mSyncStatusObserverListener != null) {\n            mSyncStatusObserver.onStatusChanged(0);\n            int mask = ContentResolver.SYNC_OBSERVER_TYPE_PENDING\n                    | ContentResolver.SYNC_OBSERVER_TYPE_ACTIVE;\n            mSyncObserverHandle = ContentResolver.addStatusChangeListener(mask,\n                    mSyncStatusObserver);\n        }\n        parent().registerReceiver(syncFinishReceiver,\n                new IntentFilter(ISyncFinishReceiver.SYNC_FINISH));\n    }\n\n    public void setHasSearchView(IOnSearchViewChangeListener listener,\n                                 Menu menu, int menu_id) {\n        mOnSearchViewChangeListener = listener;\n        mSearchView = (SearchView) MenuItemCompat.getActionView(menu\n                .findItem(menu_id));\n        if (mSearchView != null) {\n            mSearchView.setOnCloseListener(closeListener);\n            mSearchView.setOnQueryTextListener(searchViewQueryListener);\n            mSearchView.setIconifiedByDefault(true);\n        }\n    }\n\n    private SearchView.OnCloseListener closeListener = new SearchView.OnCloseListener() {\n\n        @Override\n        public boolean onClose() {\n            // Restore the SearchView if a query was entered\n            if (!TextUtils.isEmpty(mSearchView.getQuery())) {\n                mSearchView.setQuery(null, true);\n            }\n            mOnSearchViewChangeListener.onSearchViewClose();\n            return true;\n        }\n    };\n\n    private SearchView.OnQueryTextListener searchViewQueryListener = new SearchView.OnQueryTextListener() {\n\n        public boolean onQueryTextChange(String newText) {\n            String newFilter = !TextUtils.isEmpty(newText) ? newText : null;\n            return mOnSearchViewChangeListener\n                    .onSearchViewTextChange(newFilter);\n        }\n\n        @Override\n        public boolean onQueryTextSubmit(String query) {\n            // Don't care about this.\n            return true;\n        }\n    };\n\n    public void setHasFloatingButton(View view, int res_id, ListView list,\n                                     View.OnClickListener clickListener) {\n        mFab = (FloatingActionButton) view.findViewById(res_id);\n        if (mFab != null) {\n            if (list != null)\n                mFab.listenTo(list);\n            mFab.setOnClickListener(clickListener);\n        }\n    }\n\n    public void hideFab() {\n        if (mFab != null) {\n            mFab.setVisibility(View.GONE);\n        }\n    }\n\n    public void showFab() {\n        if (mFab != null) {\n            mFab.setVisibility(View.VISIBLE);\n        }\n    }\n\n    private ISyncFinishReceiver syncFinishReceiver = new ISyncFinishReceiver() {\n        @Override\n        public void onReceive(Context context, Intent intent) {\n            hideRefreshingProgress();\n            if (mSyncStatusObserverListener != null)\n                mSyncStatusObserverListener.onStatusChange(false);\n        }\n    };\n\n    public void startFragment(Fragment fragment, Boolean addToBackState, Bundle extra) {\n        parent().loadFragment(fragment, addToBackState, extra);\n    }\n\n    public void startFragment(Fragment fragment, Boolean addToBackState) {\n        startFragment(fragment, addToBackState, null);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/core/support/addons/fragment/IBaseFragment.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 30/12/14 3:30 PM\n */\npackage com.odoo.core.support.addons.fragment;\n\nimport android.content.Context;\n\nimport com.odoo.core.support.drawer.ODrawerItem;\n\nimport java.util.List;\n\npublic interface IBaseFragment {\n    public List<ODrawerItem> drawerMenus(Context context);\n\n    public <T> Class<T> database();\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/core/support/addons/fragment/IOnSearchViewChangeListener.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 8/1/15 6:30 PM\n */\npackage com.odoo.core.support.addons.fragment;\n\npublic interface IOnSearchViewChangeListener {\n    public static final String TAG = IOnSearchViewChangeListener.class.getSimpleName();\n\n    public boolean onSearchViewTextChange(String newFilter);\n\n    public void onSearchViewClose();\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/core/support/addons/fragment/ISyncStatusObserverListener.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 8/1/15 12:23 PM\n */\npackage com.odoo.core.support.addons.fragment;\n\npublic interface ISyncStatusObserverListener {\n    public static final String TAG = ISyncStatusObserverListener.class.getSimpleName();\n\n    public void onStatusChange(Boolean refreshing);\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/core/support/drawer/ODrawerItem.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 30/12/14 4:09 PM\n */\npackage com.odoo.core.support.drawer;\n\nimport android.os.Bundle;\n\nimport java.io.Serializable;\nimport java.util.Locale;\n\npublic class ODrawerItem implements Serializable {\n    private static final long serialVersionUID = 1L;\n    private String key = null, title = null;\n    private String unique_key = null;\n    private Integer counter = 0, icon = 0;\n    private Object instance = null;\n    private Boolean mGroupTitle = false;\n    private Bundle mBundle = null;\n\n    public ODrawerItem(String key) {\n        this.key = key;\n\n    }\n\n    public ODrawerItem setTitle(String title) {\n        this.title = title;\n        unique_key = key.toLowerCase(Locale.getDefault()) + \"_\" + title.replaceAll(\" \", \"_\")\n                .toLowerCase(Locale.getDefault());\n        return this;\n    }\n\n    public String getTitle() {\n        return title;\n    }\n\n    public ODrawerItem setIcon(int icon) {\n        this.icon = icon;\n        return this;\n    }\n\n    public Integer getIcon() {\n        return icon;\n    }\n\n    public ODrawerItem setCounter(int counter) {\n        this.counter = counter;\n        return this;\n    }\n\n    public Integer getCounter() {\n        return counter;\n    }\n\n    public ODrawerItem setInstance(Object instance) {\n        this.instance = instance;\n        return this;\n    }\n\n    public Object getInstance() {\n        return instance;\n    }\n\n    public ODrawerItem setGroupTitle() {\n        mGroupTitle = true;\n        return this;\n    }\n\n    public Boolean isGroupTitle() {\n        return mGroupTitle;\n    }\n\n    public ODrawerItem setExtra(Bundle bundle) {\n        mBundle = bundle;\n        return this;\n    }\n\n    public Bundle getExtra() {\n        return mBundle;\n    }\n\n    public String getKey() {\n        return unique_key;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/core/support/list/IOnItemClickListener.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 13/1/15 3:09 PM\n */\npackage com.odoo.core.support.list;\n\nimport android.view.View;\n\npublic interface IOnItemClickListener {\n    public void onItemDoubleClick(View view, int position);\n\n    public void onItemClick(View view, int position);\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/core/support/list/OCursorListAdapter.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 8/1/15 12:44 PM\n */\npackage com.odoo.core.support.list;\n\nimport android.content.Context;\nimport android.database.Cursor;\nimport android.os.Handler;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.AbsListView;\nimport android.widget.AdapterView;\nimport android.widget.CursorAdapter;\nimport android.widget.SectionIndexer;\n\nimport com.odoo.core.orm.ODataRow;\nimport com.odoo.core.utils.logger.OLog;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\n\nimport odoo.controls.OForm;\n\npublic class OCursorListAdapter extends CursorAdapter implements\n        AdapterView.OnItemClickListener, SectionIndexer {\n    public static final String TAG = OCursorListAdapter.class.getSimpleName();\n\n    private Integer mLayout = null;\n    private LayoutInflater mInflater = null;\n    private OnViewCreateListener mOnViewCreateListener = null;\n    private HashMap<Integer, OnRowViewClickListener> mViewClickListeners = new HashMap<>();\n    private HashMap<String, View> mViewCache = new HashMap<String, View>();\n    private Boolean mCacheViews = false;\n    private OnViewBindListener mOnViewBindListener = null;\n    private BeforeBindUpdateData mBeforeBindUpdateData = null;\n    private Context mContext = null;\n    private IOnItemClickListener mIOnItemClickListener = null;\n    private AbsListView mListView = null;\n    private Boolean hasIndexers = false;\n    private String mIndexerColumn = null;\n    private HashMap<String, Integer> azIndexers = new HashMap<>();\n    private String[] sections = new String[0];\n\n    public OCursorListAdapter(Context context, Cursor c, int layout) {\n        super(context, c, false);\n        mLayout = layout;\n        mInflater = LayoutInflater.from(context);\n        mContext = context;\n    }\n\n    public OCursorListAdapter allowCacheView(Boolean cache) {\n        mCacheViews = cache;\n        return this;\n    }\n\n    public View getCachedView(Cursor cr) {\n        int pos = cr.getPosition();\n        if (mViewCache.size() > pos) {\n            return mViewCache.get(\"view_\" + pos);\n        }\n        return null;\n    }\n\n    @Override\n    public void bindView(View view, Context context, Cursor cursor) {\n        final ODataRow row = new ODataRow();\n        for (String col : cursor.getColumnNames()) {\n            row.put(col, getValue(cursor, col));\n        }\n        if (mBeforeBindUpdateData != null) {\n            row.addAll(mBeforeBindUpdateData.updateDataRow(cursor));\n        }\n        if (view instanceof OForm) {\n            OForm form = (OForm) view;\n            form.initForm(row);\n        }\n        if (mOnViewBindListener != null) {\n            mOnViewBindListener.onViewBind(view, cursor, row);\n        }\n    }\n\n    @Override\n    public View getView(final int position, View view, ViewGroup viewGroup) {\n        Cursor cursor = (Cursor) getItem(position);\n        view = getCachedView(cursor);\n        if (mCacheViews && view != null) {\n            return view;\n        }\n        view = newView(mContext, cursor, (ViewGroup) view);\n        final View mView = view;\n        for (final int id : mViewClickListeners.keySet()) {\n            new Handler().postDelayed(new Runnable() {\n\n                @Override\n                public void run() {\n                    if (mView.findViewById(id) != null) {\n                        mView.findViewById(id).setOnClickListener(\n                                new View.OnClickListener() {\n\n                                    @Override\n                                    public void onClick(View v) {\n                                        OnRowViewClickListener listener = mViewClickListeners\n                                                .get(id);\n                                        Cursor c = getCursor();\n                                        c.moveToPosition(position);\n                                        listener.onRowViewClick(position, c, v,\n                                                mView);\n                                    }\n                                });\n                    } else {\n                        OLog.log(\"View @id/\"\n                                + mContext.getResources().getResourceEntryName(\n                                id) + \" not found\");\n                    }\n                }\n            }, 100);\n        }\n        return super.getView(position, view, viewGroup);\n    }\n\n    private Object getValue(Cursor c, String column) {\n        Object value = false;\n        int index = c.getColumnIndex(column);\n        switch (c.getType(index)) {\n            case Cursor.FIELD_TYPE_NULL:\n                value = false;\n                break;\n            case Cursor.FIELD_TYPE_BLOB:\n            case Cursor.FIELD_TYPE_STRING:\n                value = c.getString(index);\n                break;\n            case Cursor.FIELD_TYPE_FLOAT:\n                value = c.getFloat(index);\n                break;\n            case Cursor.FIELD_TYPE_INTEGER:\n                value = c.getInt(index);\n                break;\n        }\n        return value;\n    }\n\n    @Override\n    public View newView(Context context, Cursor cursor, ViewGroup viewGroup) {\n        View view;\n        if (mCacheViews && getCachedView(cursor) != null) {\n            view = getCachedView(cursor);\n            if (!view.isDirty()) {\n                return view;\n            }\n        }\n        if (mOnViewCreateListener != null) {\n            view = mOnViewCreateListener.onViewCreated(context, viewGroup,\n                    cursor, cursor.getPosition());\n            if (view == null) {\n                view = mInflater.inflate(mLayout, viewGroup, false);\n            }\n        } else\n            view = mInflater.inflate(mLayout, viewGroup, false);\n        if (mCacheViews) {\n            mViewCache.put(\"view_\" + cursor.getPosition(), view);\n        }\n        return view;\n    }\n\n    @Override\n    public void notifyDataSetChanged() {\n        super.notifyDataSetChanged();\n        if (hasIndexers && mIndexerColumn != null) {\n            Cursor cr = getCursor();\n            if (cr.getCount() > 0) {\n                int pos = 0;\n                if (cr.moveToFirst()) {\n                    List<String> keys = new ArrayList<>();\n                    do {\n                        int index = cr.getColumnIndex(mIndexerColumn);\n                        if (index > -1) {\n                            String colValue = cr.getString(index);\n                            azIndexers.put(colValue.substring(0, 1), pos);\n                            keys.add(colValue.substring(0, 1));\n                        }\n                        pos++;\n                    } while (cr.moveToNext());\n                    Collections.sort(keys);\n                    sections = keys.toArray(new String[keys.size()]);\n                }\n            }\n        }\n    }\n\n    public View inflate(int resource, ViewGroup viewGroup) {\n        return mInflater.inflate(resource, viewGroup, false);\n    }\n\n    public int getResource() {\n        return mLayout;\n    }\n\n    public void setOnRowViewClickListener(int view_id,\n                                          OnRowViewClickListener listener) {\n        mViewClickListeners.put(view_id, listener);\n    }\n\n    public void setOnViewCreateListener(OnViewCreateListener viewCreateListener) {\n        mOnViewCreateListener = viewCreateListener;\n    }\n\n    public void setOnViewBindListener(OnViewBindListener bindListener) {\n        mOnViewBindListener = bindListener;\n    }\n\n    public void setBeforeBindUpdateData(BeforeBindUpdateData updater) {\n        mBeforeBindUpdateData = updater;\n    }\n\n    public interface OnRowViewClickListener {\n        public void onRowViewClick(int position, Cursor cursor, View view,\n                                   View parent);\n    }\n\n    public interface OnViewBindListener {\n        public void onViewBind(View view, Cursor cursor, ODataRow row);\n    }\n\n    public interface BeforeBindUpdateData {\n        public ODataRow updateDataRow(Cursor cr);\n    }\n\n    public interface OnViewCreateListener {\n        public View onViewCreated(Context context, ViewGroup view, Cursor cr,\n                                  int position);\n    }\n\n    public void handleItemClickListener(AbsListView absListView, IOnItemClickListener listener) {\n        mIOnItemClickListener = listener;\n        mListView = absListView;\n        if (mListView != null && mIOnItemClickListener != null) {\n            mListView.setOnItemClickListener(this);\n        }\n    }\n\n    private Boolean mDoubleClick = false;\n    private Integer mDoubleClickItemIndex = -1;\n\n    @Override\n    public void onItemClick(AdapterView<?> parent, final View view, final int position, long id) {\n        if (mDoubleClick && mDoubleClickItemIndex == position) {\n            mDoubleClick = false;\n            mIOnItemClickListener.onItemDoubleClick(view, position);\n        } else {\n            mDoubleClick = true;\n            mDoubleClickItemIndex = position;\n        }\n        new Handler().postDelayed(new Runnable() {\n            @Override\n            public void run() {\n                if (mDoubleClick) {\n                    mDoubleClick = false;\n                    mDoubleClickItemIndex = -1;\n                    mIOnItemClickListener.onItemClick(view, position);\n                }\n            }\n        }, 500);\n    }\n\n    public void setHasSectionIndexers(boolean hasSectionIndexers, String onColumn) {\n        hasIndexers = hasSectionIndexers;\n        mIndexerColumn = onColumn;\n    }\n\n    // Section Indexers\n    @Override\n    public Object[] getSections() {\n        return sections;\n    }\n\n    @Override\n    public int getPositionForSection(int sectionIndex) {\n        return azIndexers.get(sections[sectionIndex]);\n    }\n\n    @Override\n    public int getSectionForPosition(int position) {\n        return azIndexers.get(sections[position]);\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/core/support/list/OListAdapter.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 7/1/15 6:07 PM\n */\npackage com.odoo.core.support.list;\n\nimport android.content.Context;\nimport android.text.TextUtils;\nimport android.util.Log;\nimport android.widget.ArrayAdapter;\nimport android.widget.Filter;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class OListAdapter extends ArrayAdapter<Object> {\n    public static final String TAG = OListAdapter.class.getSimpleName();\n\n    private Context mContext = null;\n    private List<Object> mObjects = null;\n    private List<Object> mAllObjects = null;\n    private RowFilter mFilter = null;\n    private int mResourceId = 0;\n    private RowFilterTextListener mRowFilterTextListener = null;\n    private OnSearchChange mOnSearchChange = null;\n\n    public OListAdapter(Context context, int resource, List<Object> objects) {\n        super(context, resource, objects);\n        Log.d(TAG, \"OListAdapter->constructor()\");\n        mContext = context;\n        mObjects = new ArrayList<>(objects);\n        mAllObjects = new ArrayList<>(objects);\n        mResourceId = resource;\n    }\n\n    @Override\n    public Filter getFilter() {\n        if (mFilter == null) {\n            mFilter = new RowFilter();\n        }\n        return mFilter;\n    }\n\n    public int getResource() {\n        return mResourceId;\n    }\n\n    public void replaceObjectAtPosition(int position, Object object) {\n        mAllObjects.remove(position);\n        mAllObjects.add(position, object);\n        mObjects.remove(position);\n        mObjects.add(position, object);\n    }\n\n    public void notifiyDataChange(List<Object> objects) {\n        Log.d(TAG, \"OListAdapter->notifiyDataChange()\");\n        mAllObjects.clear();\n        mObjects.clear();\n        mAllObjects.addAll(objects);\n        mObjects.addAll(objects);\n        notifyDataSetChanged();\n    }\n\n    class RowFilter extends Filter {\n\n        @Override\n        protected FilterResults performFiltering(CharSequence constraint) {\n            FilterResults result = new FilterResults();\n            if (!TextUtils.isEmpty(constraint)) {\n                String searchingStr = constraint.toString().toLowerCase();\n                List<Object> filteredItems = new ArrayList<Object>();\n                for (Object item : mAllObjects) {\n                    String filterText = \"\";\n                    if (mRowFilterTextListener != null) {\n                        filterText = mRowFilterTextListener.filterCompareWith(\n                                item).toLowerCase();\n                    } else {\n                        filterText = item.toString().toLowerCase();\n                    }\n                    if (filterText.contains(searchingStr)) {\n                        filteredItems.add(item);\n                    }\n                }\n                result.count = filteredItems.size();\n                result.values = filteredItems;\n\n            } else {\n                synchronized (this) {\n                    result.count = mAllObjects.size();\n                    result.values = mAllObjects;\n                }\n            }\n            return result;\n        }\n\n        @SuppressWarnings(\"unchecked\")\n        @Override\n        protected void publishResults(CharSequence constraint,\n                                      FilterResults results) {\n            clear();\n            mObjects = (List<Object>) results.values;\n            addAll(mObjects);\n            notifyDataSetChanged();\n            if (mOnSearchChange != null) {\n                mOnSearchChange.onSearchChange(mObjects);\n            }\n        }\n    }\n\n    public void setOnSearchChange(OnSearchChange callback) {\n        mOnSearchChange = callback;\n    }\n\n    public void setRowFilterTextListener(RowFilterTextListener listener) {\n        mRowFilterTextListener = listener;\n    }\n\n    public interface RowFilterTextListener {\n\n        public String filterCompareWith(Object object);\n    }\n\n    public interface OnSearchChange {\n\n        public void onSearchChange(List<Object> newRecords);\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/core/support/sync/SyncUtils.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 8/1/15 11:39 AM\n */\npackage com.odoo.core.support.sync;\n\nimport android.accounts.Account;\nimport android.content.ContentResolver;\nimport android.content.Context;\nimport android.os.Bundle;\nimport android.util.Log;\n\nimport com.odoo.core.support.OUser;\n\npublic class SyncUtils {\n    public static final String TAG = SyncUtils.class.getSimpleName();\n\n    private Context mContext;\n    private OUser mUser;\n\n    public SyncUtils(Context context, OUser user) {\n        mContext = context;\n        mUser = (user != null) ? user : OUser.current(context);\n    }\n\n    public static SyncUtils get(Context context) {\n        return new SyncUtils(context, null);\n    }\n\n    public static SyncUtils get(Context context, OUser user) {\n        return new SyncUtils(context, user);\n    }\n\n    public void setAutoSync(String authority, boolean autoSync) {\n        try {\n            Account account = mUser.getAccount();\n            if (!ContentResolver.isSyncActive(account, authority)) {\n                ContentResolver.setSyncAutomatically(account, authority, autoSync);\n            }\n        } catch (NullPointerException e) {\n            Log.e(TAG, e.getMessage());\n            e.printStackTrace();\n        }\n    }\n\n    public void requestSync(String authority) {\n        requestSync(authority, null);\n    }\n\n    public void requestSync(String authority, Bundle bundle) {\n        Account account = mUser.getAccount();\n        Bundle settingsBundle = new Bundle();\n        settingsBundle.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);\n        settingsBundle.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true);\n        if (bundle != null) {\n            settingsBundle.putAll(bundle);\n        }\n        ContentResolver.requestSync(account, authority, settingsBundle);\n    }\n\n    public void setSyncPeriodic(String authority, long interval_in_minute,\n                                long seconds_per_minute, long milliseconds_per_second) {\n        Account account = mUser.getAccount();\n        Bundle extras = new Bundle();\n        this.setAutoSync(authority, true);\n        ContentResolver.setIsSyncable(account, authority, 1);\n        final long sync_interval = interval_in_minute * seconds_per_minute\n                * milliseconds_per_second;\n        ContentResolver.addPeriodicSync(account, authority, extras,\n                sync_interval);\n\n    }\n\n    public void cancelSync(String authority) {\n        Account account = mUser.getAccount();\n        ContentResolver.cancelSync(account, authority);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/core/utils/BitmapUtils.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 19/12/14 11:42 AM\n */\npackage com.odoo.core.utils;\n\nimport android.content.ContentResolver;\nimport android.content.Context;\nimport android.content.res.Resources;\nimport android.graphics.Bitmap;\nimport android.graphics.BitmapFactory;\nimport android.graphics.Canvas;\nimport android.graphics.Color;\nimport android.graphics.Paint;\nimport android.graphics.Rect;\nimport android.net.Uri;\nimport android.text.TextPaint;\nimport android.util.Base64;\n\nimport com.odoo.R;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\n\nimport odoo.controls.OControlHelper;\n\npublic class BitmapUtils {\n    public static final int THUMBNAIL_SIZE = 500;\n\n    /**\n     * Read bytes.\n     *\n     * @param uri      the uri\n     * @param resolver the resolver\n     * @return the byte[]\n     * @throws IOException Signals that an I/O exception has occurred.\n     */\n    private static byte[] readBytes(Uri uri, ContentResolver resolver, boolean thumbnail)\n            throws IOException {\n        // this dynamically extends to take the bytes you read\n        InputStream inputStream = resolver.openInputStream(uri);\n        ByteArrayOutputStream byteBuffer = new ByteArrayOutputStream();\n\n        if (!thumbnail) {\n            // this is storage overwritten on each iteration with bytes\n            int bufferSize = 1024;\n            byte[] buffer = new byte[bufferSize];\n\n            // we need to know how may bytes were read to write them to the\n            // byteBuffer\n            int len = 0;\n            while ((len = inputStream.read(buffer)) != -1) {\n                byteBuffer.write(buffer, 0, len);\n            }\n        } else {\n            Bitmap imageBitmap = BitmapFactory.decodeStream(inputStream);\n            int thumb_width = imageBitmap.getWidth() / 2;\n            int thumb_height = imageBitmap.getHeight() / 2;\n            if (thumb_width > THUMBNAIL_SIZE) {\n                thumb_width = THUMBNAIL_SIZE;\n            }\n            if (thumb_width == THUMBNAIL_SIZE) {\n                thumb_height = ((imageBitmap.getHeight() / 2) * THUMBNAIL_SIZE)\n                        / (imageBitmap.getWidth() / 2);\n            }\n            imageBitmap = Bitmap.createScaledBitmap(imageBitmap, thumb_width, thumb_height, false);\n            imageBitmap.compress(Bitmap.CompressFormat.JPEG, 100, byteBuffer);\n        }\n        // and then we can return your byte array.\n        return byteBuffer.toByteArray();\n    }\n\n    public static String uriToBase64(Uri uri, ContentResolver resolver) {\n        return uriToBase64(uri, resolver, false);\n    }\n\n    public static String uriToBase64(Uri uri, ContentResolver resolver, boolean thumbnail) {\n        String encodedBase64 = \"\";\n        try {\n            byte[] bytes = readBytes(uri, resolver, thumbnail);\n            encodedBase64 = Base64.encodeToString(bytes, 0);\n        } catch (IOException e1) {\n            e1.printStackTrace();\n        }\n        return encodedBase64;\n    }\n\n    /**\n     * Gets the bitmap image.\n     *\n     * @param context the context\n     * @param base64  the base64\n     * @return the bitmap image\n     */\n    public static Bitmap getBitmapImage(Context context, String base64) {\n        byte[] imageAsBytes = Base64.decode(base64.getBytes(), 5);\n        return BitmapFactory.decodeByteArray(imageAsBytes, 0,\n                imageAsBytes.length);\n\n    }\n\n    public static Bitmap getAlphabetImage(Context context, String content) {\n        Resources res = context.getResources();\n        Bitmap mDefaultBitmap = BitmapFactory.decodeResource(res, android.R.drawable.sym_def_app_icon);\n        int width = mDefaultBitmap.getWidth();\n        int height = mDefaultBitmap.getHeight();\n        TextPaint mPaint = new TextPaint();\n        mPaint.setTypeface(OControlHelper.boldFont());\n        mPaint.setColor(Color.WHITE);\n        mPaint.setTextAlign(Paint.Align.CENTER);\n        mPaint.setAntiAlias(true);\n        int textSize = res.getDimensionPixelSize(R.dimen.text_size_xxlarge);\n\n        Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);\n        Canvas canvas = new Canvas();\n        Rect mBounds = new Rect();\n        canvas.setBitmap(bitmap);\n        canvas.drawColor(OStringColorUtil.getStringColor(context, content));\n        if (content != null) {\n            char[] alphabet = {Character.toUpperCase(content.charAt(0))};\n            mPaint.setTextSize(textSize);\n            mPaint.getTextBounds(alphabet, 0, 1, mBounds);\n            canvas.drawText(alphabet, 0, 1, 0 + width / 2,\n                    0 + height / 2 + (mBounds.bottom - mBounds.top) / 2, mPaint);\n        }\n        return bitmap;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/core/utils/IntentUtils.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 18/12/14 11:31 AM\n */\npackage com.odoo.core.utils;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.net.Uri;\nimport android.os.Bundle;\n\npublic class IntentUtils {\n\n    public static void openURLInBrowser(Context context, String url) {\n        if (!url.equals(\"false\") && !url.equals(\"\")) {\n            if (!url.contains(\"http\")) {\n                url = \"http://\" + url;\n            }\n            Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));\n            context.startActivity(intent);\n        }\n    }\n\n    public static void startActivity(Context context, Class<?> activity_class, Bundle data) {\n        Intent intent = new Intent(context, activity_class);\n        if (data != null)\n            intent.putExtras(data);\n        context.startActivity(intent);\n    }\n\n    public static void redirectToMap(Context context, String location) {\n        if (!location.equals(\"false\") && !location.equals(\"\")) {\n            String map = \"geo:0,0?q=\" + location;\n            Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(map));\n            context.startActivity(intent);\n        }\n    }\n\n    public static void requestMessage(Context context, String email) {\n        if (!email.equals(\"false\") && !email.equals(\"\")) {\n            Intent intent = new Intent(Intent.ACTION_SENDTO);\n            intent.setType(\"text/plain\");\n            intent.setData(Uri.parse(\"mailto:\" + email));\n            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\n            context.startActivity(intent);\n        }\n    }\n\n    public static void requestCall(Context context, String number) {\n        if (!number.equals(\"false\") && !number.equals(\"\")) {\n            Intent intent = new Intent(Intent.ACTION_CALL);\n            intent.setData(Uri.parse(\"tel:\" + number));\n            context.startActivity(intent);\n        }\n    }\n\n    public static void startContactIntent(Context context, String number) {\n        Intent intent = new Intent(Intent.ACTION_VIEW);\n        intent.setData(Uri.parse(\"tel:\" + number));\n        context.startActivity(intent);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/core/utils/JSONUtils.java",
    "content": "package com.odoo.core.utils;\n\nimport android.text.TextUtils;\n\nimport com.odoo.core.orm.ODataRow;\nimport com.odoo.core.orm.OModel;\nimport com.odoo.core.orm.fields.OColumn;\n\nimport org.json.JSONArray;\nimport org.json.JSONObject;\n\nimport java.util.ArrayList;\nimport java.util.Iterator;\nimport java.util.List;\n\n\npublic class JSONUtils {\n    public static <T> List<T> toList(JSONArray array) {\n        List<T> list = new ArrayList<T>();\n        try {\n            if (array != null) {\n                for (int i = 0; i < array.length(); i++) {\n                    list.add((T) array.get(i));\n                }\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return list;\n    }\n\n    public static <T> JSONArray toArray(List<T> list) {\n        JSONArray array = new JSONArray();\n        try {\n            for (T obj : list)\n                array.put(obj);\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return array;\n    }\n\n    public static <T> List<T> toList(String list_data) {\n        List<T> list = new ArrayList<>();\n        try {\n            list.addAll(JSONUtils.<T>toList(new JSONArray(list_data)));\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return list;\n    }\n\n    public static ODataRow toDataRow(JSONObject json) {\n        ODataRow row = new ODataRow();\n        try {\n            @SuppressWarnings(\"unchecked\")\n            Iterator<String> keys = json.keys();\n            while (keys.hasNext()) {\n                String key = keys.next();\n                row.put(key, json.get(key));\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return row;\n    }\n\n    public static JSONObject toJSONObject(ODataRow row) {\n        JSONObject json = new JSONObject();\n        try {\n            for (String key : row.keys()) {\n                json.put(key, row.get(key));\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return json;\n    }\n\n    public static JSONObject createJSONValues(OModel model, ODataRow row) {\n        JSONObject values = null;\n        try {\n            values = new JSONObject();\n            for (OColumn col : model.getColumns(false)) {\n                if (col.getName().equals(\"id\") && row.getInt(\"id\") == 0) {\n                    /* FIXME: 7.0 not supporting\n                    Response from server : column \"id\" specified more than once\n                     */\n                    continue;\n                }\n                if (col.getRelationType() == null) {\n                    if (!col.getName().equals(\"create_date\") || !col.getName().equals(\"write_date\")) {\n                        Object val = row.get(col.getName());\n                        if (val == null || val.toString().equals(\"false\")\n                                || TextUtils.isEmpty(val.toString())) {\n                            val = false;\n                        }\n                        values.put(col.getName(), val);\n                    }\n                } else {\n                    // Relation columns\n                    switch (col.getRelationType()) {\n                        case ManyToOne:\n                            if (!row.getString(col.getName()).equals(\"false\")) {\n                                ODataRow m2o = row.getM2ORecord(col.getName()).browse();\n                                if (m2o != null)\n                                    values.put(col.getName(), m2o.getInt(\"id\"));\n                            }\n                            break;\n                        case OneToMany:\n                            JSONArray o2mRecords = new JSONArray();\n                            List<ODataRow> o2mRecordList = row.getO2MRecord(\n                                    col.getName()).browseEach();\n                            if (o2mRecordList.size() > 0) {\n                                JSONArray rec_ids = new JSONArray();\n                                for (ODataRow o2mR : o2mRecordList) {\n                                    if (o2mR.getInt(\"id\") != 0)\n                                        rec_ids.put(o2mR.getInt(\"id\"));\n                                }\n                                o2mRecords.put(6);\n                                o2mRecords.put(false);\n                                o2mRecords.put(rec_ids);\n                                values.put(col.getName(),\n                                        new JSONArray().put(o2mRecords));\n                            }\n                            break;\n                        case ManyToMany:\n                            JSONArray m2mRecords = new JSONArray();\n                            List<ODataRow> m2mRecordList = row.getM2MRecord(\n                                    col.getName()).browseEach();\n                            if (!m2mRecordList.isEmpty()) {\n                                JSONArray rec_ids = new JSONArray();\n                                for (ODataRow o2mR : m2mRecordList) {\n                                    if (o2mR.getInt(\"id\") != 0)\n                                        rec_ids.put(o2mR.getInt(\"id\"));\n                                }\n                                m2mRecords.put(6);\n                                m2mRecords.put(false);\n                                m2mRecords.put(rec_ids);\n                                values.put(col.getName(),\n                                        new JSONArray().put(m2mRecords));\n                            }\n                            break;\n                    }\n                }\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return values;\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/core/utils/OActionBarUtils.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 19/12/14 2:36 PM\n */\npackage com.odoo.core.utils;\n\nimport android.support.v7.app.ActionBar;\nimport android.support.v7.app.ActionBarActivity;\nimport android.support.v7.widget.Toolbar;\n\nimport com.odoo.R;\n\npublic class OActionBarUtils {\n\n    public static void setActionBar(ActionBarActivity activity, Boolean withHomeButtonEnabled) {\n        Toolbar toolbar = (Toolbar) activity.findViewById(R.id.toolbar);\n        if (toolbar != null) {\n            activity.setSupportActionBar(toolbar);\n            ActionBar actionBar = activity.getSupportActionBar();\n            if (withHomeButtonEnabled) {\n                actionBar.setHomeButtonEnabled(true);\n                actionBar.setDisplayHomeAsUpEnabled(true);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/core/utils/OAlert.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 12/1/15 5:25 PM\n */\npackage com.odoo.core.utils;\n\nimport android.app.AlertDialog;\nimport android.content.Context;\nimport android.content.DialogInterface;\nimport android.text.TextUtils;\nimport android.util.TypedValue;\nimport android.widget.EditText;\nimport android.widget.LinearLayout;\n\nimport com.odoo.R;\n\npublic class OAlert {\n    public static final String TAG = OAlert.class.getSimpleName();\n\n    private enum Type {\n        Alert, Warning, Error\n    }\n\n    public static enum ConfirmType {\n        POSITIVE, NEGATIVE\n    }\n\n    public static void showAlert(Context context, String message) {\n        showAlert(context, message, null);\n    }\n\n    public static void showWarning(Context context, String message) {\n        showWarning(context, message, null);\n    }\n\n    public static void showError(Context context, String message) {\n        showError(context, message, null);\n    }\n\n    public static void showAlert(Context context, String message, OnAlertDismissListener listener) {\n        show(context, message, Type.Alert, listener);\n    }\n\n    public static void showWarning(Context context, String message, OnAlertDismissListener listener) {\n        show(context, message, Type.Warning, listener);\n    }\n\n    public static void showError(Context context, String message, OnAlertDismissListener listener) {\n        show(context, message, Type.Error, listener);\n    }\n\n    private static void show(Context context, String message, Type type, final OnAlertDismissListener listener) {\n        AlertDialog.Builder mBuilder;\n        mBuilder = new AlertDialog.Builder(context);\n        switch (type) {\n            case Alert:\n                mBuilder.setTitle(R.string.label_alert);\n                break;\n            case Error:\n                mBuilder.setTitle(R.string.label_error);\n                break;\n            case Warning:\n                mBuilder.setTitle(R.string.label_warning);\n        }\n        mBuilder.setMessage(message);\n        mBuilder.setPositiveButton(R.string.label_ok, new DialogInterface.OnClickListener() {\n            @Override\n            public void onClick(DialogInterface dialog, int which) {\n                dialog.dismiss();\n                if (listener != null) {\n                    listener.onAlertDismiss();\n                }\n            }\n        });\n        mBuilder.create().show();\n    }\n\n    public static void showConfirm(Context context, String message, final OnAlertConfirmListener listener) {\n        AlertDialog.Builder builder = new AlertDialog.Builder(context);\n        builder.setTitle(\"Confirm\");\n        builder.setMessage(message);\n        builder.setPositiveButton(\"OK\", new DialogInterface.OnClickListener() {\n            @Override\n            public void onClick(DialogInterface dialog, int which) {\n                if (listener != null) {\n                    listener.onConfirmChoiceSelect(ConfirmType.POSITIVE);\n                }\n            }\n        });\n        builder.setNegativeButton(\"Cancel\", new DialogInterface.OnClickListener() {\n            @Override\n            public void onClick(DialogInterface dialog, int which) {\n                if (listener != null) {\n                    listener.onConfirmChoiceSelect(ConfirmType.NEGATIVE);\n                }\n            }\n        });\n        builder.setOnCancelListener(new DialogInterface.OnCancelListener() {\n            @Override\n            public void onCancel(DialogInterface dialog) {\n                if (listener != null) {\n                    listener.onConfirmChoiceSelect(ConfirmType.NEGATIVE);\n                }\n            }\n        });\n        builder.create().show();\n    }\n\n    public static void inputDialog(Context context, String title, final OnUserInputListener listener) {\n        AlertDialog.Builder builder = new AlertDialog.Builder(context);\n        LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(\n                LinearLayout.LayoutParams.MATCH_PARENT,\n                LinearLayout.LayoutParams.WRAP_CONTENT);\n        int margin = OResource.dimen(context, R.dimen.default_8dp);\n        params.setMargins(margin, margin, margin, margin);\n        LinearLayout linearLayout = new LinearLayout(context);\n        linearLayout.setLayoutParams(params);\n        linearLayout.setPadding(margin, margin, margin, margin);\n        final EditText edtInput = new EditText(context);\n        edtInput.setLayoutParams(params);\n        edtInput.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16);\n        if (listener != null) {\n            listener.onViewCreated(edtInput);\n        }\n        linearLayout.addView(edtInput);\n        builder.setView(linearLayout);\n        if (title != null)\n            builder.setTitle(title);\n        builder.setPositiveButton(\"OK\", new DialogInterface.OnClickListener() {\n            @Override\n            public void onClick(DialogInterface dialog, int which) {\n                if (TextUtils.isEmpty(edtInput.getText())) {\n                    edtInput.setError(\"Field required\");\n                    edtInput.requestFocus();\n                } else {\n                    if (listener != null) {\n                        listener.onUserInputted(edtInput.getText());\n                    }\n                }\n            }\n        });\n        builder.setNegativeButton(\"Cancel\", null);\n        builder.create().show();\n    }\n\n    public static interface OnAlertConfirmListener {\n        public void onConfirmChoiceSelect(ConfirmType type);\n    }\n\n    public static interface OnAlertDismissListener {\n        public void onAlertDismiss();\n    }\n\n    public static interface OnUserInputListener {\n        public void onViewCreated(EditText inputView);\n\n        public void onUserInputted(Object value);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/core/utils/OAlertDialog.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 18/12/14 6:36 PM\n */\npackage com.odoo.core.utils;\n\nimport android.app.AlertDialog;\nimport android.content.Context;\n\nimport com.odoo.R;\n\npublic class OAlertDialog {\n\n    private Context mContext;\n    private String title, message;\n    private Boolean cancelable = true;\n\n    public OAlertDialog(Context context) {\n        mContext = context;\n    }\n\n    public OAlertDialog setTitle(String title) {\n        this.title = title;\n        return this;\n    }\n\n    public OAlertDialog setCancelable(Boolean cancelable) {\n        this.cancelable = cancelable;\n        return this;\n    }\n\n    public OAlertDialog setMessage(String message) {\n        this.message = message;\n        return this;\n    }\n\n    public void show() {\n        AlertDialog.Builder builder = new AlertDialog.Builder(mContext);\n        builder.setTitle(title);\n        builder.setMessage(message);\n        builder.setNegativeButton(OResource.string(mContext, R.string.label_ok), null);\n        builder.setCancelable(cancelable);\n        builder.create().show();\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/core/utils/OControls.java",
    "content": "package com.odoo.core.utils;\n\nimport android.graphics.Bitmap;\nimport android.graphics.Paint;\nimport android.view.View;\nimport android.widget.ImageView;\nimport android.widget.TextView;\n\npublic class OControls {\n\n    public static void setText(View parent_view, int textview_id, Object value) {\n        TextView textView = (TextView) parent_view.findViewById(textview_id);\n        if (value instanceof String || value instanceof CharSequence)\n            textView.setText(value.toString());\n        if (value instanceof Integer)\n            textView.setText(Integer.parseInt(value.toString()));\n    }\n\n    public static String getText(View parent_view, int textview_id) {\n        TextView textView = (TextView) parent_view.findViewById(textview_id);\n        return textView.getText().toString();\n    }\n\n    public static void toggleViewVisibility(View parent_view, int view_id,\n                                            Boolean visible) {\n        int view_visibility = (visible) ? View.VISIBLE : View.GONE;\n        parent_view.findViewById(view_id).setVisibility(view_visibility);\n\n    }\n\n    public static void setImage(View parent_view, int imageview_id,\n                                Bitmap bitmap) {\n        ImageView imgView = (ImageView) parent_view.findViewById(imageview_id);\n        imgView.setImageBitmap(bitmap);\n    }\n\n    public static void setImage(View parent_view, int imageview_id,\n                                int drawable_id) {\n        ImageView imgView = (ImageView) parent_view.findViewById(imageview_id);\n        imgView.setImageResource(drawable_id);\n    }\n\n    public static void setVisible(View parent_view, int resource_id) {\n        View view = parent_view.findViewById(resource_id);\n        view.setVisibility(View.VISIBLE);\n    }\n\n\n    public static void setInvisible(View parent_view, int resource_id) {\n        parent_view.findViewById(resource_id).setVisibility(View.INVISIBLE);\n    }\n\n    public static void setGone(View parent_view, int resource_id) {\n        View view = parent_view.findViewById(resource_id);\n        view.setVisibility(View.GONE);\n    }\n\n    public static void setTextViewStrikeThrough(View parent, int res_id) {\n        TextView tv = (TextView) parent.findViewById(res_id);\n        tv.setPaintFlags(tv.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);\n    }\n\n\n    public static void setTextColor(View parent, int txv_id, int color) {\n        TextView tv = (TextView) parent.findViewById(txv_id);\n        tv.setTextColor(color);\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/core/utils/OCursorUtils.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 1/1/15 12:39 PM\n */\npackage com.odoo.core.utils;\n\nimport android.database.Cursor;\n\nimport com.odoo.core.orm.ODataRow;\n\npublic class OCursorUtils {\n    public static final String TAG = OCursorUtils.class.getSimpleName();\n\n    public static ODataRow toDatarow(Cursor cr) {\n        ODataRow row = new ODataRow();\n        for (String col : cr.getColumnNames()) {\n            row.put(col, OCursorUtils.cursorValue(col, cr));\n        }\n        return row;\n    }\n\n    public static Object cursorValue(String column, Cursor cr) {\n        Object value = false;\n        int index = cr.getColumnIndex(column);\n        switch (cr.getType(index)) {\n            case Cursor.FIELD_TYPE_NULL:\n                value = false;\n                break;\n            case Cursor.FIELD_TYPE_STRING:\n                value = cr.getString(index);\n                break;\n            case Cursor.FIELD_TYPE_INTEGER:\n                value = cr.getInt(index);\n                break;\n            case Cursor.FIELD_TYPE_FLOAT:\n                value = cr.getFloat(index);\n                break;\n            case Cursor.FIELD_TYPE_BLOB:\n                value = cr.getBlob(index);\n                break;\n        }\n        return value;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/core/utils/ODateUtils.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 31/12/14 11:36 AM\n */\npackage com.odoo.core.utils;\n\nimport android.util.Log;\n\nimport java.text.SimpleDateFormat;\nimport java.util.Calendar;\nimport java.util.Date;\nimport java.util.GregorianCalendar;\nimport java.util.TimeZone;\nimport java.util.concurrent.TimeUnit;\n\npublic class ODateUtils {\n    public final static String TAG = ODateUtils.class.getSimpleName();\n    public static final String DEFAULT_FORMAT = \"yyyy-MM-dd HH:mm:ss\";\n    public static final String DEFAULT_DATE_FORMAT = \"yyyy-MM-dd\";\n    public static final String DEFAULT_TIME_FORMAT = \"HH:mm:ss\";\n\n\n    /**\n     * Return Current date string in \"yyyy-MM-dd HH:mm:ss\" format\n     *\n     * @return current date string (Default timezone)\n     */\n    public static String getDate() {\n        return getDate(new Date(), DEFAULT_FORMAT);\n    }\n\n    /**\n     * Returns current date string in given format\n     *\n     * @param format, date format\n     * @return current date string (Default timezone)\n     */\n    public static String getDate(String format) {\n        return getDate(new Date(), format);\n    }\n\n    /**\n     * Returns current date string in given format\n     *\n     * @param date,          date object\n     * @param defaultFormat, date format\n     * @return current date string (default timezone)\n     */\n    public static String getDate(Date date, String defaultFormat) {\n        return createDate(date, defaultFormat, false);\n    }\n\n    /**\n     * Returns UTC date string in \"yyyy-MM-dd HH:mm:ss\" format.\n     *\n     * @return string, UTC Date\n     */\n    public static String getUTCDate() {\n        return getUTCDate(new Date(), DEFAULT_FORMAT);\n    }\n\n    /**\n     * Return UTC date in given format\n     *\n     * @param format, date format\n     * @return UTC date string\n     */\n    public static String getUTCDate(String format) {\n        return getUTCDate(new Date(), format);\n    }\n\n    /**\n     * Returns UTC Date string in given date format\n     *\n     * @param date,          Date object\n     * @param defaultFormat, Date pattern format\n     * @return UTC date string\n     */\n    public static String getUTCDate(Date date, String defaultFormat) {\n        return createDate(date, defaultFormat, true);\n    }\n\n\n    /**\n     * Convert UTC date to default timezone date\n     *\n     * @param date       date in string\n     * @param dateFormat default date format\n     * @return string converted date string\n     */\n    public static String convertToDefault(String date, String dateFormat) {\n        return convertToDefault(date, dateFormat, dateFormat);\n    }\n\n    /**\n     * Convert UTC date to default timezone\n     *\n     * @param date       UTC date string\n     * @param dateFormat default date format\n     * @param toFormat   converting date format\n     * @return string converted date string\n     */\n    public static String convertToDefault(String date, String dateFormat, String toFormat) {\n        return createDate(createDateObject(date, dateFormat, false), toFormat, false);\n    }\n\n    /**\n     * Convert to UTC date\n     *\n     * @param date       date in string\n     * @param dateFormat default date format\n     * @return string date string in UTC timezone\n     */\n    public static String convertToUTC(String date, String dateFormat) {\n        return convertToUTC(date, dateFormat, dateFormat);\n    }\n\n    /**\n     * Convert default timezone date to UTC timezone\n     *\n     * @param date,      date in string\n     * @param dateFormat default date format\n     * @param toFormat   display format\n     * @return string, returns string converted to UTC\n     */\n    public static String convertToUTC(String date, String dateFormat, String toFormat) {\n        return createDate(createDateObject(date, dateFormat, true), toFormat, true);\n    }\n\n    public static String parseDate(String date, String dateFormat, String toFormat) {\n        return createDate(createDateObject(date, dateFormat, false), toFormat, true);\n    }\n\n    /**\n     * Create Date instance from given date string.\n     *\n     * @param date               date in string\n     * @param dateFormat,        original date format\n     * @param hasDefaultTimezone if date is in default timezone than true, otherwise false\n     * @return Date, returns Date object with given date\n     */\n    public static Date createDateObject(String date, String dateFormat, Boolean hasDefaultTimezone) {\n        Date dateObj = null;\n        try {\n            SimpleDateFormat simpleDateFormat = new SimpleDateFormat(dateFormat);\n            if (!hasDefaultTimezone) {\n                simpleDateFormat.setTimeZone(TimeZone.getTimeZone(\"GMT\"));\n            }\n            dateObj = simpleDateFormat.parse(date);\n        } catch (Exception e) {\n            Log.e(TAG, e.getMessage());\n        }\n        return dateObj;\n    }\n\n    /**\n     * Returns date before given days\n     *\n     * @param days days to before\n     * @return string date string before days\n     */\n    public static String getDateBefore(int days) {\n        Date today = new Date();\n        Calendar cal = new GregorianCalendar();\n        cal.setTime(today);\n        cal.add(Calendar.DAY_OF_MONTH, days * -1);\n        Date date = cal.getTime();\n        SimpleDateFormat gmtFormat = new SimpleDateFormat();\n        gmtFormat.applyPattern(\"yyyy-MM-dd 00:00:00\");\n        TimeZone gmtTime = TimeZone.getTimeZone(\"GMT\");\n        gmtFormat.setTimeZone(gmtTime);\n        return gmtFormat.format(date);\n    }\n\n    public static Date setDateTime(Date originalDate, int hour, int minute, int second) {\n        Calendar cal = new GregorianCalendar();\n        cal.setTime(originalDate);\n        cal.set(Calendar.HOUR, hour);\n        cal.set(Calendar.MINUTE, minute);\n        cal.set(Calendar.SECOND, second);\n        cal.set(Calendar.MILLISECOND, 0);\n        return cal.getTime();\n    }\n\n    public static String getDateDayBeforeAfterUTC(String utcDate, int days) {\n        Date dt = createDateObject(utcDate, DEFAULT_FORMAT, false);\n        Calendar cal = new GregorianCalendar();\n        cal.setTime(dt);\n        cal.add(Calendar.DAY_OF_MONTH, days);\n        return createDate(cal.getTime(), DEFAULT_FORMAT, true);\n    }\n\n    public static Date getDateDayBefore(Date originalDate, int days) {\n        Calendar cal = new GregorianCalendar();\n        cal.setTime(originalDate);\n        cal.add(Calendar.DAY_OF_MONTH, days * -1);\n        return cal.getTime();\n    }\n\n    public static String getCurrentDateWithHour(int addHour) {\n        Calendar cal = Calendar.getInstance();\n        int hour = cal.get(Calendar.HOUR);\n        cal.set(Calendar.HOUR, hour + addHour);\n        Date date = cal.getTime();\n        return ODateUtils.createDate(date, ODateUtils.DEFAULT_FORMAT, true);\n    }\n\n    public static Date getDateMinuteBefore(Date originalDate, int minutes) {\n        Calendar cal = new GregorianCalendar();\n        cal.setTime(originalDate);\n        cal.add(Calendar.MINUTE, minutes * -1);\n        return cal.getTime();\n    }\n\n    private static String createDate(Date date, String defaultFormat, Boolean utc) {\n        SimpleDateFormat gmtFormat = new SimpleDateFormat();\n        gmtFormat.applyPattern(defaultFormat);\n        TimeZone gmtTime = (utc) ? TimeZone.getTimeZone(\"GMT\") : TimeZone.getDefault();\n        gmtFormat.setTimeZone(gmtTime);\n        return gmtFormat.format(date);\n    }\n\n    public static String floatToDuration(String duration_in_float) {\n        duration_in_float = String.format(\"%2.2f\", Float.parseFloat(duration_in_float));\n        String[] parts = duration_in_float.split(\"\\\\.\");\n        long minute = Long.parseLong(parts[0]);\n        long seconds = (60 * Long.parseLong(parts[1])) / 100;\n        return String.format(\"%02d:%02d\", minute, seconds);\n    }\n\n    public static String durationToFloat(String duration) {\n        String[] parts = duration.split(\"\\\\:\");\n        if (parts.length == 2) {\n            long minute = Long.parseLong(parts[0]);\n            long seconds = Long.parseLong(parts[1]);\n            if (seconds == 60) {\n                minute = minute + 1;\n                seconds = 0;\n            } else {\n                seconds = (100 * seconds) / 60;\n            }\n            return String.format(\"%d.%d\", minute, seconds);\n        }\n        return \"false\";\n    }\n\n    public static String durationToFloat(long milliseconds) {\n        long minute = TimeUnit.MILLISECONDS.toMinutes(milliseconds);\n        long seconds = TimeUnit.MILLISECONDS.toSeconds(milliseconds) -\n                TimeUnit.MINUTES.toSeconds(minute);\n        if (seconds == 60) {\n            minute = minute + 1;\n            seconds = 0;\n        } else {\n            seconds = (100 * seconds) / 60;\n        }\n        return String.format(\"%d.%d\", minute, seconds);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/core/utils/OFragmentUtils.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 30/12/14 5:44 PM\n */\npackage com.odoo.core.utils;\n\nimport android.content.Context;\nimport android.os.Bundle;\nimport android.support.v4.app.Fragment;\nimport android.support.v4.app.FragmentManager;\nimport android.support.v4.app.FragmentTransaction;\nimport android.support.v7.app.ActionBarActivity;\nimport android.util.Log;\n\nimport com.odoo.R;\n\npublic class OFragmentUtils {\n    public static final String TAG = OFragmentUtils.class.getSimpleName();\n\n    private ActionBarActivity mActivity;\n    private Context mContext;\n    private Bundle savedInstance = null;\n    private FragmentManager fragmentManager;\n\n    public OFragmentUtils(ActionBarActivity activity, Bundle savedInstance) {\n        mActivity = activity;\n        mContext = activity;\n        fragmentManager = mActivity.getSupportFragmentManager();\n    }\n\n    public static OFragmentUtils get(ActionBarActivity activity, Bundle savedInstance) {\n        return new OFragmentUtils(activity, savedInstance);\n    }\n\n    public void startFragment(Fragment fragment, boolean addToBackState, Bundle extra) {\n        Bundle extra_data = fragment.getArguments();\n        if (extra_data == null)\n            extra_data = new Bundle();\n        if (extra != null)\n            extra_data.putAll(extra);\n        fragment.setArguments(extra_data);\n        loadFragment(fragment, addToBackState);\n    }\n\n    private void loadFragment(Fragment fragment, Boolean addToBackState) {\n        String tag = fragment.getClass().getCanonicalName();\n        if (fragmentManager.findFragmentByTag(tag) != null && savedInstance != null) {\n            fragmentManager.popBackStack(tag, FragmentManager.POP_BACK_STACK_INCLUSIVE);\n            fragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);\n        }\n        if (savedInstance == null) {\n            Log.i(TAG, \"Fragment Loaded (\" + tag + \")\");\n            FragmentTransaction tran = fragmentManager.beginTransaction()\n                    .replace(R.id.fragment_container, fragment, tag);\n            if (addToBackState)\n                tran.addToBackStack(tag);\n            tran.commitAllowingStateLoss();\n        }\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/core/utils/OListUtils.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 7/1/15 12:43 PM\n */\npackage com.odoo.core.utils;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class OListUtils {\n    public static final String TAG = OListUtils.class.getSimpleName();\n\n\n    public static List<String> toStringList(List<Integer> list) {\n        List<String> items = new ArrayList<>();\n        for (Integer item : list) {\n            items.add(item + \"\");\n        }\n        return items;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/core/utils/OPreferenceManager.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 31/12/14 5:39 PM\n */\npackage com.odoo.core.utils;\n\nimport android.content.Context;\nimport android.content.SharedPreferences;\n\nimport java.util.ArrayList;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Set;\n\npublic class OPreferenceManager {\n    public static final String TAG = OPreferenceManager.class.getSimpleName();\n    private SharedPreferences mPref = null;\n\n    public OPreferenceManager(Context context) {\n        mPref = android.preference.PreferenceManager\n                .getDefaultSharedPreferences(context);\n    }\n\n    public void putString(String key, String value) {\n        SharedPreferences.Editor editor = mPref.edit();\n        editor.putString(key, value);\n        editor.commit();\n    }\n\n    public boolean putStringSet(String key, List<String> values) {\n        SharedPreferences.Editor editor = mPref.edit();\n        editor.putStringSet(key, new HashSet<>(values));\n        return editor.commit();\n    }\n\n    public List<String> getStringSet(String key) {\n        List<String> list = new ArrayList<>();\n        Set<String> vals = mPref.getStringSet(key, null);\n        if (vals != null)\n            list.addAll(vals);\n        return list;\n    }\n\n    public String getString(String key, String default_value) {\n        return mPref.getString(key, default_value);\n    }\n\n    public int getInt(String key, int default_value) {\n        return Integer.parseInt(mPref.getString(key, default_value + \"\"));\n    }\n\n    public void setBoolean(String key, Boolean value) {\n        SharedPreferences.Editor editor = mPref.edit();\n        editor.putBoolean(key, value);\n        editor.commit();\n    }\n\n    public boolean getBoolean(String key, boolean defValue) {\n        return mPref.getBoolean(key, defValue);\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/core/utils/OResource.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 18/12/14 11:25 AM\n */\npackage com.odoo.core.utils;\n\nimport android.content.Context;\n\npublic class OResource {\n    public static String string(Context context, int res_id) {\n        return context.getResources().getString(res_id);\n    }\n\n    public static Integer dimen(Context context, int res_id) {\n        return (int) context.getResources().getDimension(res_id);\n    }\n\n    public static int color(Context context, int res_id) {\n        return context.getResources().getColor(res_id);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/core/utils/OStorageUtils.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 15/1/15 5:09 PM\n */\npackage com.odoo.core.utils;\n\nimport android.os.Environment;\n\nimport java.io.File;\n\npublic class OStorageUtils {\n    public static final String TAG = OStorageUtils.class.getSimpleName();\n\n    public static String getDirectoryPath(String file_type) {\n        File externalStorage = Environment.getExternalStorageDirectory();\n        String path = externalStorage.getAbsolutePath() + \"/Odoo\";\n        File baseDir = new File(path);\n        if (!baseDir.isDirectory()) {\n            baseDir.mkdir();\n        }\n        if (file_type == null) {\n            file_type = \"file\";\n        }\n        if (file_type.contains(\"image\")) {\n            path += \"/Images\";\n        } else if (file_type.contains(\"audio\")) {\n            path += \"/Audio\";\n        } else {\n            path += \"/Files\";\n        }\n        File fileDir = new File(path);\n        if (!fileDir.isDirectory()) {\n            fileDir.mkdir();\n        }\n        return path;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/core/utils/OStringColorUtil.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 15/1/15 12:55 PM\n */\npackage com.odoo.core.utils;\n\nimport android.content.Context;\nimport android.content.res.Resources;\nimport android.content.res.TypedArray;\nimport android.graphics.Color;\n\nimport com.odoo.R;\n\nimport java.util.Locale;\n\npublic class OStringColorUtil {\n    public static final String TAG = OStringColorUtil.class.getSimpleName();\n\n    public static int getStringColor(Context context, String content) {\n        Resources res = context.getResources();\n        TypedArray mColors = res.obtainTypedArray(R.array.letter_tile_colors);\n        int MAX_COLORS = mColors.length();\n        int firstCharAsc = content.toUpperCase(Locale.getDefault()).charAt(0);\n        int index = (firstCharAsc % MAX_COLORS);\n        if (index > MAX_COLORS - 1) {\n            index = index / 2;\n        }\n        int color = mColors.getColor(index, Color.WHITE);\n        mColors.recycle();\n        return color;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/core/utils/StringUtils.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 6/1/15 3:28 PM\n */\npackage com.odoo.core.utils;\n\nimport android.text.Html;\nimport android.text.Spanned;\n\npublic class StringUtils {\n    public static final String TAG = StringUtils.class.getSimpleName();\n\n    public static String repeat(String string, int repeat) {\n        StringBuffer str = new StringBuffer();\n        for (int i = 0; i < repeat; i++)\n            str.append(string);\n        return str.toString();\n    }\n\n    public static String capitalizeString(String string) {\n        char[] chars = string.toLowerCase().toCharArray();\n        boolean found = false;\n        for (int i = 0; i < chars.length; i++) {\n            if (!found && Character.isLetter(chars[i])) {\n                chars[i] = Character.toUpperCase(chars[i]);\n                found = true;\n            } else if (Character.isWhitespace(chars[i]) || chars[i] == '.'\n                    || chars[i] == '\\'') {\n                found = false;\n            }\n        }\n        return String.valueOf(chars);\n    }\n\n    /**\n     * Html to string.\n     *\n     * @param html the html\n     * @return the string\n     */\n    public static String htmlToString(String html) {\n\n        return Html.fromHtml(\n                html.replaceAll(\"\\\\<.*?\\\\>\", \"\").replaceAll(\"\\n\", \"\")\n                        .replaceAll(\"\\t\", \" \")).toString();\n    }\n\n    /**\n     * String to html.\n     *\n     * @param string the string\n     * @return the spanned\n     */\n    public static Spanned stringToHtml(String string) {\n        return Html.fromHtml(string);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/core/utils/controls/ExpandableHeightGridView.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n * \n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n * \n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n * \n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n * \n */\npackage com.odoo.core.utils.controls;\n\nimport android.content.Context;\nimport android.util.AttributeSet;\nimport android.view.ViewGroup;\nimport android.widget.GridView;\n\npublic class ExpandableHeightGridView extends GridView {\n\n\tboolean expanded = false;\n\n\tpublic ExpandableHeightGridView(Context context) {\n\t\tsuper(context);\n\t}\n\n\tpublic ExpandableHeightGridView(Context context, AttributeSet attrs) {\n\t\tsuper(context, attrs);\n\t}\n\n\tpublic ExpandableHeightGridView(Context context, AttributeSet attrs,\n\t\t\tint defStyle) {\n\t\tsuper(context, attrs, defStyle);\n\t}\n\n\tpublic boolean isExpanded() {\n\t\treturn expanded;\n\t}\n\n\t@Override\n\tpublic void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {\n\t\tif (isExpanded()) {\n\t\t\tint expandSpec = MeasureSpec.makeMeasureSpec(MEASURED_SIZE_MASK,\n\t\t\t\t\tMeasureSpec.AT_MOST);\n\t\t\tsuper.onMeasure(widthMeasureSpec, expandSpec);\n\n\t\t\tViewGroup.LayoutParams params = getLayoutParams();\n\t\t\tparams.height = getMeasuredHeight();\n\t\t} else {\n\t\t\tsuper.onMeasure(widthMeasureSpec, heightMeasureSpec);\n\t\t}\n\t}\n\n\tpublic void setExpanded(boolean expanded) {\n\t\tthis.expanded = expanded;\n\t}\n}"
  },
  {
    "path": "app/src/main/java/com/odoo/core/utils/dialog/OChoiceDialog.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 6/2/15 2:41 PM\n */\npackage com.odoo.core.utils.dialog;\n\nimport android.app.AlertDialog;\nimport android.content.Context;\nimport android.content.DialogInterface;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class OChoiceDialog implements DialogInterface.OnClickListener {\n    public static final String TAG = OChoiceDialog.class.getSimpleName();\n    private Context mContext;\n    private AlertDialog.Builder mBuilder;\n    private List<String> options = new ArrayList<>();\n    private OnChoiceSelectListener mOnChoiceSelectListener;\n    private int defaultSelected = -1;\n    private String title = null;\n\n    public OChoiceDialog(Context context) {\n        mContext = context;\n        mBuilder = new AlertDialog.Builder(mContext);\n    }\n\n    public static OChoiceDialog get(Context context) {\n        return new OChoiceDialog(context);\n    }\n\n    public OChoiceDialog withTitle(String title) {\n        this.title = title;\n        return this;\n    }\n\n    public OChoiceDialog withOptions(List<String> options, int selected) {\n        this.options = options;\n        defaultSelected = selected;\n        return this;\n    }\n\n    public void show(OnChoiceSelectListener listener) {\n        mOnChoiceSelectListener = listener;\n        if (title != null) {\n            mBuilder.setTitle(title);\n        }\n        mBuilder.setSingleChoiceItems(options.toArray(new String[options.size()]), defaultSelected, this);\n        mBuilder.show();\n    }\n\n    @Override\n    public void onClick(DialogInterface dialog, int which) {\n        if (mOnChoiceSelectListener != null) {\n            mOnChoiceSelectListener.choiceSelected(which, options.get(which));\n        }\n        dialog.dismiss();\n    }\n\n    public interface OnChoiceSelectListener {\n        public void choiceSelected(int position, String value);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/core/utils/drawer/DrawerUtils.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 30/12/14 4:27 PM\n */\npackage com.odoo.core.utils.drawer;\n\nimport android.content.Context;\nimport android.graphics.Typeface;\nimport android.view.View;\nimport android.widget.ImageView;\nimport android.widget.LinearLayout;\nimport android.widget.TextView;\n\nimport com.odoo.SettingsActivity;\nimport com.odoo.config.Addons;\nimport com.odoo.core.account.Profile;\nimport com.odoo.core.support.OUser;\nimport com.odoo.core.support.addons.OAddon;\nimport com.odoo.core.support.addons.fragment.IBaseFragment;\nimport com.odoo.core.support.drawer.ODrawerItem;\nimport com.odoo.core.utils.OControls;\nimport com.odoo.core.utils.OPreferenceManager;\nimport com.odoo.core.utils.OResource;\nimport com.odoo.R;\nimport com.odoo.news.News;\nimport com.odoo.news.models.OdooNews;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport odoo.zxing.handler.OdooMobileQRReader;\n\npublic class DrawerUtils {\n\n    public static List<ODrawerItem> getDrawerItems(Context context) {\n        List<ODrawerItem> items = new ArrayList<>();\n        for (OAddon addon : new Addons().getAddons()) {\n            IBaseFragment frag = (IBaseFragment) addon.get();\n            if (frag != null) {\n                List<ODrawerItem> menus = frag.drawerMenus(context);\n                if (menus != null) {\n                    items.addAll(menus);\n                }\n            }\n        }\n        items.addAll(DrawerUtils.baseSettingsItems(context));\n        return items;\n    }\n\n    public static List<ODrawerItem> baseSettingsItems(Context context) {\n        String key = \"base.settings\";\n        OPreferenceManager pref = new OPreferenceManager(context);\n        List<ODrawerItem> settings = new ArrayList<>();\n        settings.add(new ODrawerItem(key).setTitle(OResource.string(context, R.string.label_settings))\n                .setGroupTitle());\n        settings.add(new ODrawerItem(key).setTitle(OResource.string(context, R.string.title_profile))\n                .setInstance(Profile.class).setIcon(R.drawable.ic_action_user));\n        settings.add(new ODrawerItem(key).setTitle(OResource.string(context, R.string.label_settings))\n                .setIcon(R.drawable.ic_action_settings)\n                .setInstance(SettingsActivity.class));\n        if (pref.getBoolean(Profile.CONNECT_WITH_ODOO, false))\n            settings.add(new ODrawerItem(key).setTitle(OResource.string(context, R.string.label_access_odoo_mobile))\n                    .setInstance(OdooMobileQRReader.class).setIcon(R.drawable.ic_action_qrcode)\n                    .setExtra(OUser.current(context).getAsBundle()));\n        OdooNews news = new OdooNews(context, null);\n        if (!news.isEmptyTable()) {\n            settings.add(new ODrawerItem(key).setTitle(\"Odoo News\")\n                            .setInstance(new News()).setIcon(R.drawable.ic_odoo_o)\n            );\n        }\n        return settings;\n    }\n\n    public static View fillDrawerItemValue(View view, ODrawerItem item) {\n        if (item.isGroupTitle()) {\n            OControls.setText(view, R.id.group_title, item.getTitle());\n        } else {\n            if (item.getIcon() > 0)\n                OControls.setImage(view, R.id.icon, item.getIcon());\n            else\n                view.findViewById(R.id.icon).setVisibility(View.GONE);\n            OControls.setText(view, R.id.title, item.getTitle());\n            if (item.getCounter() > 0) {\n                OControls.setText(view, R.id.counter, item.getCounter() + \"\");\n            }\n        }\n        return view;\n    }\n\n    public static IBaseFragment getDefaultDrawerFragment() {\n        OAddon addon = new Addons().getDefaultAddon();\n        if (addon != null) {\n            return (IBaseFragment) addon.get();\n        }\n        return null;\n    }\n\n    public static ODrawerItem getStartableObject(Context context, IBaseFragment fragment) {\n        List<ODrawerItem> items = fragment.drawerMenus(context);\n        if (items != null) {\n            for (ODrawerItem item : items) {\n                if (!item.isGroupTitle() && item.getInstance() != null) {\n                    return item;\n                }\n            }\n        }\n        return null;\n    }\n\n    public static void focusOnView(Context context, View view, boolean focused) {\n        ODrawerItem item = (ODrawerItem) view.getTag();\n        if (!item.isGroupTitle()) {\n            ImageView icon = (ImageView) view.findViewById(R.id.icon);\n            TextView title = (TextView) view.findViewById(R.id.title);\n            TextView counter = (TextView) view.findViewById(R.id.counter);\n            if (focused) {\n                icon.setColorFilter(context.getResources().getColor(R.color.drawer_icon_tint_selected));\n                title.setTextColor(context.getResources().getColor(R.color.drawer_text_color_selected));\n                title.setTypeface(title.getTypeface(), Typeface.BOLD);\n                counter.setTextColor(context.getResources().getColor(R.color.drawer_text_color_selected));\n                counter.setTypeface(title.getTypeface(), Typeface.BOLD);\n            } else {\n                icon.setColorFilter(context.getResources().getColor(R.color.drawer_icon_tint));\n                title.setTextColor(context.getResources().getColor(R.color.drawer_text_color));\n                title.setTypeface(null, Typeface.NORMAL);\n                counter.setTextColor(context.getResources().getColor(R.color.drawer_text_color));\n                counter.setTypeface(null, Typeface.NORMAL);\n            }\n        }\n    }\n\n    public static Integer findItemIndex(ODrawerItem item, LinearLayout itemContainer) {\n        for (int i = 0; i < itemContainer.getChildCount(); i++) {\n            ODrawerItem dItem = (ODrawerItem) itemContainer.getChildAt(i).getTag();\n            if (dItem != null && dItem.getKey().equals(item.getKey())) {\n                return i;\n            }\n        }\n        return -1;\n\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/core/utils/drawer/ODrawerScrollView.java",
    "content": "package com.odoo.core.utils.drawer;\n\nimport android.content.Context;\nimport android.content.res.TypedArray;\nimport android.graphics.Canvas;\nimport android.graphics.Rect;\nimport android.graphics.drawable.Drawable;\nimport android.support.v4.view.ViewCompat;\nimport android.util.AttributeSet;\nimport android.widget.ScrollView;\n\nimport com.odoo.R;\n\npublic class ODrawerScrollView extends ScrollView {\n    private Drawable mInsetForeground;\n\n    private Rect mInsets;\n    private Rect mTempRect = new Rect();\n    private OnInsetsCallback mOnInsetsCallback;\n\n    public ODrawerScrollView(Context context) {\n        super(context);\n        init(context, null, 0);\n    }\n\n    public ODrawerScrollView(Context context, AttributeSet attrs) {\n        super(context, attrs);\n        init(context, attrs, 0);\n    }\n\n    public ODrawerScrollView(Context context, AttributeSet attrs, int defStyle) {\n        super(context, attrs, defStyle);\n        init(context, attrs, defStyle);\n    }\n\n    private void init(Context context, AttributeSet attrs, int defStyle) {\n        final TypedArray a = context.obtainStyledAttributes(attrs,\n                R.styleable.ODrawerScrollView, defStyle, 0);\n        if (a == null) {\n            return;\n        }\n        mInsetForeground = a\n                .getDrawable(R.styleable.ODrawerScrollView_insetForeground);\n        a.recycle();\n\n        setWillNotDraw(true);\n    }\n\n    @Override\n    protected boolean fitSystemWindows(Rect insets) {\n        mInsets = new Rect(insets);\n        setWillNotDraw(mInsetForeground == null);\n        ViewCompat.postInvalidateOnAnimation(this);\n        if (mOnInsetsCallback != null) {\n            mOnInsetsCallback.onInsetsChanged(insets);\n        }\n        return true; // consume insets\n    }\n\n    @Override\n    public void draw(Canvas canvas) {\n        super.draw(canvas);\n\n        int width = getWidth();\n        int height = getHeight();\n        if (mInsets != null && mInsetForeground != null) {\n            int sc = canvas.save();\n            canvas.translate(getScrollX(), getScrollY());\n\n            // Top\n            mTempRect.set(0, 0, width, mInsets.top);\n            mInsetForeground.setBounds(mTempRect);\n            mInsetForeground.draw(canvas);\n\n            // Bottom\n            mTempRect.set(0, height - mInsets.bottom, width, height);\n            mInsetForeground.setBounds(mTempRect);\n            mInsetForeground.draw(canvas);\n\n            // Left\n            mTempRect\n                    .set(0, mInsets.top, mInsets.left, height - mInsets.bottom);\n            mInsetForeground.setBounds(mTempRect);\n            mInsetForeground.draw(canvas);\n\n            // Right\n            mTempRect.set(width - mInsets.right, mInsets.top, width, height\n                    - mInsets.bottom);\n            mInsetForeground.setBounds(mTempRect);\n            mInsetForeground.draw(canvas);\n\n            canvas.restoreToCount(sc);\n        }\n    }\n\n    @Override\n    protected void onAttachedToWindow() {\n        super.onAttachedToWindow();\n        if (mInsetForeground != null) {\n            mInsetForeground.setCallback(this);\n        }\n    }\n\n    @Override\n    protected void onDetachedFromWindow() {\n        super.onDetachedFromWindow();\n        if (mInsetForeground != null) {\n            mInsetForeground.setCallback(null);\n        }\n    }\n\n    /**\n     * Allows the calling container to specify a callback for custom processing\n     * when insets change (i.e. when {@link #fitSystemWindows(android.graphics.Rect)} is called.\n     * This is useful for setting padding on UI elements based on UI chrome\n     * insets (e.g. a Google Map or a ListView). When using with ListView or\n     * GridView, remember to set clipToPadding to false.\n     */\n    public void setOnInsetsCallback(OnInsetsCallback onInsetsCallback) {\n        mOnInsetsCallback = onInsetsCallback;\n    }\n\n    public static interface OnInsetsCallback {\n        public void onInsetsChanged(Rect insets);\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/odoo/core/utils/logger/OLog.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n * \n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n * \n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n * \n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n * \n */\npackage com.odoo.core.utils.logger;\n\nimport android.text.TextUtils;\nimport android.util.Log;\n\npublic class OLog {\n\n\tpublic static void log(String... messages) {\n\t\tString message = TextUtils.join(\", \", messages);\n\t\tfinal Throwable throwable = new Throwable();\n\t\tfinal StackTraceElement[] elements = throwable.getStackTrace();\n\t\tfinal String callerClassName = elements[1].getClassName();\n\t\tfinal String callerMethodName = elements[1].getMethodName();\n\t\tLog.e(callerClassName + \"[\" + callerMethodName + \"] \", message);\n\t}\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/core/utils/notification/ONotificationBuilder.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 9/1/15 6:51 PM\n */\npackage com.odoo.core.utils.notification;\n\nimport android.app.Notification;\nimport android.app.NotificationManager;\nimport android.app.PendingIntent;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.graphics.Bitmap;\nimport android.graphics.BitmapFactory;\nimport android.graphics.Canvas;\nimport android.net.Uri;\nimport android.os.Bundle;\nimport android.support.v4.app.NotificationCompat;\nimport android.support.v4.app.NotificationCompat.Builder;\n\nimport com.odoo.R;\nimport com.odoo.core.account.BaseSettings;\nimport com.odoo.core.utils.OPreferenceManager;\nimport com.odoo.core.utils.OResource;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n\npublic class ONotificationBuilder {\n    public static final String TAG = ONotificationBuilder.class.getSimpleName();\n    private Context mContext;\n    private Builder mNotificationBuilder = null;\n    private PendingIntent mNotificationResultIntent = null;\n    private NotificationManager mNotificationManager = null;\n    private String title, text, bigText;\n    private boolean mOnGoing = false, mAutoCancel = true;\n    private Intent resultIntent = null;\n    private int icon = R.drawable.ic_odoo_o_white;\n    private int small_icon = R.drawable.ic_odoo_o_white;\n    private List<NotificationAction> mActions = new ArrayList<ONotificationBuilder.NotificationAction>();\n    private int notification_id = 0;\n    private Boolean withVibrate = true;\n    private Boolean withLargeIcon = true;\n    private Boolean withRingTone = true;\n    private int notification_color = R.color.theme_secondary;\n    private OPreferenceManager mPref;\n    private int maxProgress = -1;\n    private int currentProgress = -1;\n    private boolean indeterminate = false;\n    private Bitmap bigPictureStyle = null;\n\n    public ONotificationBuilder(Context context, int notification_id) {\n        mContext = context;\n        mPref = new OPreferenceManager(mContext);\n        this.notification_id = notification_id;\n    }\n\n    public ONotificationBuilder setTitle(String title) {\n        this.title = title;\n        return this;\n    }\n\n    public ONotificationBuilder setText(String text) {\n        this.text = text;\n        return this;\n    }\n\n    public ONotificationBuilder setIcon(int res_id) {\n        icon = res_id;\n        return this;\n    }\n\n    public ONotificationBuilder withLargeIcon(boolean largeIcon) {\n        withLargeIcon = largeIcon;\n        return this;\n    }\n\n    public boolean withLargeIcon() {\n        return withLargeIcon;\n    }\n\n    public ONotificationBuilder withRingTone(Boolean ringTone) {\n        withRingTone = ringTone;\n        return this;\n    }\n\n    public boolean withRingTone() {\n        return withRingTone;\n    }\n\n    public ONotificationBuilder setBigPicture(Bitmap bitmap) {\n        bigPictureStyle = bitmap;\n        return this;\n    }\n\n    public ONotificationBuilder setBigText(String bigText) {\n        this.bigText = bigText;\n        return this;\n    }\n\n    public ONotificationBuilder setOngoing(boolean onGoing) {\n        mOnGoing = onGoing;\n        return this;\n    }\n\n    public ONotificationBuilder setAutoCancel(boolean autoCancel) {\n        mAutoCancel = autoCancel;\n        return this;\n    }\n\n    public ONotificationBuilder addAction(NotificationAction action) {\n        mActions.add(action);\n        return this;\n    }\n\n    public ONotificationBuilder allowVibrate(Boolean vibrate) {\n        withVibrate = vibrate;\n        return this;\n    }\n\n    public ONotificationBuilder setColor(int res_id) {\n        notification_color = res_id;\n        return this;\n    }\n\n    public ONotificationBuilder setProgress(int max, int progress, boolean indeterminate) {\n        maxProgress = max;\n        currentProgress = progress;\n        this.indeterminate = indeterminate;\n        return this;\n    }\n\n    private void init() {\n        mNotificationManager = (NotificationManager) mContext\n                .getSystemService(Context.NOTIFICATION_SERVICE);\n        mNotificationBuilder = new NotificationCompat.Builder(mContext);\n        mNotificationBuilder.setContentTitle(title);\n        mNotificationBuilder.setContentText(text);\n        if (bigText == null)\n            mNotificationBuilder.setContentInfo(text);\n        if (withLargeIcon()) {\n            mNotificationBuilder.setSmallIcon(small_icon);\n            Bitmap icon = BitmapFactory.decodeResource(mContext.getResources(), this.icon);\n            Bitmap newIcon = Bitmap.createBitmap(icon.getWidth(), icon.getHeight(), icon.getConfig());\n            Canvas canvas = new Canvas(newIcon);\n            canvas.drawColor(OResource.color(mContext, R.color.theme_primary));\n            canvas.drawBitmap(icon, 0, 0, null);\n            mNotificationBuilder.setLargeIcon(newIcon);\n        } else {\n            mNotificationBuilder.setSmallIcon(icon);\n        }\n        mNotificationBuilder.setAutoCancel(mAutoCancel);\n        mNotificationBuilder.setOngoing(mOnGoing);\n        mNotificationBuilder.setColor(OResource.color(mContext, notification_color));\n        if (bigText != null) {\n            NotificationCompat.BigTextStyle notiStyle = new NotificationCompat.BigTextStyle();\n            notiStyle.setBigContentTitle(title);\n            notiStyle.setSummaryText(text);\n            notiStyle.bigText(bigText);\n            mNotificationBuilder.setStyle(notiStyle);\n        }\n        if (bigPictureStyle != null) {\n            mNotificationBuilder.setStyle(new NotificationCompat.BigPictureStyle()\n                    .bigPicture(bigPictureStyle));\n        }\n\n        if (maxProgress != -1) {\n            mNotificationBuilder.setProgress(maxProgress, currentProgress, indeterminate);\n        }\n    }\n\n    private void setSoundForNotification() {\n        Uri uri = BaseSettings.getNotificationRingTone(mContext);\n        mNotificationBuilder.setSound(uri);\n    }\n\n    private void setVibrateForNotification() {\n        mNotificationBuilder.setVibrate(new long[]{1000, 1000, 1000, 1000,\n                1000});\n    }\n\n    public ONotificationBuilder setResultIntent(Intent intent) {\n        resultIntent = intent;\n        return this;\n    }\n\n    public ONotificationBuilder build() {\n        init();\n        if (withVibrate) {\n            setVibrateForNotification();\n        }\n        if (withRingTone())\n            setSoundForNotification();\n        if (resultIntent != null) {\n            _setResultIntent();\n        }\n        if (mActions.size() > 0) {\n            _addActions();\n        }\n        return this;\n    }\n\n    private void _addActions() {\n        for (NotificationAction action : mActions) {\n            Intent intent = new Intent(mContext, action.getIntent());\n            intent.setAction(action.getAction());\n            intent.putExtras(action.getExtras());\n            PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0, intent,\n                    PendingIntent.FLAG_UPDATE_CURRENT);\n            mNotificationBuilder.addAction(action.getIcon(),\n                    action.getTitle(), pendingIntent);\n        }\n    }\n\n    private void _setResultIntent() {\n        mNotificationResultIntent = PendingIntent.getActivity(mContext, 0,\n                resultIntent, PendingIntent.FLAG_UPDATE_CURRENT);\n        mNotificationBuilder.setDefaults(Notification.DEFAULT_ALL);\n        if (mPref.getBoolean(\"hands_up_notification\", true)) {\n            mNotificationBuilder.setFullScreenIntent(mNotificationResultIntent, true);\n        } else {\n            mNotificationBuilder.setContentIntent(mNotificationResultIntent);\n        }\n    }\n\n    public void show() {\n        if (mNotificationBuilder == null) {\n            build();\n        }\n        mNotificationManager.notify(notification_id, mNotificationBuilder.build());\n    }\n\n    public static void cancelNotification(Context context, int id) {\n        NotificationManager nMgr = (NotificationManager) context.getSystemService(\n                Context.NOTIFICATION_SERVICE\n        );\n        nMgr.cancel(id);\n    }\n\n\n    public static class NotificationAction {\n        private int icon;\n        private int requestCode;\n        private String title;\n        private String action;\n        private Bundle extras;\n        private Class<?> intent;\n\n        public NotificationAction(int icon, String title, int requestCode,\n                                  String action, Class<?> intent, Bundle extras) {\n            super();\n            this.icon = icon;\n            this.title = title;\n            this.requestCode = requestCode;\n            this.action = action;\n            this.intent = intent;\n            this.extras = extras;\n        }\n\n        public Class<?> getIntent() {\n            return intent;\n        }\n\n        public void setIntent(Class<?> intent) {\n            this.intent = intent;\n        }\n\n        public int getIcon() {\n            return icon;\n        }\n\n        public void setIcon(int icon) {\n            this.icon = icon;\n        }\n\n        public int getRequestCode() {\n            return requestCode;\n        }\n\n        public void setRequestCode(int requestCode) {\n            this.requestCode = requestCode;\n        }\n\n        public String getTitle() {\n            return title;\n        }\n\n        public void setTitle(String title) {\n            this.title = title;\n        }\n\n        public String getAction() {\n            return action;\n        }\n\n        public void setAction(String action) {\n            this.action = action;\n        }\n\n        public Bundle getExtras() {\n            return extras;\n        }\n\n        public void setExtras(Bundle extras) {\n            this.extras = extras;\n        }\n\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/core/utils/reminder/ReminderActionReceiver.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 9/1/15 6:15 PM\n */\npackage com.odoo.core.utils.reminder;\n\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\n\npublic class ReminderActionReceiver extends BroadcastReceiver {\n    public static final String TAG = ReminderActionReceiver.class.getSimpleName();\n\n    @Override\n    public void onReceive(Context context, Intent intent) {\n\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/core/utils/reminder/ReminderReceiver.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 9/1/15 6:15 PM\n */\npackage com.odoo.core.utils.reminder;\n\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.os.Bundle;\n\nimport com.odoo.addons.calendar.EventDetail;\nimport com.odoo.addons.calendar.models.CalendarEvent;\nimport com.odoo.addons.crm.CRMDetail;\nimport com.odoo.addons.crm.models.CRMLead;\nimport com.odoo.addons.phonecall.PhoneCallDetail;\nimport com.odoo.addons.phonecall.models.CRMPhoneCalls;\nimport com.odoo.base.addons.res.ResCurrency;\nimport com.odoo.base.addons.res.ResPartner;\nimport com.odoo.core.orm.ODataRow;\nimport com.odoo.core.orm.fields.OColumn;\nimport com.odoo.core.utils.OResource;\nimport com.odoo.core.utils.notification.ONotificationBuilder;\nimport com.odoo.R;\n\npublic class ReminderReceiver extends BroadcastReceiver {\n    public static final String TAG = ReminderReceiver.class.getSimpleName();\n    public static final int REQUEST_EVENT_REMINDER = 12345;\n    public static final int REQUEST_PHONE_CALL_REMINDER = 12346;\n    public static final String ACTION_EVENT_REMINDER_DONE = \"action_event_reminder_done\";\n    public static final String ACTION_EVENT_REMINDER_RE_SCHEDULE = \"action_event_reminder_re_schedule\";\n    public static final String ACTION_PHONE_CALL_REMINDER_CALLBACK = \"action_phone_call_reminder_callback\";\n    public static final String ACTION_PHONE_CALL_REMINDER_DONE = \"action_phone_call_reminder_done\";\n    public static final String ACTION_PHONE_CALL_REMINDER_RE_SCHEDULE = \"action_phone_call_reminder_re_schedule\";\n\n    @Override\n    public void onReceive(Context context, Intent intent) {\n        String type = intent.getStringExtra(ReminderUtils.KEY_REMINDER_TYPE);\n        showNotification(context, type, intent.getExtras());\n    }\n\n    private void showNotification(Context context, String type, Bundle data) {\n        ONotificationBuilder builder = new ONotificationBuilder(context, data.getInt(OColumn.ROW_ID));\n        Class<?> resultClass = null;\n        int icon = R.drawable.ic_action_event;\n        ODataRow record = null;\n        data.putString(\"type\", type);\n        if (type.equals(\"event\")) {\n            resultClass = EventDetail.class;\n            CalendarEvent event = new CalendarEvent(context, null);\n            int row_id = data.getInt(OColumn.ROW_ID);\n            record = event.browse(new String[]{\"name\", \"description\", \"location\"}, row_id);\n            if (record != null) {\n                if (record.getString(\"description\").equals(\"false\")) {\n                    record.put(\"description\", record.getString(\"name\"));\n                }\n            }\n            ONotificationBuilder.NotificationAction actionDone =\n                    new ONotificationBuilder.NotificationAction(\n                            R.drawable.ic_action_action_done_all,\n                            OResource.string(context, R.string.label_mark_done),\n                            REQUEST_EVENT_REMINDER,\n                            ACTION_EVENT_REMINDER_DONE,\n                            EventDetail.class,\n                            data\n                    );\n            builder.addAction(actionDone);\n            Bundle reScheduleData = data;\n            reScheduleData.putBoolean(EventDetail.KEY_RESCHEDULE, true);\n            ONotificationBuilder.NotificationAction actionReSchedule =\n                    new ONotificationBuilder.NotificationAction(\n                            R.drawable.ic_action_time_clock,\n                            OResource.string(context, R.string.label_re_schedule),\n                            REQUEST_EVENT_REMINDER,\n                            ACTION_EVENT_REMINDER_RE_SCHEDULE,\n                            EventDetail.class,\n                            reScheduleData\n                    );\n            builder.addAction(actionReSchedule);\n\n        }\n        if (type.equals(\"phonecall\")) {\n            icon = R.drawable.ic_action_call_logs;\n            resultClass = PhoneCallDetail.class;\n            CRMPhoneCalls phoneCalls = new CRMPhoneCalls(context, null);\n            int row_id = data.getInt(OColumn.ROW_ID);\n            record = phoneCalls.browse(new String[]{\"name\", \"description\", \"partner_id\"}, row_id);\n            if (record != null) {\n                if (record.getString(\"description\").equals(\"false\")) {\n                    record.put(\"description\", record.getString(\"name\"));\n                }\n                ResPartner partner = new ResPartner(context, null);\n                data.putString(\"contact\", partner.getContact(context, record.getInt(\"partner_id\")));\n            }\n            ONotificationBuilder.NotificationAction actionCallBack =\n                    new ONotificationBuilder.NotificationAction(\n                            R.drawable.ic_action_phone,\n                            \"Call back\",\n                            REQUEST_PHONE_CALL_REMINDER,\n                            ACTION_PHONE_CALL_REMINDER_CALLBACK,\n                            PhoneCallDetail.class,\n                            data\n                    );\n            builder.addAction(actionCallBack);\n            ONotificationBuilder.NotificationAction actionDone =\n                    new ONotificationBuilder.NotificationAction(\n                            R.drawable.ic_action_action_done_all,\n                            OResource.string(context, R.string.label_mark_done),\n                            REQUEST_PHONE_CALL_REMINDER,\n                            ACTION_PHONE_CALL_REMINDER_DONE,\n                            PhoneCallDetail.class,\n                            data\n                    );\n            builder.addAction(actionDone);\n            ONotificationBuilder.NotificationAction actionReSchedule =\n                    new ONotificationBuilder.NotificationAction(\n                            R.drawable.ic_action_time_clock,\n                            OResource.string(context, R.string.label_re_schedule),\n                            REQUEST_PHONE_CALL_REMINDER,\n                            ACTION_PHONE_CALL_REMINDER_RE_SCHEDULE,\n                            PhoneCallDetail.class,\n                            data\n                    );\n            builder.addAction(actionReSchedule);\n\n        }\n        if (type.equals(\"opportunity\")) {\n            boolean reminderOnExpiryDate = data.getBoolean(\"expiry_date\");\n            icon = R.drawable.ic_action_opportunities;\n            resultClass = CRMDetail.class;\n            CRMLead lead = new CRMLead(context, null);\n            int row_id = data.getInt(OColumn.ROW_ID);\n            record = lead.browse(row_id);\n            String desc = record.getString(\"planned_revenue\") + \" \"\n                    + ResCurrency.getSymbol(context, record.getInt(\"company_currency\")) +\n                    \" at \" + record.getString(\"probability\") + \" %\";\n            if (!record.getString(\"title_action\").equals(\"false\")) {\n                desc += \"\\n\" + record.getString(\"title_action\");\n            }\n            record.put(\"description\", desc);\n            //FIXME: Add reminder actions\n        }\n        if (record != null) {\n            builder.setAutoCancel(true);\n            builder.setIcon(icon);\n            builder.setTitle(record.getString(\"name\"));\n            builder.setBigText(record.getString(\"description\"));\n\n            Intent resultIntent = new Intent(context, resultClass);\n            resultIntent.putExtras(data);\n            builder.setResultIntent(resultIntent);\n            builder.build().show();\n        }\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/core/utils/reminder/ReminderUtils.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 9/1/15 6:12 PM\n */\npackage com.odoo.core.utils.reminder;\n\nimport android.app.AlarmManager;\nimport android.app.PendingIntent;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.os.Bundle;\n\nimport com.odoo.core.orm.fields.OColumn;\n\nimport java.util.Calendar;\nimport java.util.Date;\n\npublic class ReminderUtils {\n    public static final String TAG = ReminderUtils.class.getSimpleName();\n    public static final String KEY_REMINDER_TYPE = \"key_reminder_type\";\n    private Context mContext;\n\n    public ReminderUtils(Context context) {\n        mContext = context;\n    }\n\n    public static ReminderUtils get(Context context) {\n        return new ReminderUtils(context);\n    }\n\n    public boolean setReminder(Date date, Bundle extra) {\n        Calendar cal = Calendar.getInstance();\n        cal.setTime(date);\n        cal.set(Calendar.SECOND, 0);\n        Intent myIntent = new Intent(mContext, ReminderReceiver.class);\n        myIntent.putExtras(extra);\n        int row_id = extra.getInt(OColumn.ROW_ID);\n        AlarmManager alarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);\n        PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, row_id, myIntent, 0);\n        alarmManager.set(AlarmManager.RTC_WAKEUP, cal.getTime().getTime(), pendingIntent);\n        return true;\n    }\n\n    public boolean resetReminder(Date date, Bundle extra) {\n        if (cancelReminder(date, extra)) {\n            setReminder(date, extra);\n        }\n        return true;\n    }\n\n    public boolean cancelReminder(Date date, Bundle extra) {\n        Intent myIntent = new Intent(mContext, ReminderReceiver.class);\n        myIntent.putExtras(extra);\n        int row_id = extra.getInt(OColumn.ROW_ID);\n        AlarmManager alarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);\n        PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, row_id, myIntent,\n                PendingIntent.FLAG_CANCEL_CURRENT);\n        alarmManager.cancel(pendingIntent);\n        return true;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/core/utils/sys/IOnActivityResultListener.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 19/12/14 1:00 PM\n */\npackage com.odoo.core.utils.sys;\n\nimport android.content.Intent;\n\npublic interface IOnActivityResultListener {\n    public void onOdooActivityResult(int requestCode, int resultCode, Intent data);\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/core/utils/sys/IOnBackPressListener.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 19/12/14 11:24 AM\n */\npackage com.odoo.core.utils.sys;\n\npublic interface IOnBackPressListener {\n    public boolean onBackPressed();\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/core/utils/sys/OCacheUtils.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 10/2/15 11:39 AM\n */\npackage com.odoo.core.utils.sys;\n\nimport android.content.Context;\n\nimport java.io.File;\n\npublic class OCacheUtils {\n    public static final String TAG = OCacheUtils.class.getSimpleName();\n\n    public static void clearSystemCache(Context context) {\n        try {\n            File dir = context.getCacheDir();\n            if (dir != null && dir.isDirectory()) {\n                deleteDir(dir);\n            }\n        } catch (Exception e) {\n        }\n    }\n\n    public static boolean deleteDir(File dir) {\n        if (dir != null && dir.isDirectory()) {\n            String[] children = dir.list();\n            for (int i = 0; i < children.length; i++) {\n                boolean success = deleteDir(new File(dir, children[i]));\n                if (!success) {\n                    return false;\n                }\n            }\n        }\n        return dir.delete();\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/datas/OConstants.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 18/12/14 11:28 AM\n */\npackage com.odoo.datas;\n\npublic class OConstants {\n    public static final String URL_ODOO = \"https://www.odoo.com\";\n    public static final String URL_ODOO_RESET_PASSWORD = URL_ODOO + \"/web/reset_password\";\n    public static final String URL_ODOO_SIGN_UP = URL_ODOO + \"/web/signup\";\n    public static final String URL_ODOO_ACCOUNTS = \"https://accounts.odoo.com\";\n    public static final String URL_ODOO_MOBILE_GIT_HUB = \"https://github.com/Odoo-mobile\";\n    public static final String URL_ODOO_APPS_ON_PLAY_STORE = \"https://play.google.com/store/apps/developer?id=Odoo+SA\";\n\n    public static final String ODOO_COMPANY_NAME = \"Odoo\";\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/news/News.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 13/3/15 3:35 PM\n */\npackage com.odoo.news;\n\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.IntentFilter;\nimport android.database.Cursor;\nimport android.os.Bundle;\nimport android.support.annotation.Nullable;\nimport android.support.v4.app.LoaderManager;\nimport android.support.v4.content.CursorLoader;\nimport android.support.v4.content.Loader;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.AdapterView;\nimport android.widget.ListView;\n\nimport com.odoo.R;\nimport com.odoo.core.orm.ODataRow;\nimport com.odoo.core.orm.fields.OColumn;\nimport com.odoo.core.support.addons.fragment.BaseFragment;\nimport com.odoo.core.support.drawer.ODrawerItem;\nimport com.odoo.core.support.list.OCursorListAdapter;\nimport com.odoo.core.utils.OControls;\nimport com.odoo.core.utils.OCursorUtils;\nimport com.odoo.core.utils.StringUtils;\nimport com.odoo.news.models.OdooNews;\n\nimport java.util.List;\n\nimport odoo.Odoo;\n\npublic class News extends BaseFragment implements OCursorListAdapter.\n        OnViewBindListener, LoaderManager.LoaderCallbacks<Cursor>, AdapterView.OnItemClickListener {\n    public static final String TAG = News.class.getSimpleName();\n    private OdooNews news = null;\n    private View mView = null;\n    private ListView mList = null;\n    private OCursorListAdapter mAdapter = null;\n    private DataRefreshReceiver dataRefreshReceiver = null;\n\n    @Override\n    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {\n        news = new OdooNews(getActivity(), null);\n        return inflater.inflate(R.layout.news_list, container, false);\n    }\n\n    @Override\n    public List<ODrawerItem> drawerMenus(Context context) {\n        return null;\n    }\n\n    @Override\n    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {\n        super.onViewCreated(view, savedInstanceState);\n        mView = view;\n        dataRefreshReceiver = new DataRefreshReceiver();\n        initAdapter();\n    }\n\n    private void initAdapter() {\n        mList = (ListView) mView.findViewById(R.id.newsList);\n        mAdapter = new OCursorListAdapter(getActivity(), null, R.layout.odoo_news);\n        mAdapter.setOnViewBindListener(this);\n        mList.setAdapter(mAdapter);\n        mList.setOnItemClickListener(this);\n        getLoaderManager().initLoader(0, null, this);\n    }\n\n    @Override\n    public Class<OdooNews> database() {\n        return OdooNews.class;\n    }\n\n\n    @Override\n    public void onViewBind(View view, Cursor cursor, ODataRow row) {\n        OControls.setText(view, R.id.subject, row.getString(\"subject\"));\n        OControls.setText(view, R.id.message, StringUtils.htmlToString(row.getString(\"message\")));\n    }\n\n    @Override\n    public Loader<Cursor> onCreateLoader(int id, Bundle args) {\n        return new CursorLoader(getActivity(), db().uri(), null, null, null, OColumn.ROW_ID + \" desc\");\n    }\n\n    @Override\n    public void onLoadFinished(Loader<Cursor> loader, Cursor data) {\n        mAdapter.changeCursor(data);\n    }\n\n    @Override\n    public void onLoaderReset(Loader<Cursor> loader) {\n        mAdapter.changeCursor(null);\n    }\n\n    @Override\n    public void onResume() {\n        super.onResume();\n        parent().registerReceiver(dataRefreshReceiver, new IntentFilter(Odoo.ACTION_ODOO_UPDATES));\n        getLoaderManager().restartLoader(0, null, News.this);\n    }\n\n    @Override\n    public void onPause() {\n        super.onPause();\n        parent().unregisterReceiver(dataRefreshReceiver);\n    }\n\n    @Override\n    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {\n        NewsDetail nDetail = new NewsDetail();\n        ODataRow row = OCursorUtils.toDatarow((Cursor) mAdapter.getItem(position));\n        nDetail.setArguments(row.getPrimaryBundleData());\n        startFragment(nDetail, true);\n    }\n\n    class DataRefreshReceiver extends BroadcastReceiver {\n\n        @Override\n        public void onReceive(Context context, Intent intent) {\n            getLoaderManager().restartLoader(0, null, News.this);\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/news/NewsDetail.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 13/3/15 5:29 PM\n */\npackage com.odoo.news;\n\nimport android.content.Context;\nimport android.os.Bundle;\nimport android.support.annotation.Nullable;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.webkit.WebView;\n\nimport com.odoo.R;\nimport com.odoo.core.orm.ODataRow;\nimport com.odoo.core.orm.fields.OColumn;\nimport com.odoo.core.support.addons.fragment.BaseFragment;\nimport com.odoo.core.support.drawer.ODrawerItem;\nimport com.odoo.core.utils.OControls;\nimport com.odoo.news.models.OdooNews;\n\nimport java.util.List;\n\npublic class NewsDetail extends BaseFragment {\n    public static final String TAG = NewsDetail.class.getSimpleName();\n    private int id = 0;\n\n    @Override\n    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {\n        return inflater.inflate(R.layout.news_detail, container, false);\n    }\n\n    @Override\n    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {\n        super.onViewCreated(view, savedInstanceState);\n        OdooNews news = new OdooNews(getActivity(), null);\n        getArgument();\n        ODataRow row = news.browse(id);\n        OControls.setText(view, R.id.detailSubject, row.getString(\"subject\"));\n        WebView wvMessage = (WebView) view.findViewById(R.id.detailMessage);\n        wvMessage.loadData(row.getString(\"message\"), \"text/html;UTF-8\", \"UTF-8\");\n\n    }\n\n    private void getArgument() {\n        Bundle b = getArguments();\n        id = b.getInt(OColumn.ROW_ID);\n    }\n\n    @Override\n    public List<ODrawerItem> drawerMenus(Context context) {\n        return null;\n    }\n\n    @Override\n    public <T> Class<T> database() {\n        return null;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/news/OdooNewsReceiver.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 13/3/15 2:29 PM\n */\npackage com.odoo.news;\n\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\n\nimport com.odoo.core.orm.OValues;\nimport com.odoo.news.models.OdooNews;\n\n/**\n * Odoo News Receiver\n */\npublic class OdooNewsReceiver extends BroadcastReceiver {\n    public static final String TAG = OdooNewsReceiver.class.getSimpleName();\n\n    @Override\n    public void onReceive(Context context, Intent intent) {\n        // Use Keys: subject, from, message\n        OdooNews news = new OdooNews(context, null);\n        OValues values = new OValues();\n        values.put(\"sender\", intent.getExtras().getString(\"from\"));\n        values.put(\"subject\", intent.getExtras().getString(\"subject\"));\n        values.put(\"message\", intent.getExtras().getString(\"message\"));\n        news.insert(values);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/news/models/OdooNews.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 13/3/15 2:43 PM\n */\npackage com.odoo.news.models;\n\nimport android.content.Context;\n\nimport com.odoo.core.orm.OModel;\nimport com.odoo.core.orm.fields.OColumn;\nimport com.odoo.core.orm.fields.types.OText;\nimport com.odoo.core.orm.fields.types.OVarchar;\nimport com.odoo.core.support.OUser;\n\npublic class OdooNews extends OModel {\n    public static final String TAG = OdooNews.class.getSimpleName();\n\n    OColumn message = new OColumn(\"Message\", OText.class);\n    OColumn sender = new OColumn(\"sender\", OVarchar.class);\n    OColumn subject = new OColumn(\"Subject\", OVarchar.class);\n\n    public OdooNews(Context context, OUser user) {\n        super(context, \"odoo.news\", user);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/odoo/server/notifications/OdooServerNotificationReceiver.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 1/4/15 7:38 PM\n */\npackage com.odoo.server.notifications;\n\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.os.Bundle;\n\nimport com.odoo.core.utils.notification.ONotificationBuilder;\n\nimport odoo.OdooServerNotification;\n\npublic class OdooServerNotificationReceiver extends BroadcastReceiver {\n    public static final String TAG = OdooServerNotificationReceiver.class.getSimpleName();\n\n    @Override\n    public void onReceive(Context context, Intent intent) {\n        Bundle data = intent.getExtras();\n        int message_id = Integer.parseInt(data.getString(OdooServerNotification.KEY_MESSAGE_ID));\n        ONotificationBuilder builder = new ONotificationBuilder(context,\n                message_id);\n        builder.setTitle(data.getString(OdooServerNotification.KEY_MESSAGE_AUTHOR_NAME));\n        builder.setBigText(data.getString(OdooServerNotification.KEY_MESSAGE_BODY));\n        builder.build().show();\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/odoo/controls/BezelImageView.java",
    "content": "/*\n * Copyright 2014 Google Inc. All rights reserved.\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 odoo.controls;\n\nimport android.content.Context;\nimport android.content.res.TypedArray;\nimport android.graphics.Bitmap;\nimport android.graphics.Canvas;\nimport android.graphics.ColorMatrix;\nimport android.graphics.ColorMatrixColorFilter;\nimport android.graphics.Paint;\nimport android.graphics.PorterDuff;\nimport android.graphics.PorterDuffXfermode;\nimport android.graphics.Rect;\nimport android.graphics.RectF;\nimport android.graphics.drawable.Drawable;\nimport android.support.v4.view.ViewCompat;\nimport android.util.AttributeSet;\nimport android.widget.ImageView;\n\nimport com.odoo.R;\n\n/**\n * An {@link android.widget.ImageView} that draws its contents inside a mask and\n * draws a border drawable on top. This is useful for applying a beveled look to\n * image contents, but is also flexible enough for use with other desired\n * aesthetics.\n */\npublic class BezelImageView extends ImageView {\n    private Paint mBlackPaint;\n    private Paint mMaskedPaint;\n\n    private Rect mBounds;\n    private RectF mBoundsF;\n\n    private Drawable mBorderDrawable;\n    private Drawable mMaskDrawable;\n\n    private ColorMatrixColorFilter mDesaturateColorFilter;\n    private boolean mDesaturateOnPress = false;\n\n    private boolean mCacheValid = false;\n    private Bitmap mCacheBitmap;\n    private int mCachedWidth;\n    private int mCachedHeight;\n    private Context mContext;\n\n    public BezelImageView(Context context) {\n        this(context, null);\n    }\n\n    public BezelImageView(Context context, AttributeSet attrs) {\n        this(context, attrs, 0);\n    }\n\n    public BezelImageView(Context context, AttributeSet attrs, int defStyle) {\n        super(context, attrs, defStyle);\n        mContext = context;\n        // Attribute initialization\n        final TypedArray a = context.obtainStyledAttributes(attrs,\n                R.styleable.BezelImageView, defStyle, 0);\n\n        mMaskDrawable = a.getDrawable(R.styleable.BezelImageView_maskDrawable);\n        if (mMaskDrawable != null) {\n            mMaskDrawable.setCallback(this);\n        }\n\n        mBorderDrawable = a\n                .getDrawable(R.styleable.BezelImageView_borderDrawable);\n        if (mBorderDrawable != null) {\n            mBorderDrawable.setCallback(this);\n        }\n\n        mDesaturateOnPress = a.getBoolean(\n                R.styleable.BezelImageView_desaturateOnPress,\n                mDesaturateOnPress);\n\n        a.recycle();\n        otherInit();\n    }\n\n    public void autoSetMaskDrawable() {\n        mMaskDrawable = mContext.getResources().getDrawable(\n                R.drawable.circle_mask);\n        otherInit();\n    }\n\n    private void otherInit() {\n        // Other initialization\n        mBlackPaint = new Paint();\n        mBlackPaint.setColor(0xff000000);\n\n        mMaskedPaint = new Paint();\n        mMaskedPaint\n                .setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));\n\n        // Always want a cache allocated.\n        mCacheBitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);\n\n        if (mDesaturateOnPress) {\n            // Create a desaturate color filter for pressed state.\n            ColorMatrix cm = new ColorMatrix();\n            cm.setSaturation(0);\n            mDesaturateColorFilter = new ColorMatrixColorFilter(cm);\n        }\n    }\n\n    @Override\n    protected boolean setFrame(int l, int t, int r, int b) {\n        final boolean changed = super.setFrame(l, t, r, b);\n        mBounds = new Rect(0, 0, r - l, b - t);\n        mBoundsF = new RectF(mBounds);\n\n        if (mBorderDrawable != null) {\n            mBorderDrawable.setBounds(mBounds);\n        }\n        if (mMaskDrawable != null) {\n            mMaskDrawable.setBounds(mBounds);\n        }\n\n        if (changed) {\n            mCacheValid = false;\n        }\n\n        return changed;\n    }\n\n    @Override\n    protected void onDraw(Canvas canvas) {\n        if (mBounds == null) {\n            return;\n        }\n\n        int width = mBounds.width();\n        int height = mBounds.height();\n\n        if (width == 0 || height == 0) {\n            return;\n        }\n\n        if (!mCacheValid || width != mCachedWidth || height != mCachedHeight) {\n            // Need to redraw the cache\n            if (width == mCachedWidth && height == mCachedHeight) {\n                // Have a correct-sized bitmap cache already allocated. Just\n                // erase it.\n                mCacheBitmap.eraseColor(0);\n            } else {\n                // Allocate a new bitmap with the correct dimensions.\n                mCacheBitmap.recycle();\n                // noinspection AndroidLintDrawAllocation\n                mCacheBitmap = Bitmap.createBitmap(width, height,\n                        Bitmap.Config.ARGB_8888);\n                mCachedWidth = width;\n                mCachedHeight = height;\n            }\n\n            Canvas cacheCanvas = new Canvas(mCacheBitmap);\n            if (mMaskDrawable != null) {\n                int sc = cacheCanvas.save();\n                mMaskDrawable.draw(cacheCanvas);\n                mMaskedPaint\n                        .setColorFilter((mDesaturateOnPress && isPressed()) ? mDesaturateColorFilter\n                                : null);\n                cacheCanvas.saveLayer(mBoundsF, mMaskedPaint,\n                        Canvas.HAS_ALPHA_LAYER_SAVE_FLAG\n                                | Canvas.FULL_COLOR_LAYER_SAVE_FLAG);\n                super.onDraw(cacheCanvas);\n                cacheCanvas.restoreToCount(sc);\n            } else if (mDesaturateOnPress && isPressed()) {\n                int sc = cacheCanvas.save();\n                cacheCanvas.drawRect(0, 0, mCachedWidth, mCachedHeight,\n                        mBlackPaint);\n                mMaskedPaint.setColorFilter(mDesaturateColorFilter);\n                cacheCanvas.saveLayer(mBoundsF, mMaskedPaint,\n                        Canvas.HAS_ALPHA_LAYER_SAVE_FLAG\n                                | Canvas.FULL_COLOR_LAYER_SAVE_FLAG);\n                super.onDraw(cacheCanvas);\n                cacheCanvas.restoreToCount(sc);\n            } else {\n                super.onDraw(cacheCanvas);\n            }\n\n            if (mBorderDrawable != null) {\n                mBorderDrawable.draw(cacheCanvas);\n            }\n        }\n\n        // Draw from cache\n        canvas.drawBitmap(mCacheBitmap, mBounds.left, mBounds.top, null);\n    }\n\n    @Override\n    protected void drawableStateChanged() {\n        super.drawableStateChanged();\n        if (mBorderDrawable != null && mBorderDrawable.isStateful()) {\n            mBorderDrawable.setState(getDrawableState());\n        }\n        if (mMaskDrawable != null && mMaskDrawable.isStateful()) {\n            mMaskDrawable.setState(getDrawableState());\n        }\n        if (isDuplicateParentStateEnabled()) {\n            ViewCompat.postInvalidateOnAnimation(this);\n        }\n    }\n\n    @Override\n    public void invalidateDrawable(Drawable who) {\n        if (who == mBorderDrawable || who == mMaskDrawable) {\n            invalidate();\n        } else {\n            super.invalidateDrawable(who);\n        }\n    }\n\n    @Override\n    protected boolean verifyDrawable(Drawable who) {\n        return who == mBorderDrawable || who == mMaskDrawable\n                || super.verifyDrawable(who);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/odoo/controls/DateTimePicker.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 7/1/15 5:10 PM\n */\npackage odoo.controls;\n\nimport android.app.DatePickerDialog;\nimport android.app.Dialog;\nimport android.app.TimePickerDialog;\nimport android.content.Context;\nimport android.content.DialogInterface;\n\nimport com.odoo.core.utils.ODateUtils;\n\nimport java.text.SimpleDateFormat;\nimport java.util.Calendar;\nimport java.util.Date;\n\npublic class DateTimePicker {\n    public static final String TAG = DateTimePicker.class.getSimpleName();\n\n    public enum Type {\n        Date, DateTime, Time\n    }\n\n    private Context mContext = null;\n    private Builder mBuilder;\n    private DatePicker mDatePicker;\n    private TimePicker mTimePicker;\n\n    public DateTimePicker() {\n\n    }\n\n    public DateTimePicker(Context context, Builder builder) {\n        mContext = context;\n        mBuilder = builder;\n    }\n\n    public void show() {\n        if (mBuilder.getType() == Type.Time) {\n            mTimePicker = new TimePicker(mContext, mBuilder.getTime());\n            mTimePicker.setPickerCallback(callBack);\n            mTimePicker.show();\n        } else {\n            mDatePicker = new DatePicker(mContext, mBuilder.getDate());\n            mDatePicker.setPickerCallback(callBack);\n            mDatePicker.show();\n        }\n    }\n\n    PickerCallBack callBack = new PickerCallBack() {\n\n        @Override\n        public void onTimePick(String time) {\n            mBuilder.getCallBack().onTimePick(time);\n            mTimePicker.dismiss();\n        }\n\n        @Override\n        public void onDatePick(String date) {\n            mDatePicker.dismiss();\n            if (mBuilder.getType() == Type.DateTime) {\n                mTimePicker = new TimePicker(mContext, mBuilder.getTime());\n                mTimePicker.setPickerCallback(callBack);\n                mTimePicker.show();\n            }\n            mBuilder.getCallBack().onDatePick(date);\n        }\n    };\n\n    public static class Builder {\n        private Context mContext;\n        private Type mType = Type.DateTime;\n        private PickerCallBack mCallback;\n        private String mDialogTitle = null;\n        private String time = null;\n        private String date = null;\n        private String dateTime = null;\n\n        public Builder(Context context) {\n            mContext = context;\n        }\n\n        public Builder setDate(String date) {\n            this.date = date;\n            return this;\n        }\n\n        public Builder setTime(String time) {\n            this.time = time;\n            return this;\n        }\n\n        public Builder setDateTime(String dateTime) {\n            if (dateTime != null) {\n                date = ODateUtils.parseDate(dateTime, ODateUtils.DEFAULT_FORMAT,\n                        ODateUtils.DEFAULT_DATE_FORMAT);\n                time = ODateUtils.parseDate(dateTime, ODateUtils.DEFAULT_FORMAT,\n                        ODateUtils.DEFAULT_TIME_FORMAT);\n            }\n            return this;\n        }\n\n        public Calendar getDate() {\n            if (date != null) {\n                Date dt = ODateUtils.createDateObject(date, ODateUtils.DEFAULT_DATE_FORMAT, false);\n                Calendar cal = Calendar.getInstance();\n                cal.setTime(dt);\n                return cal;\n            }\n            return null;\n        }\n\n        public Calendar getTime() {\n            if (time != null) {\n                Date dt = ODateUtils.createDateObject(time, ODateUtils.DEFAULT_TIME_FORMAT, false);\n                Calendar cal = Calendar.getInstance();\n                cal.setTime(dt);\n                return cal;\n            }\n            return null;\n        }\n\n        public Builder setType(Type type) {\n            mType = type;\n            return this;\n        }\n\n        public Type getType() {\n            return mType;\n        }\n\n        public Builder setCallBack(PickerCallBack callback) {\n            mCallback = callback;\n            return this;\n        }\n\n        public PickerCallBack getCallBack() {\n            return mCallback;\n        }\n\n        public Builder setTitle(String title) {\n            mDialogTitle = title;\n            return this;\n        }\n\n        public Builder setTitle(int res_id) {\n            mDialogTitle = mContext.getResources().getString(res_id);\n            return this;\n        }\n\n        public String getDialogTitle() {\n            return mDialogTitle;\n        }\n\n        public DateTimePicker build() {\n            DateTimePicker picker = new DateTimePicker(mContext, this);\n            return picker;\n        }\n    }\n\n    public class DatePicker implements DatePickerDialog.OnDateSetListener,\n            DialogInterface.OnCancelListener {\n\n        private PickerCallBack mCallback;\n        private boolean called = false;\n        private Dialog mDialog;\n\n        public DatePicker(Context context, Calendar date) {\n            final Calendar c = (date != null) ? date : Calendar.getInstance();\n            int year = c.get(Calendar.YEAR);\n            int month = c.get(Calendar.MONTH);\n            int day = c.get(Calendar.DAY_OF_MONTH);\n            mDialog = new DatePickerDialog(context, this, year, month, day);\n            mDialog.setOnCancelListener(this);\n        }\n\n        @Override\n        public void onCancel(DialogInterface dialog) {\n\n        }\n\n        @Override\n        public void onDateSet(android.widget.DatePicker view, int year,\n                              int monthOfYear, int dayOfMonth) {\n            if (mCallback != null && !called) {\n                Calendar cal = Calendar.getInstance();\n                cal.set(Calendar.MONTH, monthOfYear);\n                cal.set(Calendar.DAY_OF_MONTH, dayOfMonth);\n                cal.set(Calendar.YEAR, year);\n                Date now = cal.getTime();\n                String date = new SimpleDateFormat(ODateUtils.DEFAULT_DATE_FORMAT)\n                        .format(now);\n                mCallback.onDatePick(date);\n                called = true;\n            }\n        }\n\n        public void setPickerCallback(PickerCallBack callback) {\n            mCallback = callback;\n        }\n\n        public void show() {\n            mDialog.show();\n        }\n\n        public void dismiss() {\n            mDialog.dismiss();\n        }\n    }\n\n    public class TimePicker implements TimePickerDialog.OnTimeSetListener,\n            DialogInterface.OnCancelListener {\n\n        private PickerCallBack mCallback;\n        private TimePickerDialog mDialog = null;\n\n        public TimePicker(Context context, Calendar time) {\n\n            final Calendar c = (time != null) ? time : Calendar.getInstance();\n            int hour = c.get(Calendar.HOUR_OF_DAY);\n            int minute = c.get(Calendar.MINUTE);\n            mDialog = new TimePickerDialog(context, this, hour, minute, false);\n            mDialog.setOnCancelListener(this);\n        }\n\n        @Override\n        public void onTimeSet(android.widget.TimePicker view, int hourOfDay,\n                              int minute) {\n            if (mCallback != null) {\n                Calendar cal = Calendar.getInstance();\n                cal.set(Calendar.HOUR_OF_DAY, hourOfDay);\n                cal.set(Calendar.MINUTE, minute);\n                cal.set(Calendar.MILLISECOND, 0);\n                Date now = cal.getTime();\n                String time = new SimpleDateFormat(ODateUtils.DEFAULT_TIME_FORMAT)\n                        .format(now);\n                mCallback.onTimePick(time);\n            }\n        }\n\n        @Override\n        public void onCancel(DialogInterface dialog) {\n        }\n\n        public void setPickerCallback(PickerCallBack callback) {\n            mCallback = callback;\n        }\n\n        public void show() {\n            mDialog.show();\n        }\n\n        public void dismiss() {\n            mDialog.dismiss();\n        }\n    }\n\n    public interface PickerCallBack {\n        public void onDatePick(String date);\n\n        public void onTimePick(String time);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/odoo/controls/ExpandableListControl.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 3/2/15 2:08 PM\n */\npackage odoo.controls;\n\nimport android.content.Context;\nimport android.util.AttributeSet;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.LinearLayout;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class ExpandableListControl extends LinearLayout\n        implements ExpandableListOperationListener {\n    public static final String TAG = ExpandableListControl.class.getSimpleName();\n    private ExpandableListAdapter mAdapter;\n    private Context context;\n\n    public ExpandableListControl(Context context) {\n        super(context);\n        this.context = context;\n    }\n\n    public ExpandableListControl(Context context, AttributeSet attrs) {\n        super(context, attrs);\n        this.context = context;\n    }\n\n    public ExpandableListControl(Context context, AttributeSet attrs, int defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n        this.context = context;\n    }\n\n    @Override\n    public void onAdapterDataChange(List<Object> items) {\n        removeAllViews();\n        for (int i = 0; i < items.size(); i++) {\n            View view = mAdapter.getView(i, null, this);\n            addView(view);\n        }\n    }\n\n    public ExpandableListAdapter getAdapter(int resource, List<Object> objects,\n                                            final ExpandableListAdapterGetViewListener listener) {\n        mAdapter = new ExpandableListAdapter(context, resource, objects) {\n            @Override\n            public View getView(int position, View convertView, ViewGroup parent) {\n                if (convertView == null) {\n                    convertView = LayoutInflater.from(context).inflate(getResource(), parent, false);\n                }\n                if (listener != null) {\n                    return listener.getView(position, convertView, parent);\n                }\n                return convertView;\n            }\n        };\n        mAdapter.setOperationListener(this);\n        return mAdapter;\n    }\n\n\n    public abstract static class ExpandableListAdapter {\n        private List<Object> objects = new ArrayList<>();\n        private Context context;\n        private int resource = android.R.layout.simple_list_item_1;\n        private ExpandableListOperationListener listener;\n\n        public ExpandableListAdapter(Context context, int resource, List<Object> objects) {\n            this.context = context;\n            this.objects = objects;\n            this.resource = resource;\n        }\n\n        public abstract View getView(int position, View convertView, ViewGroup parent);\n\n        public void notifyDataSetChanged(List<Object> items) {\n            objects = items;\n            listener.onAdapterDataChange(items);\n        }\n\n        public Object getItem(int position) {\n            return objects.get(position);\n        }\n\n        public void setOperationListener(ExpandableListOperationListener listener) {\n            this.listener = listener;\n        }\n\n        public int getResource() {\n            return resource;\n        }\n    }\n\n    public static interface ExpandableListAdapterGetViewListener {\n        public View getView(int position, View view, ViewGroup parent);\n    }\n\n\n}\n"
  },
  {
    "path": "app/src/main/java/odoo/controls/ExpandableListOperationListener.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 3/2/15 2:17 PM\n */\npackage odoo.controls;\n\nimport java.util.List;\n\npublic interface ExpandableListOperationListener {\n    public void onAdapterDataChange(List<Object> items);\n}\n"
  },
  {
    "path": "app/src/main/java/odoo/controls/IOControlData.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 7/1/15 5:15 PM\n */\npackage odoo.controls;\n\nimport android.view.View;\n\nimport com.odoo.core.orm.fields.OColumn;\n\npublic interface IOControlData {\n    public static final String TAG = IOControlData.class.getSimpleName();\n\n    public void setValue(Object value);\n\n    public Object getValue();\n\n    public void setEditable(Boolean editable);\n\n    public Boolean isEditable();\n\n    public void setLabelText(String label);\n\n    public void setColumn(OColumn column);\n\n    public void initControl();\n\n    public String getLabel();\n\n    public void setValueUpdateListener(ValueUpdateListener listener);\n\n    public static interface ValueUpdateListener {\n        public void onValueUpdate(Object value);\n\n        public void visibleControl(boolean isVisible);\n    }\n\n    public Boolean isControlReady();\n\n    public void resetData();\n\n    public View getFieldView();\n\n    public void setError(String error);\n}\n"
  },
  {
    "path": "app/src/main/java/odoo/controls/IOnChangeCallback.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 7/1/15 5:11 PM\n */\npackage odoo.controls;\n\nimport com.odoo.core.orm.ODataRow;\n\npublic interface IOnChangeCallback {\n    public static final String TAG = IOnChangeCallback.class.getSimpleName();\n\n    public void onValueChange(ODataRow row);\n}\n"
  },
  {
    "path": "app/src/main/java/odoo/controls/IOnDomainFilterCallbacks.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 7/1/15 5:11 PM\n */\npackage odoo.controls;\n\nimport com.odoo.core.orm.fields.OColumn;\n\npublic interface IOnDomainFilterCallbacks {\n    public static final String TAG = IOnDomainFilterCallbacks.class.getSimpleName();\n\n    public void onFieldValueChanged(OColumn.ColumnDomain domain);\n}\n"
  },
  {
    "path": "app/src/main/java/odoo/controls/IOnQuickRecordCreateListener.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 20/1/15 5:01 PM\n */\npackage odoo.controls;\n\nimport com.odoo.core.orm.ODataRow;\n\npublic interface IOnQuickRecordCreateListener {\n    public void onRecordCreated(ODataRow row);\n}\n"
  },
  {
    "path": "app/src/main/java/odoo/controls/OBlobField.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 7/1/15 5:10 PM\n */\npackage odoo.controls;\n\nimport android.annotation.TargetApi;\nimport android.content.Context;\nimport android.os.Build;\nimport android.util.AttributeSet;\nimport android.view.View;\nimport android.widget.LinearLayout;\n\nimport com.odoo.core.orm.fields.OColumn;\nimport com.odoo.core.utils.BitmapUtils;\n\npublic class OBlobField extends LinearLayout implements IOControlData {\n    public static final String TAG = OBlobField.class.getSimpleName();\n\n    private Context mContext;\n    private Boolean mReady = false, isEditable = false;\n    private ValueUpdateListener mValueUpdateListener = null;\n    private String mLabel;\n    private OColumn mCol;\n    private Object mValue;\n    private BezelImageView imgView;\n    private OField.WidgetType mWidget = OField.WidgetType.Image;\n    private float imageSize = -1;\n    private Integer defaultImage = -1;\n\n    @TargetApi(Build.VERSION_CODES.LOLLIPOP)\n    public OBlobField(Context context, AttributeSet attrs, int defStyleAttr,\n                      int defStyleRes) {\n        super(context, attrs, defStyleAttr, defStyleRes);\n        init(context, attrs, defStyleAttr, defStyleRes);\n    }\n\n    public OBlobField(Context context, AttributeSet attrs, int defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n        init(context, attrs, defStyleAttr, 0);\n    }\n\n    public OBlobField(Context context, AttributeSet attrs) {\n        super(context, attrs);\n        init(context, attrs, 0, 0);\n    }\n\n    public OBlobField(Context context) {\n        super(context);\n        init(context, null, 0, 0);\n    }\n\n    private void init(Context context, AttributeSet attrs, int defStyleAttr,\n                      int defStyleRes) {\n        mContext = context;\n        if (attrs != null) {\n\n        }\n        if (mContext.getClass().getSimpleName().contains(\"BridgeContext\"))\n            initControl();\n    }\n\n    @Override\n    public void initControl() {\n        LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT,\n                LayoutParams.WRAP_CONTENT);\n        if (imageSize > -1) {\n            params = new LayoutParams((int) imageSize, (int) imageSize);\n        }\n        removeAllViews();\n        setOrientation(VERTICAL);\n        imgView = new BezelImageView(mContext);\n        imgView.setLayoutParams(params);\n        switch (mWidget) {\n            case ImageCircle:\n                imgView.autoSetMaskDrawable();\n            case Image:\n                break;\n        }\n        addView(imgView);\n    }\n\n    @Override\n    public void setValue(Object value) {\n        mValue = value;\n        if (mValue != null && imgView != null) {\n            if (!mValue.equals(\"false\")) {\n                imgView.setImageBitmap(BitmapUtils.getBitmapImage(mContext, mValue.toString()));\n            } else if (defaultImage > -1) {\n                imgView.setImageResource(defaultImage);\n            }\n        }\n    }\n\n\n    @Override\n    public void setError(String error) {\n\n    }\n\n    @Override\n    public View getFieldView() {\n        return imgView;\n    }\n\n    @Override\n    public Object getValue() {\n        return mValue;\n    }\n\n    @Override\n    public void setEditable(Boolean editable) {\n        isEditable = editable;\n    }\n\n    @Override\n    public Boolean isEditable() {\n        return isEditable;\n    }\n\n    @Override\n    public void setColumn(OColumn column) {\n        mCol = column;\n    }\n\n    @Override\n    public void setLabelText(String label) {\n        mLabel = label;\n    }\n\n    @Override\n    public String getLabel() {\n        if (mLabel != null)\n            return mLabel;\n        if (mCol != null)\n            return mCol.getLabel();\n        return \"unknown\";\n    }\n\n    @Override\n    public void setValueUpdateListener(ValueUpdateListener listener) {\n        mValueUpdateListener = listener;\n    }\n\n    @Override\n    public Boolean isControlReady() {\n        return mReady;\n    }\n\n    @Override\n    public void resetData() {\n\n    }\n\n    @Override\n    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {\n        super.onMeasure(widthMeasureSpec, heightMeasureSpec);\n        mReady = true;\n    }\n\n    public void setWidgetType(OField.WidgetType type) {\n        if (type != null) {\n            mWidget = type;\n            initControl();\n        }\n    }\n\n    public void setImageSize(float size) {\n        imageSize = size;\n    }\n\n    public void setDefaultImage(int image) {\n        defaultImage = image;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/odoo/controls/OBooleanField.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 7/1/15 5:10 PM\n */\npackage odoo.controls;\n\nimport android.annotation.TargetApi;\nimport android.content.Context;\nimport android.graphics.Color;\nimport android.os.Build;\nimport android.util.AttributeSet;\nimport android.util.TypedValue;\nimport android.view.View;\nimport android.widget.CheckBox;\nimport android.widget.CompoundButton;\nimport android.widget.LinearLayout;\nimport android.widget.Switch;\nimport android.widget.TextView;\nimport android.widget.Toast;\n\nimport com.odoo.core.orm.fields.OColumn;\n\npublic class OBooleanField extends LinearLayout implements IOControlData,\n        CompoundButton.OnCheckedChangeListener {\n    public static final String TAG = OBooleanField.class.getSimpleName();\n\n    private Context mContext;\n    private OColumn mColumn;\n    private Boolean mEditable = false;\n    private String mLabel = null;\n    private Boolean mValue = false;\n    private OField.WidgetType mWidget = null;\n    private ValueUpdateListener mValueUpdateListener = null;\n    // Controls\n    private TextView txvView = null;\n    private CheckBox mCheckbox = null;\n    private Switch mSwitch = null;\n    private Boolean mReady = false;\n    private float textSize = -1;\n    private int appearance = -1;\n    private int textColor = Color.BLACK;\n\n    @TargetApi(Build.VERSION_CODES.LOLLIPOP)\n    public OBooleanField(Context context, AttributeSet attrs, int defStyleAttr,\n                         int defStyleRes) {\n        super(context, attrs, defStyleAttr, defStyleRes);\n        init(context, attrs, defStyleAttr, defStyleRes);\n    }\n\n    public OBooleanField(Context context, AttributeSet attrs, int defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n        init(context, attrs, defStyleAttr, 0);\n    }\n\n    public OBooleanField(Context context, AttributeSet attrs) {\n        super(context, attrs);\n        init(context, attrs, 0, 0);\n    }\n\n    public OBooleanField(Context context) {\n        super(context);\n        init(context, null, 0, 0);\n    }\n\n    private void init(Context context, AttributeSet attrs, int defStyleAttr,\n                      int defStyleRes) {\n        mContext = context;\n        if (attrs != null) {\n\n        }\n        if (mContext.getClass().getSimpleName().contains(\"BridgeContext\"))\n            initControl();\n    }\n\n    public void initControl() {\n        mReady = false;\n        LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT,\n                LayoutParams.WRAP_CONTENT);\n        removeAllViews();\n        setOrientation(VERTICAL);\n        if (isEditable()) {\n            if (mWidget != null) {\n                switch (mWidget) {\n                    case Switch:\n                        mSwitch = new Switch(mContext);\n                        mSwitch.setLayoutParams(params);\n                        mSwitch.setOnCheckedChangeListener(this);\n                        setValue(getValue());\n                        if (mLabel != null)\n                            mSwitch.setText(mLabel);\n                        if (textSize > -1) {\n                            mSwitch.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);\n                        }\n                        if (appearance > -1) {\n                            mSwitch.setTextAppearance(mContext, appearance);\n                        }\n                        mSwitch.setTextColor(textColor);\n                        addView(mSwitch);\n                        break;\n                    default:\n                        break;\n                }\n            } else {\n                mCheckbox = new CheckBox(mContext);\n                mCheckbox.setLayoutParams(params);\n                mCheckbox.setOnCheckedChangeListener(this);\n                if (mLabel != null)\n                    mCheckbox.setText(mLabel);\n                if (textSize > -1) {\n                    mCheckbox.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);\n                }\n                if (appearance > -1) {\n                    mCheckbox.setTextAppearance(mContext, appearance);\n                }\n                mCheckbox.setTextColor(textColor);\n                addView(mCheckbox);\n            }\n        } else {\n            txvView = new TextView(mContext);\n            txvView.setLayoutParams(params);\n            txvView.setText(getCheckBoxLabel());\n            if (mLabel != null)\n                txvView.setText(mLabel);\n            if (textSize > -1) {\n                txvView.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);\n            }\n            if (appearance > -1) {\n                txvView.setTextAppearance(mContext, appearance);\n            }\n            addView(txvView);\n        }\n    }\n\n    @Override\n    public void setValue(Object value) {\n        if (value == null)\n            return;\n        mValue = Boolean.parseBoolean(value.toString());\n        if (isEditable()) {\n            if (mWidget != null) {\n                switch (mWidget) {\n                    case Switch:\n                        mSwitch.setChecked(Boolean.parseBoolean(getValue()\n                                .toString()));\n                        break;\n                    default:\n                        break;\n                }\n            } else {\n                mCheckbox.setChecked(Boolean\n                        .parseBoolean(getValue().toString()));\n            }\n        } else {\n            txvView.setText(getCheckBoxLabel());\n        }\n        if (mValueUpdateListener != null) {\n            mValueUpdateListener.onValueUpdate(value);\n            if (!isEditable() && mValue == false) {\n                mValueUpdateListener.visibleControl(false);\n            } else {\n                mValueUpdateListener.visibleControl(true);\n            }\n        }\n    }\n\n    @Override\n    public View getFieldView() {\n        if (isEditable()) {\n            if (mWidget != null) {\n                switch (mWidget) {\n                    case Switch:\n                        return mSwitch;\n                }\n            }\n            return mCheckbox;\n        } else {\n            return txvView;\n        }\n    }\n\n    @Override\n    public void setError(String error) {\n        if (error != null)\n            Toast.makeText(mContext, error, Toast.LENGTH_LONG).show();\n    }\n\n    @Override\n    public Object getValue() {\n        return mValue;\n    }\n\n    @Override\n    public void setEditable(Boolean editable) {\n        mEditable = editable;\n        initControl();\n    }\n\n    @Override\n    public Boolean isEditable() {\n        return mEditable;\n    }\n\n    public void setWidgetType(OField.WidgetType type) {\n        mWidget = type;\n        initControl();\n    }\n\n    @Override\n    public void setLabelText(String label) {\n        mLabel = label;\n    }\n\n    private String getCheckBoxLabel() {\n        String label = \"\";\n        if (getValue() != null && Boolean.parseBoolean(getValue().toString())) {\n            label = \"✔ \";\n        }\n        label += getLabel();\n        return label;\n    }\n\n    @Override\n    public String getLabel() {\n        if (mLabel != null)\n            return mLabel;\n        if (mColumn != null)\n            return mColumn.getLabel();\n        return \"unknown\";\n    }\n\n    @Override\n    public void setColumn(OColumn column) {\n        mColumn = column;\n        if (mLabel == null && mColumn != null)\n            mLabel = mColumn.getLabel();\n    }\n\n    @Override\n    public void setValueUpdateListener(ValueUpdateListener listener) {\n        mValueUpdateListener = listener;\n    }\n\n    @Override\n    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {\n        setValue(isChecked);\n    }\n\n    @Override\n    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {\n        super.onMeasure(widthMeasureSpec, heightMeasureSpec);\n        mReady = true;\n    }\n\n    @Override\n    public Boolean isControlReady() {\n        return mReady;\n    }\n\n    @Override\n    public void resetData() {\n        setValue(getValue());\n    }\n\n    public void setResource(float textSize, int appearance, int color) {\n        this.textSize = textSize;\n        this.appearance = appearance;\n        this.textColor = color;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/odoo/controls/OControlHelper.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 7/1/15 5:46 PM\n */\npackage odoo.controls;\n\nimport android.graphics.Typeface;\n\npublic class OControlHelper {\n    public static final String TAG = OControlHelper.class.getSimpleName();\n\n    public static Typeface boldFont() {\n        return Typeface.create(\"sans-serif-condensed\", 0);\n    }\n\n    public static Typeface lightFont() {\n        return Typeface.create(\"sans-serif-light\", 0);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/odoo/controls/ODateTimeField.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 7/1/15 5:10 PM\n */\npackage odoo.controls;\n\nimport android.annotation.TargetApi;\nimport android.content.Context;\nimport android.graphics.Color;\nimport android.os.Build;\nimport android.text.TextUtils;\nimport android.util.AttributeSet;\nimport android.util.TypedValue;\nimport android.view.View;\nimport android.widget.LinearLayout;\nimport android.widget.TextView;\nimport android.widget.Toast;\n\nimport com.odoo.core.orm.fields.OColumn;\nimport com.odoo.core.utils.ODateUtils;\n\nimport java.util.Date;\n\nimport static odoo.controls.OField.FieldType;\n\npublic class ODateTimeField extends LinearLayout implements IOControlData,\n        DateTimePicker.PickerCallBack {\n    public static final String TAG = ODateTimeField.class.getSimpleName();\n\n\n    private Context mContext;\n    private Boolean mEditable = false;\n    private OColumn mColumn;\n    private String mLabel, mHint;\n    private ValueUpdateListener mValueUpdateListener = null;\n    private FieldType mFieldType;\n    private TextView txvText;\n    private Object mValue;\n    private String mParsePattern = ODateUtils.DEFAULT_DATE_FORMAT;\n    private DateTimePicker.Builder builder = null;\n    private String mDate;\n    private Boolean mReady = false;\n    private float textSize = -1;\n    private int appearance = -1;\n    private int textColor = Color.BLACK;\n\n    @TargetApi(Build.VERSION_CODES.LOLLIPOP)\n    public ODateTimeField(Context context, AttributeSet attrs,\n                          int defStyleAttr, int defStyleRes) {\n        super(context, attrs, defStyleAttr, defStyleRes);\n        init(context, attrs, defStyleAttr, defStyleRes);\n    }\n\n    public ODateTimeField(Context context, AttributeSet attrs, int defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n        init(context, attrs, defStyleAttr, 0);\n    }\n\n    public ODateTimeField(Context context, AttributeSet attrs) {\n        super(context, attrs);\n        init(context, attrs, 0, 0);\n    }\n\n    public ODateTimeField(Context context) {\n        super(context);\n        init(context, null, 0, 0);\n    }\n\n    private void init(Context context, AttributeSet attrs, int defStyleAttr,\n                      int defStyleRes) {\n        mContext = context;\n        if (attrs != null) {\n\n        }\n        mReady = false;\n        initControl();\n    }\n\n    public void setFieldType(FieldType type) {\n        mFieldType = type;\n        if (mFieldType == FieldType.DateTime) {\n            mParsePattern = ODateUtils.DEFAULT_FORMAT;\n        }\n    }\n\n    @Override\n    public void initControl() {\n        LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT,\n                LayoutParams.WRAP_CONTENT);\n        removeAllViews();\n        setOrientation(VERTICAL);\n        txvText = new TextView(mContext);\n        txvText.setLayoutParams(params);\n        txvText.setOnClickListener(null);\n        if (isEditable()) {\n            txvText.setOnClickListener(onClick);\n        }\n        if (mValue != null && !mValue.toString().equals(\"false\")) {\n            txvText.setText(getDate(mValue.toString(), mParsePattern));\n        }\n        if (textSize > -1) {\n            txvText.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);\n        }\n        if (appearance > -1) {\n            txvText.setTextAppearance(mContext, appearance);\n        }\n        txvText.setTextColor(textColor);\n        addView(txvText);\n    }\n\n    @Override\n    public void setValue(Object value) {\n        mValue = value;\n        if (value == null || value.toString().equals(\"false\")) {\n            txvText.setText(\"No Value\");\n            return;\n        }\n        txvText.setText(getDate(mValue.toString(), mParsePattern));\n        if (mValueUpdateListener != null) {\n            mValueUpdateListener.onValueUpdate(value);\n        }\n    }\n\n    @Override\n    public View getFieldView() {\n        return null;\n    }\n\n\n    @Override\n    public void setError(String error) {\n        if (error != null)\n            Toast.makeText(mContext, error, Toast.LENGTH_LONG).show();\n    }\n\n    @Override\n    public Object getValue() {\n        if (mValue != null && !TextUtils.isEmpty(mValue.toString())) {\n            if (mFieldType == FieldType.Date)\n                return mValue.toString().replaceAll(\" 00:00:00\", \"\");\n            return mValue;\n        }\n        return null;\n    }\n\n    @Override\n    public void setEditable(Boolean editable) {\n        if (mEditable != editable) {\n            mEditable = editable;\n        }\n    }\n\n    @Override\n    public Boolean isEditable() {\n        return mEditable;\n    }\n\n    @Override\n    public void setLabelText(String label) {\n        mLabel = label;\n    }\n\n    @Override\n    public void setColumn(OColumn column) {\n        mColumn = column;\n    }\n\n    @Override\n    public String getLabel() {\n        if (mLabel != null)\n            return mLabel;\n        if (mColumn != null)\n            return mColumn.getLabel();\n        if (mHint != null)\n            return mHint;\n        return \"unknown\";\n    }\n\n    @Override\n    public void setValueUpdateListener(ValueUpdateListener listener) {\n        mValueUpdateListener = listener;\n    }\n\n    View.OnClickListener onClick = new OnClickListener() {\n\n        @Override\n        public void onClick(View v) {\n            builder = new DateTimePicker.Builder(mContext);\n            if (mFieldType == FieldType.Date) {\n                if (getValue() != null && !getValue().toString().equals(\"false\"))\n                    builder.setDate(getValue().toString());\n                builder.setType(DateTimePicker.Type.Date);\n            } else if (mFieldType == FieldType.Time) {\n                if (getValue() != null && !getValue().toString().equals(\"false\"))\n                    builder.setTime(getValue().toString());\n                builder.setType(DateTimePicker.Type.Time);\n            } else {\n                if (getValue() != null && !getValue().toString().equals(\"false\"))\n                    builder.setDateTime(getValue().toString());\n                builder.setType(DateTimePicker.Type.DateTime);\n            }\n            builder.setCallBack(ODateTimeField.this);\n            builder.build().show();\n        }\n    };\n\n    private String getDate(String date, String format) {\n        if (date.contains(\"now()\") || date.contains(\"NOW()\")) {\n            mValue = ODateUtils.getUTCDate((mFieldType == FieldType.Date) ? ODateUtils.DEFAULT_DATE_FORMAT\n                    : (mFieldType == FieldType.Time) ? ODateUtils.DEFAULT_TIME_FORMAT : ODateUtils.DEFAULT_FORMAT);\n            return ODateUtils.getDate(format);\n        } else {\n            if (mFieldType == FieldType.Date) {\n                date += \" 00:00:00\";\n            }\n            String defaultFormat = ODateUtils.DEFAULT_FORMAT;\n            if (mFieldType == FieldType.Time) {\n                defaultFormat = ODateUtils.DEFAULT_TIME_FORMAT;\n            }\n            return ODateUtils.convertToDefault(date, defaultFormat, format);\n        }\n    }\n\n    @Override\n    public void onDatePick(String date) {\n        mDate = date;\n        if (mFieldType == FieldType.Date) {\n            setValue(mDate + \" 00:00:00\");\n        }\n    }\n\n    @Override\n    public void onTimePick(String time) {\n        String date;\n        String format;\n        if (mFieldType == FieldType.Time) {\n            date = time;\n            format = ODateUtils.DEFAULT_TIME_FORMAT;\n        } else {\n            date = mDate + \" \" + time;\n            format = ODateUtils.DEFAULT_FORMAT;\n        }\n        Date dt = ODateUtils.createDateObject(date, format, true);\n        String utc_date = ODateUtils.getUTCDate(dt, format);\n        setValue(utc_date);\n    }\n\n    public void setParsePattern(String parsePattern) {\n        if (parsePattern != null)\n            mParsePattern = parsePattern;\n    }\n\n    @Override\n    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {\n        super.onMeasure(widthMeasureSpec, heightMeasureSpec);\n        mReady = true;\n    }\n\n    @Override\n    public Boolean isControlReady() {\n        return mReady;\n    }\n\n    @Override\n    public void resetData() {\n        setValue(getValue());\n    }\n\n    public void setResource(float textSize, int appearance, int color) {\n        this.textSize = textSize;\n        this.appearance = appearance;\n        this.textColor = color;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/odoo/controls/OEditTextField.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 7/1/15 5:10 PM\n */\npackage odoo.controls;\n\nimport android.annotation.TargetApi;\nimport android.content.Context;\nimport android.graphics.Color;\nimport android.os.Build;\nimport android.util.AttributeSet;\nimport android.util.TypedValue;\nimport android.view.View;\nimport android.widget.EditText;\nimport android.widget.LinearLayout;\nimport android.widget.TextView;\n\nimport com.odoo.core.orm.fields.OColumn;\nimport com.odoo.core.utils.ODateUtils;\n\npublic class OEditTextField extends LinearLayout implements IOControlData,\n        View.OnFocusChangeListener {\n    public static final String TAG = OEditTextField.class.getSimpleName();\n\n    private Context mContext;\n    private EditText edtText;\n    private TextView txvText;\n    private Boolean mEditable = false, mReady = false;\n    private OField.WidgetType mWidget = null;\n    private OColumn mColumn;\n    private String mLabel, mHint;\n    private ValueUpdateListener mValueUpdateListener = null;\n    private float textSize = -1;\n    private int appearance = -1;\n    private int textColor = Color.BLACK;\n\n    @TargetApi(Build.VERSION_CODES.LOLLIPOP)\n    public OEditTextField(Context context, AttributeSet attrs,\n                          int defStyleAttr, int defStyleRes) {\n        super(context, attrs, defStyleAttr, defStyleRes);\n        init(context, attrs, defStyleAttr, defStyleRes);\n    }\n\n    public OEditTextField(Context context, AttributeSet attrs, int defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n        init(context, attrs, defStyleAttr, 0);\n    }\n\n    public OEditTextField(Context context, AttributeSet attrs) {\n        super(context, attrs);\n        init(context, attrs, 0, 0);\n    }\n\n    public OEditTextField(Context context) {\n        super(context);\n        init(context, null, 0, 0);\n    }\n\n    private void init(Context context, AttributeSet attrs, int defStyleAttr,\n                      int defStyleRes) {\n        mContext = context;\n        if (attrs != null) {\n\n        }\n        mReady = false;\n        if (mContext.getClass().getSimpleName().contains(\"BridgeContext\"))\n            initControl();\n    }\n\n    public void initControl() {\n        // Creating control\n        LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT,\n                LayoutParams.WRAP_CONTENT);\n        removeAllViews();\n        setOrientation(VERTICAL);\n        if (mEditable) {\n            edtText = new EditText(mContext);\n            edtText.setTypeface(OControlHelper.lightFont());\n            edtText.setLayoutParams(params);\n            edtText.setBackgroundColor(Color.TRANSPARENT);\n            edtText.setPadding(0, 10, 10, 10);\n            edtText.setHint(getLabel());\n            edtText.setOnFocusChangeListener(this);\n            if (textSize > -1) {\n                edtText.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);\n            }\n            if (appearance > -1) {\n                edtText.setTextAppearance(mContext, appearance);\n            }\n            edtText.setTextColor(textColor);\n            addView(edtText);\n        } else {\n            txvText = new TextView(mContext);\n            txvText.setTypeface(OControlHelper.lightFont());\n            txvText.setLayoutParams(params);\n            txvText.setBackgroundColor(Color.TRANSPARENT);\n            txvText.setPadding(0, 10, 10, 10);\n            if (textSize > -1) {\n                txvText.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);\n            }\n            if (appearance > -1) {\n                txvText.setTextAppearance(mContext, appearance);\n            }\n            txvText.setTextColor(textColor);\n            addView(txvText);\n        }\n    }\n\n    public void setWidgetType(OField.WidgetType type) {\n        mWidget = type;\n        initControl();\n    }\n\n    @Override\n    public void setValue(Object value) {\n        if (value == null)\n            return;\n        if (value.toString().equals(\"false\")) {\n            value = \"\";\n        } else if (mWidget == OField.WidgetType.Duration) {\n            value = ODateUtils.floatToDuration(value.toString());\n        }\n        if (mEditable) {\n            edtText.setText(value.toString());\n        } else {\n            txvText.setText(value.toString());\n        }\n        if (mValueUpdateListener != null) {\n            mValueUpdateListener.onValueUpdate(value);\n        }\n    }\n\n    @Override\n    public View getFieldView() {\n        if (mEditable)\n            return edtText;\n        return txvText;\n    }\n\n\n    @Override\n    public void setError(String error) {\n        if (mEditable) {\n            edtText.setError(error);\n        }\n    }\n\n    @Override\n    public Object getValue() {\n        Object value = null;\n        if (mEditable)\n            value = edtText.getText();\n        else if (txvText != null)\n            value = txvText.getText();\n        if ((value != null || !value.toString().equals(\"false\")) && mWidget == OField.WidgetType.Duration) {\n            value = ODateUtils.durationToFloat(value.toString());\n        }\n        return value;\n    }\n\n    @Override\n    public void setEditable(Boolean editable) {\n        if (mEditable != editable) {\n            mEditable = editable;\n        }\n    }\n\n    @Override\n    public Boolean isEditable() {\n        return mEditable;\n    }\n\n    public void setHint(String hint) {\n        mHint = hint;\n    }\n\n    @Override\n    public void setLabelText(String label) {\n        mLabel = label;\n    }\n\n    @Override\n    public void setColumn(OColumn column) {\n        mColumn = column;\n    }\n\n    @Override\n    public String getLabel() {\n        if (mLabel != null)\n            return mLabel;\n        if (mColumn != null)\n            return mColumn.getLabel();\n        if (mHint != null)\n            return mHint;\n        return \"unknown\";\n    }\n\n    @Override\n    public void setValueUpdateListener(ValueUpdateListener listener) {\n        mValueUpdateListener = listener;\n    }\n\n    @Override\n    public void onFocusChange(View v, boolean hasFocus) {\n        if (!hasFocus && edtText.getText().length() > 0) {\n            setValue(getValue());\n        }\n    }\n\n    @Override\n    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {\n        super.onMeasure(widthMeasureSpec, heightMeasureSpec);\n        mReady = true;\n    }\n\n    @Override\n    public Boolean isControlReady() {\n        return mReady;\n    }\n\n    @Override\n    public void resetData() {\n        setValue(getValue());\n    }\n\n    public void setResource(float textSize, int appearance, int color) {\n        this.textSize = textSize;\n        this.appearance = appearance;\n        this.textColor = color;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/odoo/controls/OField.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 7/1/15 5:10 PM\n */\npackage odoo.controls;\n\nimport android.annotation.TargetApi;\nimport android.content.Context;\nimport android.content.res.TypedArray;\nimport android.graphics.Color;\nimport android.os.Build;\nimport android.util.AttributeSet;\nimport android.util.TypedValue;\nimport android.view.Gravity;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.ImageView;\nimport android.widget.LinearLayout;\nimport android.widget.TextView;\n\nimport com.odoo.core.orm.ODataRow;\nimport com.odoo.core.orm.OModel;\nimport com.odoo.core.orm.fields.OColumn;\nimport com.odoo.core.orm.fields.types.OBlob;\nimport com.odoo.core.orm.fields.types.OBoolean;\nimport com.odoo.core.orm.fields.types.ODate;\nimport com.odoo.core.orm.fields.types.ODateTime;\nimport com.odoo.core.orm.fields.types.OFloat;\nimport com.odoo.core.orm.fields.types.OHtml;\nimport com.odoo.core.orm.fields.types.OInteger;\nimport com.odoo.core.orm.fields.types.OSelection;\nimport com.odoo.core.orm.fields.types.OText;\nimport com.odoo.core.orm.fields.types.OTimestamp;\nimport com.odoo.core.orm.fields.types.OVarchar;\nimport com.odoo.R;\n\npublic class OField extends LinearLayout implements IOControlData.ValueUpdateListener {\n    public static final String TAG = OField.class.getSimpleName();\n    private Context mContext = null;\n    private FieldType mType = FieldType.Text;\n    private OColumn mColumn = null;\n    private OModel mModel = null;\n    private String mLabel, mField_name;\n    private Object mValue = null;\n    private boolean mEditable = false, showIcon = true, show_label = true;\n    private TextView label_view = null;\n    private int resId, tint_color = Color.BLACK, mValueArrayId = -1;\n    private ImageView img_icon = null;\n    private ViewGroup container = null;\n    private Boolean with_bottom_padding = true, with_top_padding = true;\n    private WidgetType mWidgetType = null;\n    private String mParsePattern = null;\n    private IOnChangeCallback mOnChangeCallback = null;\n    private IOnDomainFilterCallbacks mOnDomainFilterCallbacks = null;\n    private OColumn.ColumnDomain mColumnDomain = null;\n    private float mWidgetImageSize = -1;\n    private Boolean withPadding = true;\n    // Controls\n    private IOControlData mControlData = null;\n    private Boolean useTemplate = true;\n    private Integer defaultImage = -1;\n    // Appearance\n    private int textColor = Color.BLACK;\n    private int labelColor = Color.DKGRAY;\n    private int textAppearance = -1;\n    private int labelAppearance = -1;\n    private float textSize = -1;\n    private float labelSize = -1;\n    private IOnFieldValueChangeListener mValueUpdateListener = null;\n\n    public enum WidgetType {\n        Switch, RadioGroup, SelectionDialog, Searchable, SearchableLive, Image, ImageCircle, Duration;\n\n        public static WidgetType getWidgetType(int widget) {\n            switch (widget) {\n                case 0:\n                    return WidgetType.Switch;\n                case 1:\n                    return WidgetType.RadioGroup;\n                case 2:\n                    return WidgetType.SelectionDialog;\n                case 3:\n                    return WidgetType.Searchable;\n                case 4:\n                    return WidgetType.SearchableLive;\n                case 5:\n                    return WidgetType.Image;\n                case 6:\n                    return WidgetType.ImageCircle;\n                case 7:\n                    return WidgetType.Duration;\n            }\n            return null;\n        }\n    }\n\n    public enum FieldType {\n        Text, Boolean, ManyToOne, Chips, Selection, Date, Time, DateTime, Blob, RelationType;\n\n        public static FieldType getTypeValue(int type_val) {\n            switch (type_val) {\n                case 0:\n                    return FieldType.Text;\n                case 1:\n                    return FieldType.Boolean;\n                case 2:\n                    return FieldType.ManyToOne;\n                case 3:\n                    return FieldType.Chips;\n                case 4:\n                    return FieldType.Selection;\n                case 5:\n                    return FieldType.Date;\n                case 6:\n                    return FieldType.DateTime;\n                case 7:\n                    return FieldType.Blob;\n                case 8:\n                    return FieldType.Time;\n            }\n            return FieldType.Text;\n        }\n    }\n\n    public OField(Context context) {\n        super(context);\n        init(context, null, 0, 0);\n    }\n\n    @TargetApi(Build.VERSION_CODES.LOLLIPOP)\n    public OField(Context context, AttributeSet attrs, int defStyleAttr,\n                  int defStyleRes) {\n        super(context, attrs, defStyleAttr, defStyleRes);\n        init(context, attrs, defStyleAttr, defStyleRes);\n    }\n\n    public OField(Context context, AttributeSet attrs, int defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n        init(context, attrs, defStyleAttr, 0);\n    }\n\n    public OField(Context context, AttributeSet attrs) {\n        super(context, attrs);\n        init(context, attrs, 0, 0);\n    }\n\n    private void init(Context context, AttributeSet attrs, int defStyleAttr,\n                      int defStyleRes) {\n        mContext = context;\n        if (attrs != null) {\n            TypedArray types = mContext.obtainStyledAttributes(attrs,\n                    R.styleable.OField);\n            mField_name = types.getString(R.styleable.OField_fieldName);\n            resId = types.getResourceId(R.styleable.OField_iconResource, 0);\n            showIcon = types.getBoolean(R.styleable.OField_showIcon, true);\n            tint_color = types.getColor(R.styleable.OField_iconTint, 0);\n            show_label = types.getBoolean(R.styleable.OField_showLabel, true);\n            int type_value = types.getInt(R.styleable.OField_fieldType, 0);\n            mType = FieldType.getTypeValue(type_value);\n\n            with_bottom_padding = types.getBoolean(\n                    R.styleable.OField_withBottomPadding, true);\n            with_top_padding = types.getBoolean(\n                    R.styleable.OField_withTopPadding, true);\n            mLabel = types.getString(R.styleable.OField_controlLabel);\n            mValue = types.getString(R.styleable.OField_defaultValue);\n            mParsePattern = types.getString(R.styleable.OField_parsePattern);\n            mValueArrayId = types.getResourceId(\n                    R.styleable.OField_valueArray, -1);\n            mWidgetType = WidgetType.getWidgetType(types.getInt(\n                    R.styleable.OField_widgetType, -1));\n            mWidgetImageSize = types.getDimension(R.styleable.OField_widgetImageSize, -1);\n            withPadding = types.getBoolean(R.styleable.OField_withOutSidePadding, true);\n\n            textColor = types.getColor(R.styleable.OField_fieldTextColor, Color.BLACK);\n            labelColor = types.getColor(R.styleable.OField_fieldLabelColor, Color.DKGRAY);\n            textAppearance = types.getResourceId(R.styleable.OField_fieldTextAppearance, -1);\n            labelAppearance = types.getResourceId(R.styleable.OField_fieldLabelTextAppearance, -1);\n            textSize = types.getDimension(R.styleable.OField_fieldTextSize, -1);\n            labelSize = types.getDimension(R.styleable.OField_fieldLabelSize, -1);\n            defaultImage = types.getResourceId(R.styleable.OField_defaultImage, -1);\n            types.recycle();\n        }\n        if (mContext.getClass().getSimpleName().contains(\"BridgeContext\"))\n            initControl();\n    }\n\n    public void useTemplate(Boolean withTemplate) {\n        useTemplate = withTemplate;\n    }\n\n    private void initLayout() {\n        removeAllViews();\n        if (useTemplate) {\n            View layout = LayoutInflater.from(mContext).inflate(\n                    R.layout.base_control_template, this, false);\n\n            if (withPadding) {\n                int top_padding = layout.getPaddingTop();\n                int right_padding = layout.getPaddingRight();\n                int bottom_padding = layout.getPaddingBottom();\n                int left_padding = layout.getPaddingLeft();\n                if (!with_bottom_padding) {\n                    layout.setPadding(left_padding, top_padding, right_padding, 0);\n                }\n                if (!with_top_padding) {\n                    layout.setPadding(left_padding, 0, right_padding, bottom_padding);\n                }\n            } else {\n                layout.setPadding(0, 0, 0, 0);\n            }\n            addView(layout);\n            container = (ViewGroup) findViewById(R.id.control_container);\n            img_icon = (ImageView) findViewById(android.R.id.icon);\n            img_icon.setColorFilter(tint_color);\n            setImageIcon();\n        } else {\n            container = this;\n        }\n    }\n\n    public void initControl() {\n        initLayout();\n        View controlView = null;\n        if (show_label) {\n            label_view = getLabelView();\n            container.addView(label_view);\n        }\n        switch (mType) {\n            case Text:\n                controlView = initTextControl();\n                break;\n            case Boolean:\n                controlView = initBooleanControl();\n                break;\n            case Chips:\n                break;\n            case ManyToOne:\n            case Selection:\n                controlView = initSelectionWidget();\n                break;\n            case Date:\n            case Time:\n            case DateTime:\n                controlView = initDateTimeControl(mType);\n                break;\n            case Blob:\n                controlView = initBlobControl();\n                break;\n            default:\n                return;\n        }\n        mControlData.setValueUpdateListener(this);\n        mControlData.setEditable(getEditable());\n        mControlData.initControl();\n        mControlData.setValue(mValue);\n        container.addView(controlView);\n    }\n\n    public <T> T getFieldView() {\n        return (T) mControlData.getFieldView();\n    }\n\n    public void setIconTintColor(int color) {\n        tint_color = color;\n        if (img_icon != null) {\n            img_icon.setColorFilter(tint_color);\n        }\n    }\n\n    private void setImageIcon() {\n        if (showIcon) {\n            if (resId != 0)\n                img_icon.setImageResource(resId);\n            if (tint_color != 0)\n                img_icon.setColorFilter(tint_color);\n        } else\n            img_icon.setVisibility(View.GONE);\n    }\n\n    public <T> void setColumn(OColumn column) {\n        mColumn = column;\n        mType = getType(column.getType());\n        if (label_view != null) {\n            label_view.setText(getLabelText());\n        }\n        if (mControlData != null) {\n            mControlData.setColumn(mColumn);\n        }\n    }\n\n    private <T> FieldType getType(Class<T> type_class) {\n        try {\n            // Varchar\n            if (type_class.isAssignableFrom(OVarchar.class)\n                    || type_class.isAssignableFrom(OInteger.class)\n                    || type_class.isAssignableFrom(OFloat.class)) {\n                return FieldType.Text;\n            }\n            // boolean\n            if (type_class.isAssignableFrom(OBoolean.class)) {\n                return FieldType.Boolean;\n            }\n\n            // Blob\n            if (type_class.isAssignableFrom(OBlob.class)) {\n                return FieldType.Blob;\n            }\n            // DateTime\n            if (type_class.isAssignableFrom(ODateTime.class)\n                    || type_class.isAssignableFrom(OTimestamp.class)) {\n                return FieldType.DateTime;\n            }\n            // Date\n            if (type_class.isAssignableFrom(ODate.class)) {\n                return FieldType.Date;\n            }\n            // Text\n            if (type_class.isAssignableFrom(OText.class)) {\n                return FieldType.Text;\n            }\n            // FIXME: WebView type\n            if (type_class.isAssignableFrom(OHtml.class)) {\n                return FieldType.Text;\n            }\n            if (type_class.isAssignableFrom(OSelection.class)) {\n                return FieldType.Selection;\n            }\n            // ManyToOne\n            if (mColumn.getRelationType() != null\n                    && mColumn.getRelationType() == OColumn.RelationType.ManyToOne) {\n                return FieldType.ManyToOne;\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return null;\n    }\n\n    public String getLabelText() {\n        if (mLabel != null)\n            return mLabel;\n        if (mColumn != null)\n            return mColumn.getLabel();\n        if (mControlData != null)\n            return mControlData.getLabel();\n        return getFieldName();\n    }\n\n    public void setValue(Object value) {\n        mValue = value;\n        if (mValue != null && mControlData != null) {\n            mControlData.setValue(mValue);\n        }\n    }\n\n    public Object getValue() {\n        if (mControlData != null)\n            return mControlData.getValue();\n        return null;\n    }\n\n    public void setEditable(Boolean editable) {\n        mEditable = editable;\n        if (mControlData != null) {\n            Object value = getValue();\n            mControlData.setEditable(editable);\n            mControlData.initControl();\n            if (value != null)\n                mControlData.setValue(value);\n        }\n    }\n\n    public boolean getEditable() {\n        return mEditable;\n    }\n\n    public String getFieldName() {\n        return mField_name;\n    }\n\n    // EditText control (TextView, EditText)\n    private View initTextControl() {\n        setOrientation(VERTICAL);\n        OEditTextField edt = new OEditTextField(mContext);\n        edt.setWidgetType(mWidgetType);\n        mControlData = edt;\n        edt.setResource(textSize, textAppearance, textColor);\n        edt.setColumn(mColumn);\n        edt.setHint(mLabel);\n        return edt;\n    }\n\n    // Boolean Control (Checkbox, W-Switch)\n    private View initBooleanControl() {\n        OBooleanField bool = new OBooleanField(mContext);\n        mControlData = bool;\n        bool.setResource(textSize, textAppearance, textColor);\n        bool.setColumn(mColumn);\n        bool.setEditable(getEditable());\n        bool.setLabelText(getLabelText());\n        bool.setWidgetType(mWidgetType);\n        return bool;\n    }\n\n    // Selection, Searchable, SearchableLive\n    private View initSelectionWidget() {\n        OSelectionField selection = new OSelectionField(mContext);\n        mControlData = selection;\n        selection.setResource(textSize, textAppearance, textColor);\n        selection.setLabelText(getLabelText());\n        selection.setModel(mModel);\n        selection.setArrayResourceId(mValueArrayId);\n        selection.setColumn(mColumn);\n        selection.setWidgetType(mWidgetType);\n        return selection;\n    }\n\n    // Datetime (dialog with date or date time)\n    private View initDateTimeControl(FieldType type) {\n        ODateTimeField datetime = new ODateTimeField(mContext);\n        mControlData = datetime;\n        datetime.setResource(textSize, textAppearance, textColor);\n        datetime.setFieldType(type);\n        datetime.setParsePattern(mParsePattern);\n        datetime.setLabelText(getLabelText());\n        datetime.setColumn(mColumn);\n        return datetime;\n    }\n\n    // Blob (file contents)\n    private View initBlobControl() {\n        OBlobField blob = new OBlobField(mContext);\n        mControlData = blob;\n        blob.setDefaultImage(defaultImage);\n        blob.setImageSize(mWidgetImageSize);\n        blob.setLabelText(getLabelText());\n        blob.setColumn(mColumn);\n        blob.setWidgetType(mWidgetType);\n        return blob;\n    }\n\n    private TextView getLabelView() {\n        LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT,\n                LayoutParams.WRAP_CONTENT);\n        TextView label = new TextView(mContext);\n        if (labelSize > -1) {\n            label.setTextSize(TypedValue.COMPLEX_UNIT_PX, labelSize);\n        }\n        if (labelAppearance > -1) {\n            label.setTextAppearance(mContext, labelAppearance);\n        }\n        label.setTextColor(labelColor);\n        label.setLayoutParams(params);\n        label.setGravity(Gravity.LEFT);\n        label.setText(getLabelText());\n        label.setAllCaps(true);\n        return label;\n    }\n\n    public void setIcon(int resourceId) {\n        img_icon.setImageResource(resourceId);\n    }\n\n    public void setError(String error) {\n        mControlData.setError(error);\n    }\n\n    public int getIcon() {\n        return resId;\n    }\n\n    public void setModel(OModel model) {\n        mModel = model;\n    }\n\n    public OModel getModel() {\n        return mModel;\n    }\n\n    public OColumn getColumn() {\n        return mColumn;\n    }\n\n    public void resetData() {\n        mControlData.resetData();\n    }\n\n    @Override\n    public void onValueUpdate(Object value) {\n        mValue = value;\n        if (mValueUpdateListener != null) {\n            mValueUpdateListener.onFieldValueChange(this, value);\n        }\n        if (value instanceof ODataRow) {\n            mValue = ((ODataRow) value).get(OColumn.ROW_ID);\n        }\n        if (mEditable) {\n            if (mControlData.isControlReady()) {\n                ODataRow row = new ODataRow();\n                if (mOnChangeCallback != null\n                        || mOnDomainFilterCallbacks != null) {\n                    if (!(value instanceof ODataRow)) {\n                        row.put(mColumn.getName(), value);\n                    } else {\n                        row = (ODataRow) value;\n                    }\n                }\n                if (mOnChangeCallback != null) {\n                    mOnChangeCallback.onValueChange(row);\n                }\n                if (mOnDomainFilterCallbacks != null) {\n                    mColumnDomain.setValue(row.getInt(OColumn.ROW_ID));\n                    mOnDomainFilterCallbacks.onFieldValueChanged(mColumnDomain);\n                }\n            }\n        }\n    }\n\n    public void setOnValueChangeListener(IOnFieldValueChangeListener listener) {\n        mValueUpdateListener = listener;\n    }\n\n    @Override\n    public void visibleControl(boolean isVisible) {\n        if (isVisible) {\n            setVisibility(View.VISIBLE);\n        } else {\n            setVisibility(View.GONE);\n        }\n    }\n\n    /**\n     * OnChange CallBack for column\n     *\n     * @param callback\n     */\n    public void setOnChangeCallbackListener(IOnChangeCallback callback) {\n        mOnChangeCallback = callback;\n    }\n\n    /**\n     * Domain Filters\n     *\n     * @param domain\n     * @param callback\n     */\n    public void setOnFilterDomainCallBack(OColumn.ColumnDomain domain,\n                                          IOnDomainFilterCallbacks callback) {\n        mColumnDomain = domain;\n        mOnDomainFilterCallbacks = callback;\n    }\n\n    public interface IOnFieldValueChangeListener {\n        public void onFieldValueChange(OField field, Object value);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/odoo/controls/OForm.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 7/1/15 5:10 PM\n */\npackage odoo.controls;\n\nimport android.animation.LayoutTransition;\nimport android.annotation.TargetApi;\nimport android.app.ProgressDialog;\nimport android.content.Context;\nimport android.content.res.TypedArray;\nimport android.os.AsyncTask;\nimport android.os.Build;\nimport android.os.Handler;\nimport android.text.TextUtils;\nimport android.util.AttributeSet;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.LinearLayout;\nimport android.widget.RelativeLayout;\n\nimport com.odoo.R;\nimport com.odoo.base.addons.mail.widget.MailChatterView;\nimport com.odoo.core.orm.ODataRow;\nimport com.odoo.core.orm.OModel;\nimport com.odoo.core.orm.OValues;\nimport com.odoo.core.orm.fields.OColumn;\nimport com.odoo.core.utils.OResource;\nimport com.odoo.core.utils.logger.OLog;\n\nimport java.util.HashMap;\nimport java.util.LinkedHashMap;\n\npublic class OForm extends LinearLayout {\n    public static final String TAG = OForm.class.getSimpleName();\n    private Boolean mEditable = false;\n    private String mModel;\n    private OModel model = null;\n    private HashMap<String, OField> mFormFieldControls = new HashMap<>();\n    private Context mContext = null;\n    private ODataRow mRecord = null;\n    private Boolean autoUIGenerate = true;\n    private int icon_tint_color = 0;\n    private Boolean mFirstModeChange = true;\n    private OValues extraValues = new OValues();\n    private MailChatterView chatterView = null;\n    private Boolean loadChatter = true;\n\n    public OForm(Context context) {\n        super(context);\n        init(context, null, 0, 0);\n    }\n\n    @TargetApi(Build.VERSION_CODES.LOLLIPOP)\n    public OForm(Context context, AttributeSet attrs, int defStyleAttr,\n                 int defStyleRes) {\n        super(context, attrs, defStyleAttr, defStyleRes);\n        init(context, attrs, defStyleAttr, defStyleRes);\n    }\n\n    public OForm(Context context, AttributeSet attrs, int defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n        init(context, attrs, defStyleAttr, 0);\n    }\n\n    public OForm(Context context, AttributeSet attrs) {\n        super(context, attrs);\n        init(context, attrs, 0, 0);\n    }\n\n    public void setEditable(Boolean editable) {\n        mEditable = editable;\n        if (mEditable) {\n            mFirstModeChange = true;\n        }\n        for (String key : mFormFieldControls.keySet()) {\n            OField control = mFormFieldControls.get(key);\n            control.setEditable(editable);\n        }\n        mFirstModeChange = false;\n    }\n\n    private void init(Context context, AttributeSet attrs, int defStyleAttr,\n                      int defStyleRes) {\n        mFirstModeChange = true;\n        mContext = context;\n        if (attrs != null) {\n            TypedArray types = mContext.obtainStyledAttributes(attrs,\n                    R.styleable.OForm);\n            mModel = types.getString(R.styleable.OForm_modelName);\n            mEditable = types.getBoolean(R.styleable.OForm_editableMode,\n                    false);\n            autoUIGenerate = types.getBoolean(R.styleable.OForm_autoUIGenerate, true);\n            icon_tint_color = types.getColor(R.styleable.OForm_controlIconTint, -1);\n            types.recycle();\n        }\n        initForm();\n        LayoutTransition transition = new LayoutTransition();\n        setLayoutTransition(transition);\n    }\n\n    public boolean getEditable() {\n        return mEditable;\n    }\n\n    public void setModel(String model) {\n        mModel = model;\n    }\n\n    public String getModel() {\n        return mModel;\n    }\n\n    public void setData(ODataRow record) {\n        initForm(record);\n    }\n\n    public ODataRow getData() {\n        return mRecord;\n    }\n\n    public void initForm(ODataRow record) {\n        mRecord = new ODataRow();\n        mRecord = record;\n        initForm();\n    }\n\n    public void setIconTintColor(int color) {\n        icon_tint_color = color;\n    }\n\n    private void initForm() {\n        findAllFields(this);\n        OLog.log(\"Trying to get model \" + mModel);\n        model = OModel.get(mContext, mModel, null);\n        if (model != null) {\n            setOrientation(VERTICAL);\n            for (String key : mFormFieldControls.keySet()) {\n                View v = mFormFieldControls.get(key);\n                if (v instanceof OField) {\n                    OField c = (OField) v;\n                    c.setEditable(mEditable);\n                    c.useTemplate(autoUIGenerate);\n                    c.setModel(model);\n                    OColumn column = model.getColumn(c.getFieldName());\n                    if (column != null) {\n                        c.setColumn(column);\n                        // Setting OnChange Event\n                        if (column.hasOnChange()) {\n                            setOnChangeForControl(column, c);\n                        }\n\n                        // Setting domain Filter for column\n                        if (column.hasDomainFilterColumn()) {\n                            setOnDomainFilterCallBack(column, c);\n                        }\n                    }\n                    c.initControl();\n                    Object val = c.getValue();\n                    if (mRecord != null) {\n                        if (mRecord.contains(c.getFieldName()))\n                            val = mRecord.get(c.getFieldName());\n                    }\n                    if (val != null)\n                        c.setValue(val);\n                    if (icon_tint_color != -1) {\n                        c.setIconTintColor(icon_tint_color);\n                    }\n                }\n            }\n\n            // Adding chatter view if model requested\n            if (loadChatter) {\n                if (model != null && model.hasMailChatter()\n                        && mRecord != null && mRecord.contains(\"id\")\n                        && mRecord.getInt(\"id\") != 0) {\n                    if (chatterView == null) {\n                        chatterView = (MailChatterView) LayoutInflater.from(mContext)\n                                .inflate(R.layout.base_mail_chatter, this, false);\n                        chatterView.setModelName(model.getModelName());\n                        chatterView.setRecordServerId(mRecord.getInt(\"id\"));\n                        chatterView.generateView();\n                        addView(chatterView);\n                    }\n                }\n            }\n        }\n    }\n\n    public void loadChatter(boolean loadChatter) {\n        this.loadChatter = loadChatter;\n    }\n\n    public void loadChatter(Boolean loadChatter) {\n        this.loadChatter = loadChatter;\n    }\n\n    private void findAllFields(ViewGroup view) {\n        int child = view.getChildCount();\n        for (int i = 0; i < child; i++) {\n            View v = view.getChildAt(i);\n            if (v instanceof LinearLayout || v instanceof RelativeLayout) {\n                if (v.getVisibility() == View.VISIBLE)\n                    findAllFields((ViewGroup) v);\n            }\n            if (v instanceof OField) {\n                OField field = (OField) v;\n                if (field.getVisibility() == View.VISIBLE)\n                    mFormFieldControls.put(field.getFieldName(), field);\n            }\n        }\n    }\n\n    public OValues getValues() {\n        OValues values = new OValues();\n        for (String key : mFormFieldControls.keySet()) {\n            OField control = mFormFieldControls.get(key);\n            Object val = control.getValue();\n            OColumn column = control.getColumn();\n            if (val == null || TextUtils.isEmpty(val.toString())\n                    || val.toString().equals(\"-1\")) {\n                val = false;\n            }\n\n            if (column != null && column.isRequired()) {\n                if (val.toString().equals(\"false\")) {\n                    control.setError(column.getLabel() +\n                            \" \" + OResource.string(mContext, R.string.label_required));\n                    return null;\n                } else {\n                    control.setError(null);\n                }\n            }\n            values.put(key, val);\n        }\n        values.addAll(extraValues.toDataRow().getAll());\n        return values;\n    }\n\n    // OnDomainFilterCallBack callbacks\n    private void setOnDomainFilterCallBack(final OColumn column, OField field) {\n        LinkedHashMap<String, OColumn.ColumnDomain> filterDomain = column\n                .getFilterDomains();\n        for (String key : filterDomain.keySet()) {\n            OColumn.ColumnDomain domain = filterDomain.get(key);\n            if (domain.getColumn() != null) {\n                OField fld = mFormFieldControls.get(domain.getColumn());\n                if (fld != null) {\n                    setFilterDomainCallback(domain, fld, field, column);\n                }\n            }\n        }\n\n    }\n\n    private void setFilterDomainCallback(OColumn.ColumnDomain domain,\n                                         final OField field, final OField oField, final OColumn column) {\n        field.setOnFilterDomainCallBack(domain, new IOnDomainFilterCallbacks() {\n\n            @Override\n            public void onFieldValueChanged(OColumn.ColumnDomain dm) {\n                column.addDomain(dm.getColumn(), dm.getOperator(),\n                        dm.getValue());\n                column.setHasDomainFilterColumn(false);\n                oField.setColumn(column);\n                oField.resetData();\n            }\n        });\n    }\n\n    // OnChange event for control column\n    private void setOnChangeForControl(final OColumn column, OField field) {\n        field.setOnChangeCallbackListener(new IOnChangeCallback() {\n\n            @Override\n            public void onValueChange(final ODataRow row) {\n                if (!mFirstModeChange) {\n                    if (!column.isOnChangeBGProcess()) {\n                        new Handler().postDelayed(new Runnable() {\n\n                            @Override\n                            public void run() {\n                                Object value = model.getOnChangeMethodValue(column, row);\n                                if (value instanceof ODataRow)\n                                    fillOnChangeData((ODataRow) value);\n                            }\n                        }, 300);\n                    } else {\n                        new Handler().postDelayed(new Runnable() {\n\n                            @Override\n                            public void run() {\n                                OnChangeBackground bgProcess = new OnChangeBackground(\n                                        column);\n                                bgProcess.execute(row);\n                            }\n                        }, 300);\n                    }\n                }\n                if (mFirstModeChange) {\n                    mFirstModeChange = false;\n                }\n            }\n\n        });\n    }\n\n    private void fillOnChangeData(ODataRow values) {\n        if (values != null) {\n            for (String key : values.keys()) {\n                if (mFormFieldControls.containsKey(key)) {\n                    OField fld = mFormFieldControls.get(key);\n                    fld.setValue(values.get(key));\n                } else {\n                    extraValues.put(key, values.get(key));\n                }\n            }\n        }\n    }\n\n    private class OnChangeBackground extends\n            AsyncTask<ODataRow, Void, ODataRow> {\n        private ProgressDialog mDialog;\n\n        private OColumn mCol;\n\n        public OnChangeBackground(OColumn col) {\n            mCol = col;\n        }\n\n        @Override\n        protected void onPreExecute() {\n            super.onPreExecute();\n            mDialog = new ProgressDialog(mContext);\n            mDialog.setTitle(mContext.getString(R.string.title_working));\n            mDialog.setMessage(mContext.getString(R.string.title_please_wait));\n            mDialog.setCancelable(false);\n            mDialog.show();\n        }\n\n        @Override\n        protected ODataRow doInBackground(ODataRow... params) {\n            try {\n                Thread.sleep(300);\n                return (ODataRow) model.getOnChangeMethodValue(mCol, params[0]);\n            } catch (Exception e) {\n                e.printStackTrace();\n            }\n            return null;\n        }\n\n        @Override\n        protected void onPostExecute(ODataRow result) {\n            super.onPostExecute(result);\n            if (result != null) {\n                fillOnChangeData(result);\n            }\n            mDialog.dismiss();\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/odoo/controls/OSelectionField.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 7/1/15 5:11 PM\n */\npackage odoo.controls;\n\nimport android.annotation.TargetApi;\nimport android.app.AlertDialog;\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.IntentFilter;\nimport android.graphics.Color;\nimport android.os.Build;\nimport android.util.AttributeSet;\nimport android.util.TypedValue;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.AdapterView;\nimport android.widget.ArrayAdapter;\nimport android.widget.LinearLayout;\nimport android.widget.ListView;\nimport android.widget.RadioButton;\nimport android.widget.RadioGroup;\nimport android.widget.Spinner;\nimport android.widget.TextView;\nimport android.widget.Toast;\n\nimport com.odoo.core.orm.ODataRow;\nimport com.odoo.core.orm.OM2ORecord;\nimport com.odoo.core.orm.OModel;\nimport com.odoo.core.orm.fields.OColumn;\nimport com.odoo.core.orm.fields.types.OSelection;\nimport com.odoo.core.utils.OControls;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class OSelectionField extends LinearLayout implements IOControlData,\n        AdapterView.OnItemSelectedListener, AdapterView.OnItemClickListener, RadioGroup.OnCheckedChangeListener {\n    public static final String TAG = OSelectionField.class.getSimpleName();\n\n    private Context mContext;\n    private Object mValue = null;\n    private Boolean mEditable = false;\n    private OField.WidgetType mWidget = null;\n    private Integer mResourceArray = null;\n    private OColumn mCol;\n    private String mLabel;\n    private OModel mModel;\n    private List<ODataRow> items = new ArrayList<>();\n    private ValueUpdateListener mValueUpdateListener = null;\n    // Controls\n    private Spinner mSpinner = null;\n    private SpinnerAdapter mAdapter;\n    private RadioGroup mRadioGroup = null;\n    private TextView txvView = null;\n    private Boolean mReady = false;\n    private float textSize = -1;\n    private int appearance = -1;\n    private int textColor = Color.BLACK;\n\n    @TargetApi(Build.VERSION_CODES.LOLLIPOP)\n    public OSelectionField(Context context, AttributeSet attrs,\n                           int defStyleAttr, int defStyleRes) {\n        super(context, attrs, defStyleAttr, defStyleRes);\n        init(context, attrs, defStyleAttr, defStyleRes);\n    }\n\n    public OSelectionField(Context context, AttributeSet attrs, int defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n        init(context, attrs, defStyleAttr, 0);\n    }\n\n    public OSelectionField(Context context, AttributeSet attrs) {\n        super(context, attrs);\n        init(context, attrs, 0, 0);\n    }\n\n    public OSelectionField(Context context) {\n        super(context);\n        init(context, null, 0, 0);\n    }\n\n    private void init(Context context, AttributeSet attrs, int defStyleAttr,\n                      int defStyleRes) {\n        mContext = context;\n        if (attrs != null) {\n\n        }\n        if (mContext.getClass().getSimpleName().contains(\"BridgeContext\"))\n            initControl();\n    }\n\n    private void createRadioGroup() {\n        final LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT,\n                LayoutParams.WRAP_CONTENT);\n        if (mRadioGroup == null) {\n            mRadioGroup = new RadioGroup(mContext);\n            mRadioGroup.setLayoutParams(params);\n        } else {\n            removeView(mRadioGroup);\n        }\n        mRadioGroup.removeAllViews();\n        mRadioGroup.setOnCheckedChangeListener(this);\n        for (ODataRow label : items) {\n            RadioButton rdoBtn = new RadioButton(mContext);\n            rdoBtn.setLayoutParams(params);\n            rdoBtn.setText(label.getString(mModel.getDefaultNameColumn()));\n            if (textSize > -1) {\n                rdoBtn.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);\n            }\n            if (appearance > -1) {\n                rdoBtn.setTextAppearance(mContext, appearance);\n            }\n            rdoBtn.setTextColor(textColor);\n            mRadioGroup.addView(rdoBtn);\n        }\n        addView(mRadioGroup);\n    }\n\n    @Override\n    public void initControl() {\n        final LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT,\n                LayoutParams.WRAP_CONTENT);\n        removeAllViews();\n        setOrientation(VERTICAL);\n        createItems();\n        if (isEditable()) {\n            if (mWidget != null) {\n                switch (mWidget) {\n                    case RadioGroup:\n                        createRadioGroup();\n                        return;\n                    case SelectionDialog:\n                        txvView = new TextView(mContext);\n                        txvView.setLayoutParams(params);\n                        mAdapter = new SpinnerAdapter(mContext,\n                                android.R.layout.simple_list_item_1, items);\n                        setOnClickListener(new OnClickListener() {\n\n                            @Override\n                            public void onClick(View v) {\n\n                                AlertDialog dialog = createSelectionDialog(\n                                        getPos(), items, params);\n                                txvView.setTag(dialog);\n                                dialog.show();\n                            }\n                        });\n                        if (textSize > -1) {\n                            txvView.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);\n                        }\n                        if (appearance > -1) {\n                            txvView.setTextAppearance(mContext, appearance);\n                        }\n                        txvView.setTextColor(textColor);\n                        addView(txvView);\n                        return;\n                    case Searchable:\n                    case SearchableLive:\n                        txvView = new TextView(mContext);\n                        txvView.setLayoutParams(params);\n                        setOnClickListener(new OnClickListener() {\n\n                            @Override\n                            public void onClick(View v) {\n                                Intent intent = new Intent(mContext,\n                                        SearchableItemActivity.class);\n                                intent.putExtra(\"resource_id\", mResourceArray);\n                                intent.putExtra(\"selected_position\", getPos());\n                                intent.putExtra(OColumn.ROW_ID, getPos());\n                                intent.putExtra(\"search_hint\", getLabel());\n                                if (mCol != null) {\n                                    intent.putExtra(\"column_name\", mCol.getName());\n                                }\n                            /*\n                             * FIXME: What about filter domain. Pass detail for\n\t\t\t\t\t\t\t * filter domain\n\t\t\t\t\t\t\t */\n                                intent.putExtra(\"model\", mModel.getModelName());\n                                intent.putExtra(\"live_search\",\n                                        (mWidget == OField.WidgetType.SearchableLive));\n                                try {\n                                    mContext.unregisterReceiver(valueReceiver);\n                                } catch (Exception e) {\n\n                                }\n                                mContext.registerReceiver(valueReceiver,\n                                        new IntentFilter(\"searchable_value_select\"));\n                                mContext.startActivity(intent);\n                            }\n                        });\n                        if (textSize > -1) {\n                            txvView.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);\n                        }\n                        if (appearance > -1) {\n                            txvView.setTextAppearance(mContext, appearance);\n                        }\n                        txvView.setTextColor(textColor);\n                        addView(txvView);\n                        return;\n                    default:\n                        break;\n                }\n            }\n\n            // Default View\n            mSpinner = new Spinner(mContext);\n            mSpinner.setLayoutParams(params);\n            mAdapter = new SpinnerAdapter(mContext,\n                    android.R.layout.simple_list_item_1, items);\n            mSpinner.setAdapter(mAdapter);\n            mSpinner.setOnItemSelectedListener(this);\n            addView(mSpinner);\n        } else {\n            setOnClickListener(null);\n            txvView = new TextView(mContext);\n            if (textSize > -1) {\n                txvView.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);\n            }\n            if (appearance > -1) {\n                txvView.setTextAppearance(mContext, appearance);\n            }\n            txvView.setTextColor(textColor);\n            addView(txvView);\n        }\n    }\n\n    private void createItems() {\n        items.clear();\n        if (!mContext.getClass().getSimpleName().contains(\"BridgeContext\")) {\n            if (mResourceArray != null && mResourceArray != -1) {\n                String[] items_list = mContext.getResources().getStringArray(\n                        mResourceArray);\n                ODataRow row = new ODataRow();\n                row.put(OColumn.ROW_ID, -1);\n                row.put(mModel.getDefaultNameColumn(), \"Nothing Selected\");\n                items.add(row);\n                for (int i = 0; i < items_list.length; i++) {\n                    row = new ODataRow();\n                    row.put(OColumn.ROW_ID, i);\n                    row.put(mModel.getDefaultNameColumn(), items_list[i]);\n                    items.add(row);\n                }\n            } else if (mCol.getType().isAssignableFrom(OSelection.class)) {\n                List<ODataRow> rows = new ArrayList<>();\n                Object defaultVal = mCol.getDefaultValue();\n                for (String key : mCol.getSelectionMap().keySet()) {\n                    String val = mCol.getSelectionMap().get(key);\n                    ODataRow row = new ODataRow();\n                    row.put(\"key\", key);\n                    row.put(\"name\", val);\n                    if (defaultVal != null && defaultVal.toString().equals(val)) {\n                        rows.add(0, row);\n                    } else {\n                        rows.add(row);\n                    }\n                }\n                items.addAll(rows);\n            } else {\n                items.addAll(getRecordItems(mModel, mCol));\n            }\n        }\n    }\n\n    private int getPos() {\n        if (mResourceArray != -1 && mValue != null) {\n            return Integer.parseInt(mValue.toString());\n        } else if (mCol.getType().isAssignableFrom(OSelection.class)) {\n            if (items.size() <= 0) {\n                createItems();\n            }\n            for (ODataRow item : items) {\n                int index = items.indexOf(item);\n                if (item.getString(\"key\").equals(mValue.toString())) {\n                    return index;\n                }\n            }\n        } else {\n            ODataRow rec = getValueForM2O();\n            if (rec != null) {\n                return rec.getInt(OColumn.ROW_ID);\n            }\n        }\n        return -1;\n    }\n\n    @Override\n    public void setValue(Object value) {\n        mValue = value;\n        if (mValue == null || mValue.toString().equals(\"false\")) {\n            mValue = -1;\n        }\n        ODataRow row = new ODataRow();\n        if (isEditable()) {\n            if (mWidget != null) {\n                switch (mWidget) {\n                    case RadioGroup:\n                        if (mResourceArray != -1) {\n                            ((RadioButton) mRadioGroup.getChildAt(getPos()))\n                                    .setChecked(true);\n                            row = items.get(getPos());\n                        } else {\n                            Integer row_id = null;\n                            if (mValue instanceof OM2ORecord) {\n                                row = ((OM2ORecord) mValue).browse();\n                                row_id = row.getInt(OColumn.ROW_ID);\n                            } else\n                                row_id = (Integer) mValue;\n                            int index = 0;\n                            for (int i = 0; i < items.size(); i++) {\n                                if (items.get(i).getInt(OColumn.ROW_ID) == row_id) {\n                                    index = i;\n                                    break;\n                                }\n                            }\n                            row = items.get(index);\n                            ((RadioButton) mRadioGroup.getChildAt(index))\n                                    .setChecked(true);\n                        }\n                        break;\n                    case Searchable:\n                    case SearchableLive:\n                    case SelectionDialog:\n                        if (mResourceArray != -1) {\n                            row = items.get(getPos());\n                        } else {\n                            if (mValue instanceof OM2ORecord)\n                                row = ((OM2ORecord) mValue).browse();\n                            else if (mValue instanceof Integer)\n                                row = getRecordData((Integer) mValue);\n                        }\n                        txvView.setText(row.getString(mModel.getDefaultNameColumn()));\n                        if (txvView.getTag() != null) {\n                            AlertDialog dialog = (AlertDialog) txvView.getTag();\n                            dialog.dismiss();\n                        }\n                        break;\n                    default:\n                        break;\n                }\n            } else {\n                if (mResourceArray != -1) {\n                    mSpinner.setSelection(getPos());\n                    row = items.get(getPos());\n                } else if (mCol.getType().isAssignableFrom(OSelection.class)) {\n                    int pos = getPos();\n                    mSpinner.setSelection(pos);\n                } else {\n                    Integer row_id = null;\n                    if (mValue instanceof OM2ORecord) {\n                        row = ((OM2ORecord) mValue).browse();\n                        row_id = row.getInt(OColumn.ROW_ID);\n                    } else if (mValue instanceof Integer)\n                        row_id = (Integer) mValue;\n                    int index = 0;\n                    for (int i = 0; i < items.size(); i++) {\n                        if (items.get(i).getInt(OColumn.ROW_ID) == row_id) {\n                            index = i;\n                            break;\n                        }\n                    }\n                    row = items.get(index);\n                    mSpinner.setSelection(index);\n                }\n            }\n        } else {\n            if (mResourceArray != -1 || mCol.getType().isAssignableFrom(OSelection.class)) {\n                row = items.get(getPos());\n            } else {\n                if (mValue instanceof OM2ORecord) {\n                    row = ((OM2ORecord) mValue).browse();\n                    if (row == null) {\n                        row = new ODataRow();\n                    }\n                } else {\n                    if (!(mValue instanceof Boolean) && mValue != null && !mValue.toString().equals(\"false\")) {\n                        int row_id = (Integer) mValue;\n                        row = getRecordData(row_id);\n                    } else {\n                        row = new ODataRow();\n                        row.put(mModel.getDefaultNameColumn(), \"No \" + mCol.getLabel() + \" selected\");\n                    }\n                }\n            }\n            if (!row.getString(mModel.getDefaultNameColumn()).equals(\"false\"))\n                txvView.setText(row.getString(mModel.getDefaultNameColumn()));\n        }\n        if (mValueUpdateListener != null && mValue != -1) {\n            mValueUpdateListener.onValueUpdate(row);\n        }\n    }\n\n    @Override\n    public View getFieldView() {\n        return null;\n    }\n\n\n    @Override\n    public void setError(String error) {\n        if (error != null)\n            Toast.makeText(mContext, error, Toast.LENGTH_LONG).show();\n    }\n\n    private ODataRow getValueForM2O() {\n        if (getValue() != null) {\n            if (getValue() instanceof OM2ORecord)\n                return ((OM2ORecord) getValue()).browse();\n            else if (getValue() instanceof Integer)\n                return getRecordData((Integer) getValue());\n        }\n        return null;\n    }\n\n    @Override\n    public Object getValue() {\n        if (mValue instanceof OM2ORecord) {\n            return ((OM2ORecord) mValue).getId();\n        }\n        return mValue;\n    }\n\n    @Override\n    public void setEditable(Boolean editable) {\n        mEditable = editable;\n        initControl();\n    }\n\n    @Override\n    public Boolean isEditable() {\n        return mEditable;\n    }\n\n    public void setWidgetType(OField.WidgetType type) {\n        mWidget = type;\n        initControl();\n    }\n\n    public void setArrayResourceId(int res_id) {\n        mResourceArray = res_id;\n    }\n\n    public void setColumn(OColumn col) {\n        mCol = col;\n        if (mCol != null && mLabel == null) {\n            mLabel = mCol.getLabel();\n        }\n    }\n\n    private ODataRow getRecordData(int row_id) {\n        ODataRow row;\n        if (row_id > 0) {\n            OModel rel_model = mModel.createInstance(mCol.getType());\n            row = rel_model.browse(row_id);\n        } else {\n            row = items.get(0);\n        }\n        return row;\n    }\n\n    private class SpinnerAdapter extends ArrayAdapter<ODataRow> {\n\n        public SpinnerAdapter(Context context, int resource,\n                              List<ODataRow> objects) {\n            super(context, resource, objects);\n        }\n\n        public View getView(int position, View convertView, ViewGroup parent) {\n            return generateView(position, convertView, parent);\n        }\n\n        @Override\n        public View getDropDownView(int position, View convertView,\n                                    ViewGroup parent) {\n            return generateView(position, convertView, parent);\n        }\n\n        private View generateView(int position, View convertView,\n                                  ViewGroup parent) {\n            View v = convertView;\n            if (v == null)\n                v = LayoutInflater.from(mContext).inflate(\n                        android.R.layout.simple_list_item_1, parent, false);\n            ODataRow row = getItem(position);\n            OControls.setText(v, android.R.id.text1, row.getString(mModel.getDefaultNameColumn()));\n            return v;\n        }\n    }\n\n    @Override\n    public void onItemSelected(AdapterView<?> parent, View view, int position,\n                               long id) {\n        if (mResourceArray != -1) {\n            mValue = position;\n        } else if (mCol.getType().isAssignableFrom(OSelection.class)) {\n            ODataRow row = mAdapter.getItem(position);\n            mValue = row.getString(\"key\");\n        } else {\n            mValue = items.get(position).get(OColumn.ROW_ID);\n        }\n        setValue(mValue);\n    }\n\n    @Override\n    public void onNothingSelected(AdapterView<?> parent) {\n        mValue = null;\n    }\n\n    @Override\n    public void setLabelText(String label) {\n        mLabel = label;\n    }\n\n    @Override\n    public String getLabel() {\n        if (mLabel != null)\n            return mLabel;\n        if (mCol != null)\n            return mCol.getLabel();\n        return \"unknown\";\n    }\n\n    private AlertDialog createSelectionDialog(final int selected_position,\n                                              final List<ODataRow> items, LayoutParams params) {\n        final AlertDialog.Builder builder = new AlertDialog.Builder(mContext);\n        ListView dialogView = new ListView(mContext);\n        dialogView.setAdapter(mAdapter);\n        dialogView.setOnItemClickListener(this);\n        dialogView.setLayoutParams(params);\n        builder.setView(dialogView);\n        return builder.create();\n    }\n\n    @Override\n    public void onItemClick(AdapterView<?> parent, View view, int position,\n                            long id) {\n        setValue(position);\n    }\n\n    BroadcastReceiver valueReceiver = new BroadcastReceiver() {\n\n        @Override\n        public void onReceive(Context context, Intent intent) {\n            setValue(intent.getIntExtra(\"selected_position\", -1));\n            mContext.unregisterReceiver(valueReceiver);\n        }\n    };\n\n    public void setModel(OModel model) {\n        mModel = model;\n    }\n\n    public static List<ODataRow> getRecordItems(OModel model, OColumn column) {\n        List<ODataRow> items = new ArrayList<ODataRow>();\n\n        OModel rel_model = model.createInstance(column.getType());\n        StringBuffer whr = new StringBuffer();\n        List<Object> args_list = new ArrayList<Object>();\n        // Skipping onchange domain filter\n        if (!column.hasDomainFilterColumn()) {\n            for (String key : column.getDomains().keySet()) {\n                OColumn.ColumnDomain domain = column.getDomains().get(key);\n                if (domain.getConditionalOperator() != null) {\n                    whr.append(domain.getConditionalOperator());\n                } else {\n                    whr.append(\" \");\n                    whr.append(domain.getColumn());\n                    whr.append(\" \");\n                    whr.append(domain.getOperator());\n                    whr.append(\" ? \");\n                    args_list.add(domain.getValue().toString());\n                }\n            }\n        }\n        String where = null;\n        String[] args = null;\n        if (args_list.size() > 0) {\n            where = whr.toString();\n            args = args_list.toArray(new String[args_list.size()]);\n        }\n        List<ODataRow> rows = new ArrayList<>();\n        rows = rel_model.select(new String[]{rel_model.getDefaultNameColumn()}, where,\n                args, rel_model.getDefaultNameColumn());\n        ODataRow row = new ODataRow();\n        row.put(OColumn.ROW_ID, -1);\n        row.put(rel_model.getDefaultNameColumn(), \"No \" + column.getLabel() + \" selected\");\n        items.add(row);\n        items.addAll(rows);\n        return items;\n    }\n\n    @Override\n    public void setValueUpdateListener(ValueUpdateListener listener) {\n        mValueUpdateListener = listener;\n    }\n\n    @Override\n    public void onCheckedChanged(RadioGroup group, int checkedId) {\n        int index = mRadioGroup.indexOfChild(group.findViewById(checkedId));\n        ODataRow row = items.get(index);\n        setValue(row.getInt(OColumn.ROW_ID));\n    }\n\n    @Override\n    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {\n        super.onMeasure(widthMeasureSpec, heightMeasureSpec);\n        mReady = true;\n    }\n\n    @Override\n    public Boolean isControlReady() {\n        return mReady;\n    }\n\n    @Override\n    public void resetData() {\n        if (isEditable()) {\n            if (mWidget == null) {\n                if (mAdapter != null) {\n                    createItems();\n                    mAdapter.notifyDataSetChanged();\n                }\n            } else {\n                switch (mWidget) {\n                    case SelectionDialog:\n                        createItems();\n                        break;\n                    case RadioGroup:\n                        createItems();\n                        createRadioGroup();\n                        break;\n                    case Searchable:\n                    case SearchableLive:\n                        break;\n                    default:\n                        break;\n                }\n            }\n        }\n    }\n\n    public void setResource(float textSize, int appearance, int color) {\n        this.textSize = textSize;\n        this.appearance = appearance;\n        this.textColor = color;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/odoo/controls/SearchableItemActivity.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 7/1/15 5:11 PM\n */\npackage odoo.controls;\n\nimport android.app.AlertDialog;\nimport android.app.ProgressDialog;\nimport android.content.Intent;\nimport android.graphics.Color;\nimport android.os.AsyncTask;\nimport android.os.Bundle;\nimport android.support.v7.app.ActionBarActivity;\nimport android.text.Editable;\nimport android.text.TextWatcher;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.AdapterView;\nimport android.widget.EditText;\nimport android.widget.ImageView;\nimport android.widget.ListView;\n\nimport com.odoo.core.orm.ODataRow;\nimport com.odoo.core.orm.OModel;\nimport com.odoo.core.orm.ServerDataHelper;\nimport com.odoo.core.orm.fields.OColumn;\nimport com.odoo.core.support.OdooFields;\nimport com.odoo.core.support.list.OListAdapter;\nimport com.odoo.core.utils.OControls;\nimport com.odoo.core.utils.OResource;\nimport com.odoo.R;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport odoo.ODomain;\n\npublic class SearchableItemActivity extends ActionBarActivity implements\n        AdapterView.OnItemClickListener, TextWatcher, View.OnClickListener,\n        OListAdapter.OnSearchChange, IOnQuickRecordCreateListener {\n    public static final String TAG = SearchableItemActivity.class.getSimpleName();\n\n    private EditText edt_searchable_input;\n    private ListView mList = null;\n    private OListAdapter mAdapter;\n    private List<Object> objects = new ArrayList<>();\n    private int selected_position = -1;\n    private Boolean mLiveSearch = false;\n    private int resource_array_id = -1;\n    private OModel mModel = null;\n    private OModel mRelModel = null;\n    private Integer mRowId = null;\n    private LiveSearch mLiveDataLoader = null;\n    private OColumn mCol = null;\n    private AlertDialog.Builder builder;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.base_control_searchable_layout);\n        setResult(RESULT_CANCELED);\n        edt_searchable_input = (EditText) findViewById(R.id.edt_searchable_input);\n        edt_searchable_input.addTextChangedListener(this);\n        Bundle extra = getIntent().getExtras();\n        if (extra != null) {\n            if (extra.containsKey(\"resource_id\")) {\n                resource_array_id = extra.getInt(\"resource_id\");\n            }\n            if (extra.containsKey(OColumn.ROW_ID)) {\n                mRowId = extra.getInt(OColumn.ROW_ID);\n            }\n            if (extra.containsKey(\"model\")) {\n                mModel = OModel.get(this, extra.getString(\"model\"), null);\n            }\n            if (extra.containsKey(\"live_search\")) {\n                mLiveSearch = extra.getBoolean(\"live_search\");\n            }\n            if (extra.containsKey(\"selected_position\")) {\n                selected_position = extra.getInt(\"selected_position\");\n            }\n            if (extra.containsKey(\"search_hint\")) {\n                edt_searchable_input.setHint(\"Search \"\n                        + extra.getString(\"search_hint\"));\n            }\n            if (resource_array_id != -1) {\n                String[] arrays = getResources().getStringArray(\n                        resource_array_id);\n                for (int i = 0; i < arrays.length; i++) {\n                    ODataRow row = new ODataRow();\n                    row.put(OColumn.ROW_ID, i);\n                    row.put(mRelModel.getDefaultNameColumn(), arrays[i]);\n                    objects.add(row);\n                }\n            } else {\n                if (extra.containsKey(\"column_name\")) {\n                    mCol = mModel.getColumn(extra.getString(\"column_name\"));\n                    mRelModel = mModel.createInstance(mCol.getType());\n                    objects.addAll(OSelectionField.getRecordItems(mRelModel,\n                            mCol));\n                }\n            }\n\n            mList = (ListView) findViewById(R.id.searchable_items);\n            mList.setOnItemClickListener(this);\n            mAdapter = new OListAdapter(this,\n                    android.R.layout.simple_expandable_list_item_1, objects) {\n                @Override\n                public View getView(int position, View convertView,\n                                    ViewGroup parent) {\n                    View v = convertView;\n                    if (v == null)\n                        v = getLayoutInflater().inflate(getResource(), parent,\n                                false);\n                    ODataRow row = (ODataRow) objects.get(position);\n                    OControls.setText(v, android.R.id.text1,\n                            row.getString(mRelModel.getDefaultNameColumn()));\n                    if (row.contains(OColumn.ROW_ID)\n                            && selected_position == row.getInt(OColumn.ROW_ID)) {\n                        v.setBackgroundColor(getResources().getColor(\n                                R.color.control_pressed));\n                    } else {\n                        v.setBackgroundColor(Color.TRANSPARENT);\n                    }\n                    return v;\n                }\n            };\n            if (mLiveSearch) {\n                mAdapter.setOnSearchChange(this);\n            }\n            mList.setAdapter(mAdapter);\n        } else {\n            finish();\n        }\n    }\n\n    @Override\n    public void onItemClick(AdapterView<?> parent, View view, int position,\n                            long id) {\n        ODataRow data = (ODataRow) objects.get(position);\n        if (!data.contains(OColumn.ROW_ID)) {\n            QuickCreateRecordProcess quickCreateRecordProcess = new QuickCreateRecordProcess(this);\n            quickCreateRecordProcess.execute(data);\n        } else {\n            onRecordCreated(data);\n        }\n    }\n\n    @Override\n    public void onRecordCreated(ODataRow row) {\n        Intent intent = new Intent(\"searchable_value_select\");\n        intent.putExtra(\"selected_position\", row.getInt(OColumn.ROW_ID));\n        if (mRowId != null) {\n            intent.putExtra(\"record_id\", true);\n        }\n        sendBroadcast(intent);\n        finish();\n    }\n\n    @Override\n    public void beforeTextChanged(CharSequence s, int start, int count,\n                                  int after) {\n\n    }\n\n    @Override\n    public void onTextChanged(CharSequence s, int start, int before, int count) {\n        mAdapter.getFilter().filter(s);\n        ImageView imgView = (ImageView) findViewById(R.id.search_icon);\n        if (s.length() > 0) {\n            imgView.setImageResource(R.drawable.ic_action_navigation_close);\n            imgView.setOnClickListener(this);\n            imgView.setClickable(true);\n        } else {\n            imgView.setClickable(false);\n            imgView.setImageResource(R.drawable.ic_action_search);\n            imgView.setOnClickListener(null);\n        }\n    }\n\n    @Override\n    public void afterTextChanged(Editable s) {\n\n    }\n\n    @Override\n    public void onClick(View v) {\n        setResult(RESULT_CANCELED);\n        finish();\n    }\n\n    @Override\n    public void onSearchChange(List<Object> newRecords) {\n        if (newRecords.size() <= 0) {\n            if (mLiveDataLoader != null)\n                mLiveDataLoader.cancel(true);\n            if (edt_searchable_input.getText().length() >= 3) {\n                mLiveDataLoader = new LiveSearch();\n                mLiveDataLoader.execute(edt_searchable_input.getText()\n                        .toString());\n            }\n        }\n    }\n\n\n    private class LiveSearch extends AsyncTask<String, Void, List<ODataRow>> {\n\n        @Override\n        protected void onPreExecute() {\n            super.onPreExecute();\n            findViewById(R.id.loading_progress).setVisibility(View.VISIBLE);\n            mList.setVisibility(View.GONE);\n        }\n\n        @Override\n        protected List<ODataRow> doInBackground(String... params) {\n            try {\n                ServerDataHelper helper = mRelModel.getServerDataHelper();\n                ODomain domain = new ODomain();\n                domain.add(mRelModel.getDefaultNameColumn(), \"ilike\", params[0]);\n                if (mCol != null) {\n                    for (String key : mCol.getDomains().keySet()) {\n                        OColumn.ColumnDomain dom = mCol.getDomains().get(key);\n                        domain.add(dom.getColumn(), dom.getOperator(),\n                                dom.getValue());\n                    }\n                }\n                OdooFields fields = new OdooFields(mRelModel.getColumns());\n                return helper.searchRecords(fields, domain, 10);\n            } catch (Exception e) {\n                e.printStackTrace();\n            }\n            return null;\n        }\n\n        @Override\n        protected void onPostExecute(List<ODataRow> result) {\n            super.onPostExecute(result);\n            findViewById(R.id.loading_progress).setVisibility(View.GONE);\n            mList.setVisibility(View.VISIBLE);\n            if (result != null && result.size() > 0) {\n                objects.addAll(result);\n                mAdapter.notifiyDataChange(objects);\n            }\n        }\n\n        @Override\n        protected void onCancelled() {\n            super.onCancelled();\n            findViewById(R.id.loading_progress).setVisibility(View.GONE);\n            mList.setVisibility(View.VISIBLE);\n        }\n    }\n\n    private class QuickCreateRecordProcess extends AsyncTask<ODataRow, Void, ODataRow> {\n\n        private ProgressDialog progressDialog;\n        IOnQuickRecordCreateListener mOnQuickRecordCreateListener = null;\n\n        public QuickCreateRecordProcess(IOnQuickRecordCreateListener listener) {\n            mOnQuickRecordCreateListener = listener;\n        }\n\n        @Override\n        protected void onPreExecute() {\n            super.onPreExecute();\n            progressDialog = new ProgressDialog(SearchableItemActivity.this);\n            progressDialog.setTitle(R.string.title_please_wait);\n            progressDialog.setMessage(OResource.string(SearchableItemActivity.this, R.string.title_working));\n            progressDialog.setCancelable(false);\n            progressDialog.show();\n        }\n\n        @Override\n        protected ODataRow doInBackground(ODataRow... params) {\n            try {\n                Thread.sleep(700);\n                return mRelModel.quickCreateRecord(params[0]);\n            } catch (Exception e) {\n                e.printStackTrace();\n            }\n            return null;\n        }\n\n        @Override\n        protected void onPostExecute(ODataRow data) {\n            super.onPostExecute(data);\n            if (data != null && mOnQuickRecordCreateListener != null) {\n                mOnQuickRecordCreateListener.onRecordCreated(data);\n            }\n            progressDialog.dismiss();\n        }\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/odoo/controls/fab/DirectionScrollListener.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 9/1/15 2:24 PM\n */\npackage odoo.controls.fab;\n\nimport android.view.View;\nimport android.widget.AbsListView;\n\npublic class DirectionScrollListener implements AbsListView.OnScrollListener {\n    public static final String TAG = DirectionScrollListener.class.getSimpleName();\n    private static final int DIRECTION_CHANGE_THRESHOLD = 1;\n    private final FloatingActionButton mFloatingActionButton;\n    private int mPrevPosition;\n    private int mPrevTop;\n    private boolean mUpdated;\n\n    DirectionScrollListener(FloatingActionButton floatingActionButton) {\n        mFloatingActionButton = floatingActionButton;\n    }\n\n    @Override\n    public void onScroll(AbsListView view, int firstVisibleItem,\n                         int visibleItemCount, int totalItemCount) {\n        final View topChild = view.getChildAt(0);\n        int firstViewTop = 0;\n        if (topChild != null) {\n            firstViewTop = topChild.getTop();\n        }\n        boolean goingDown;\n        boolean changed = true;\n        if (mPrevPosition == firstVisibleItem) {\n            final int topDelta = mPrevTop - firstViewTop;\n            goingDown = firstViewTop < mPrevTop;\n            changed = Math.abs(topDelta) > DIRECTION_CHANGE_THRESHOLD;\n        } else {\n            goingDown = firstVisibleItem > mPrevPosition;\n        }\n        if (changed && mUpdated) {\n            mFloatingActionButton.hide(goingDown);\n        }\n        mPrevPosition = firstVisibleItem;\n        mPrevTop = firstViewTop;\n        mUpdated = true;\n    }\n\n    @Override\n    public void onScrollStateChanged(AbsListView view, int scrollState) {\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/odoo/controls/fab/FloatingActionButton.java",
    "content": "/**\n * Odoo, Open Source Management Solution\n * Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Affero General Public License for more details\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http:www.gnu.org/licenses/>\n *\n * Created on 9/1/15 2:25 PM\n */\npackage odoo.controls.fab;\n\nimport android.animation.ObjectAnimator;\nimport android.content.Context;\nimport android.content.res.TypedArray;\nimport android.graphics.Bitmap;\nimport android.graphics.Canvas;\nimport android.graphics.Color;\nimport android.graphics.Paint;\nimport android.graphics.Point;\nimport android.graphics.drawable.BitmapDrawable;\nimport android.graphics.drawable.Drawable;\nimport android.util.AttributeSet;\nimport android.view.Display;\nimport android.view.MotionEvent;\nimport android.view.View;\nimport android.view.WindowManager;\nimport android.view.animation.AccelerateDecelerateInterpolator;\nimport android.view.animation.Interpolator;\nimport android.widget.AbsListView;\n\nimport com.odoo.R;\n\npublic class FloatingActionButton extends View {\n    public static final String TAG = FloatingActionButton.class.getSimpleName();\n    private final Interpolator mInterpolator = new AccelerateDecelerateInterpolator();\n    private final Paint mButtonPaint = new Paint(Paint.ANTI_ALIAS_FLAG);\n    private final Paint mDrawablePaint = new Paint(Paint.ANTI_ALIAS_FLAG);\n    private Bitmap mBitmap;\n    private int mColor;\n    private boolean mHidden = false;\n    /**\n     * The FAB button's Y position when it is displayed.\n     */\n    private float mYDisplayed = -1;\n    /**\n     * The FAB button's Y position when it is hidden.\n     */\n    private float mYHidden = -1;\n\n    public FloatingActionButton(Context context) {\n        this(context, null);\n    }\n\n    public FloatingActionButton(Context context, AttributeSet attributeSet) {\n        this(context, attributeSet, 0);\n    }\n\n    public FloatingActionButton(Context context, AttributeSet attrs,\n                                int defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n\n        TypedArray a = getContext().obtainStyledAttributes(attrs,\n                R.styleable.FloatingActionButton);\n        mColor = a.getColor(R.styleable.FloatingActionButton_fabColor,\n                Color.WHITE);\n        mButtonPaint.setStyle(Paint.Style.FILL);\n        mButtonPaint.setColor(mColor);\n        float radius, dx, dy;\n        radius = a.getFloat(R.styleable.FloatingActionButton_shadowRadius,\n                10.0f);\n        dx = a.getFloat(R.styleable.FloatingActionButton_shadowDx, 0.0f);\n        dy = a.getFloat(R.styleable.FloatingActionButton_shadowDy, 3.5f);\n        int color = a.getInteger(R.styleable.FloatingActionButton_shadowColor,\n                Color.argb(100, 0, 0, 0));\n        mButtonPaint.setShadowLayer(radius, dx, dy, color);\n\n        Drawable drawable = a\n                .getDrawable(R.styleable.FloatingActionButton_drawable);\n        if (null != drawable) {\n            mBitmap = ((BitmapDrawable) drawable).getBitmap();\n        }\n        setWillNotDraw(false);\n        setLayerType(View.LAYER_TYPE_SOFTWARE, null);\n\n        WindowManager mWindowManager = (WindowManager) context\n                .getSystemService(Context.WINDOW_SERVICE);\n        Display display = mWindowManager.getDefaultDisplay();\n        Point size = new Point();\n        display.getSize(size);\n        mYHidden = size.y;\n        a.recycle();\n    }\n\n    public void setColor(int color) {\n        mColor = color;\n        mButtonPaint.setColor(mColor);\n        invalidate();\n    }\n\n    public void setDrawable(Drawable drawable) {\n        mBitmap = ((BitmapDrawable) drawable).getBitmap();\n        invalidate();\n    }\n\n    @Override\n    protected void onDraw(Canvas canvas) {\n        canvas.drawCircle(getWidth() / 2, getHeight() / 2,\n                (float) (getWidth() / 2.6), mButtonPaint);\n        if (null != mBitmap) {\n            canvas.drawBitmap(mBitmap, (getWidth() - mBitmap.getWidth()) / 2,\n                    (getHeight() - mBitmap.getHeight()) / 2, mDrawablePaint);\n        }\n    }\n\n    @Override\n    protected void onLayout(boolean changed, int left, int top, int right,\n                            int bottom) {\n        // Perform the default behavior\n        super.onLayout(changed, left, top, right, bottom);\n\n        // Store the FAB button's displayed Y position if we are not already\n        // aware of it\n        if (mYDisplayed == -1) {\n            mYDisplayed = this.getY();\n        }\n    }\n\n    @Override\n    public boolean onTouchEvent(MotionEvent event) {\n        int color;\n        if (event.getAction() == MotionEvent.ACTION_UP) {\n            color = mColor;\n        } else {\n            color = darkenColor(mColor);\n        }\n        mButtonPaint.setColor(color);\n        invalidate();\n        return super.onTouchEvent(event);\n    }\n\n    public void hide(boolean hide) {\n        // If the hidden state is being updated\n        if (mHidden != hide) {\n\n            // Store the new hidden state\n            mHidden = hide;\n\n            // Animate the FAB to it's new Y position\n            ObjectAnimator animator = ObjectAnimator.ofFloat(this, \"Y\",\n                    mHidden ? mYHidden : mYDisplayed);\n            animator.setInterpolator(mInterpolator);\n            animator.start();\n        }\n    }\n\n    public void listenTo(AbsListView listView) {\n        if (null != listView) {\n            listView.setOnScrollListener(new DirectionScrollListener(this));\n        }\n    }\n\n    public static int darkenColor(int color) {\n        float[] hsv = new float[3];\n        Color.colorToHSV(color, hsv);\n        hsv[2] *= 0.8f;\n        return Color.HSVToColor(hsv);\n    }\n}\n"
  },
  {
    "path": "app/src/main/res/drawable/circle_mask.xml",
    "content": "<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:shape=\"oval\">\n\n    <solid android:color=\"#000\" />\n\n</shape>"
  },
  {
    "path": "app/src/main/res/drawable/circle_mask_gray.xml",
    "content": "<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:shape=\"oval\">\n\n    <solid android:color=\"#cccccc\" />\n\n</shape>"
  },
  {
    "path": "app/src/main/res/drawable/circle_mask_primary.xml",
    "content": "<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:shape=\"oval\" >\n\n    <solid android:color=\"@color/theme_primary\" />\n\n</shape>"
  },
  {
    "path": "app/src/main/res/drawable/circle_mask_secondary.xml",
    "content": "<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:shape=\"oval\" >\n\n    <solid android:color=\"@color/theme_secondary\" />\n\n</shape>"
  },
  {
    "path": "app/src/main/res/drawable/drawer_background_cover.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<bitmap xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:gravity=\"top\"\n    android:src=\"@drawable/android_cover\"\n    android:tileMode=\"clamp\">\n\n</bitmap>"
  },
  {
    "path": "app/src/main/res/drawable/icon_bg_oval_blue.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape\n    android:shape=\"oval\"\n    xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <solid android:color=\"@color/android_blue\" />\n\n</shape>\n"
  },
  {
    "path": "app/src/main/res/drawable/icon_bg_oval_green.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape\n    android:shape=\"oval\"\n    xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <solid android:color=\"@color/android_green\" />\n\n</shape>\n"
  },
  {
    "path": "app/src/main/res/drawable/icon_bg_oval_orange.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape\n    android:shape=\"oval\"\n    xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <solid android:color=\"@color/android_orange\" />\n\n</shape>\n"
  },
  {
    "path": "app/src/main/res/drawable/icon_bg_oval_red.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape\n    android:shape=\"oval\"\n    xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <solid android:color=\"@color/android_red\" />\n\n</shape>\n"
  },
  {
    "path": "app/src/main/res/drawable/icon_bg_oval_violet.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape\n    android:shape=\"oval\"\n    xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <solid android:color=\"@color/android_violet\" />\n\n</shape>\n"
  },
  {
    "path": "app/src/main/res/drawable/login_signup_button.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item android:drawable=\"@drawable/login_signup_button_clicked\" android:state_activated=\"false\" android:state_pressed=\"true\"/>\n    <item android:drawable=\"@drawable/login_signup_button_clicked\" android:state_activated=\"true\"/>\n    <item android:drawable=\"@drawable/login_signup_button_normal\"/>\n\n</selector>"
  },
  {
    "path": "app/src/main/res/drawable/login_signup_button_clicked.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layer-list xmlns:android=\"http://schemas.android.com/apk/res/android\" >\n\n    <item>\n        <shape>\n            <solid android:color=\"@color/theme_primary_dark\" />\n\n            <corners android:radius=\"2dp\" />\n        </shape>\n    </item>\n\n</layer-list>\n"
  },
  {
    "path": "app/src/main/res/drawable/login_signup_button_normal.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layer-list xmlns:android=\"http://schemas.android.com/apk/res/android\" >\n\n    <item>\n        <shape>\n            <solid android:color=\"@color/theme_primary_light\" />\n\n            <corners android:radius=\"2dp\" />\n        </shape>\n    </item>\n\n</layer-list>"
  },
  {
    "path": "app/src/main/res/drawable/login_signup_control_bg.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layer-list xmlns:android=\"http://schemas.android.com/apk/res/android\" >\n\n    <!-- Background -->\n    <item>\n        <shape>\n            <solid android:color=\"#ffffff\" />\n\n            <corners android:radius=\"2dp\" />\n        </shape>\n    </item>\n\n</layer-list>"
  },
  {
    "path": "app/src/main/res/drawable/tag_background.xml",
    "content": "<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:shape=\"rectangle\">\n    <gradient\n        android:startColor=\"@color/theme_secondary\"\n        android:endColor=\"@color/theme_secondary\" />\n\n    <corners android:radius=\"4dp\" />\n</shape>"
  },
  {
    "path": "app/src/main/res/layout/activity_app_intro.xml",
    "content": "<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\"\n    tools:context=\"com.odoo.core.account.AppIntro\"\n    android:background=\"@android:color/white\">\n\n    <View\n        android:background=\"@color/theme_primary\"\n        android:layout_height=\"@dimen/statusBarHeight\"\n        android:layout_width=\"match_parent\" />\n\n    <com.odoo.widgets.slider.SliderView\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:id=\"@+id/sliderView\">\n\n    </com.odoo.widgets.slider.SliderView>\n\n</LinearLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/base_about.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:layout_width=\"match_parent\"\n    android:orientation=\"vertical\"\n    android:layout_height=\"match_parent\">\n\n    <android.support.v7.widget.Toolbar\n        android:id=\"@+id/toolbar\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:background=\"@color/theme_primary\"\n        android:minHeight=\"?attr/actionBarSize\"\n        app:titleMarginStart=\"@dimen/default_16dp\"\n        android:paddingTop=\"@dimen/statusBarHeight\"\n        android:paddingRight=\"@dimen/default_8dp\"\n        app:popupTheme=\"@style/ThemeOverlay.AppCompat.Dark\"\n        app:theme=\"@style/ToolBarTheme\" />\n\n    <ScrollView\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:fillViewport=\"true\">\n\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:background=\"#ffffff\"\n            android:orientation=\"vertical\">\n\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:id=\"@+id/abtus_header\"\n                android:layout_height=\"250dp\"\n                android:background=\"@color/theme_primary\"\n                android:gravity=\"center\"\n                android:orientation=\"vertical\"\n                android:padding=\"20dp\">\n\n                <ImageView\n                    android:id=\"@+id/abtus_imgLogo\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"50dp\"\n                    android:layout_gravity=\"center\"\n                    android:layout_marginTop=\"20dp\"\n                    android:src=\"@drawable/odoo_small\"\n                    android:tint=\"#ffffff\" />\n\n                <TextView\n                    android:id=\"@+id/txvVersionName\"\n                    android:layout_width=\"fill_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:fontFamily=\"@string/font_condensed\"\n                    android:gravity=\"center\"\n                    android:paddingBottom=\"10dp\"\n                    android:paddingTop=\"25dp\"\n                    android:text=\"@string/app_version_name\"\n                    android:textAppearance=\"?android:attr/textAppearanceLarge\"\n                    android:textColor=\"#ebebeb\" />\n            </LinearLayout>\n\n            <LinearLayout\n                android:id=\"@+id/layoutServerConfig\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"match_parent\"\n                android:background=\"#ffffff\"\n                android:orientation=\"vertical\"\n                android:padding=\"20dp\">\n\n                <TextView\n                    android:id=\"@+id/line1\"\n                    android:layout_width=\"fill_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:fontFamily=\"@string/font_light\"\n                    android:gravity=\"left\"\n                    android:paddingBottom=\"10dp\"\n                    android:paddingTop=\"10dp\"\n                    android:text=\"@string/about_Company_line1\"\n                    android:textAppearance=\"?android:attr/textAppearanceMedium\" />\n\n                <TextView\n                    android:id=\"@+id/line2\"\n                    android:layout_width=\"fill_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:fontFamily=\"@string/font_light\"\n                    android:gravity=\"left\"\n                    android:paddingBottom=\"10dp\"\n                    android:paddingTop=\"10dp\"\n                    android:text=\"@string/about_Company_line2\"\n                    android:textAppearance=\"?android:attr/textAppearanceMedium\"\n                    android:textColorLink=\"#414141\" />\n\n                <TextView\n                    android:id=\"@+id/line3\"\n                    android:layout_width=\"fill_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:fontFamily=\"@string/font_light\"\n                    android:gravity=\"left\"\n                    android:paddingBottom=\"10dp\"\n                    android:paddingTop=\"10dp\"\n                    android:text=\"@string/about_Company_line3\"\n                    android:textAppearance=\"?android:attr/textAppearanceMedium\"\n                    android:textColorLink=\"#414141\" />\n\n                <TextView\n                    android:id=\"@+id/line4\"\n                    android:layout_width=\"fill_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:fontFamily=\"@string/font_light\"\n                    android:gravity=\"left\"\n                    android:paddingBottom=\"10dp\"\n                    android:paddingTop=\"10dp\"\n                    android:text=\"@string/about_Company_line4\"\n                    android:textAppearance=\"?android:attr/textAppearanceMedium\"\n                    android:textColorLink=\"#414141\" />\n            </LinearLayout>\n        </LinearLayout>\n\n    </ScrollView>\n</LinearLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/base_account_ask_pass.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:orientation=\"vertical\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <ImageView\n        android:id=\"@+id/userAvatar\"\n        android:scaleType=\"centerCrop\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"180dp\" />\n\n    <LinearLayout\n        android:orientation=\"vertical\"\n        android:padding=\"@dimen/default_16dp\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\">\n\n        <TextView\n            android:id=\"@+id/txvUsername\"\n            android:textAppearance=\"?android:attr/textAppearanceLarge\"\n            android:textColor=\"@color/theme_secondary_dark\"\n            android:layout_width=\"match_parent\"\n            android:layout_marginBottom=\"@dimen/default_8dp\"\n            android:fontFamily=\"@string/font_condensed\"\n            android:layout_height=\"wrap_content\" />\n\n        <EditText\n            android:id=\"@+id/edtPassword\"\n            android:textAppearance=\"?android:attr/textAppearanceLarge\"\n            android:fontFamily=\"@string/font_light\"\n            android:layout_width=\"match_parent\"\n            android:inputType=\"textPassword\"\n            android:singleLine=\"true\"\n            android:hint=\"@string/error_provide_password\"\n            android:layout_height=\"wrap_content\" />\n    </LinearLayout>\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/base_account_item.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<android.support.v7.widget.CardView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:card_view=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:elevation=\"3dp\"\n    card_view:cardCornerRadius=\"0dp\"\n    android:layout_marginBottom=\"8dp\"\n    android:layout_height=\"wrap_content\">\n\n    <LinearLayout\n        android:padding=\"@dimen/default_16dp\"\n        android:layout_width=\"match_parent\"\n        android:orientation=\"horizontal\"\n        android:layout_height=\"match_parent\">\n\n        <odoo.controls.BezelImageView\n            android:id=\"@+id/profile_image\"\n            android:layout_width=\"50dp\"\n            android:layout_height=\"50dp\"\n            android:scaleType=\"centerCrop\"\n            app:maskDrawable=\"@drawable/circle_mask\"\n            android:src=\"@drawable/avatar\" />\n\n        <LinearLayout\n            android:layout_width=\"0dp\"\n            android:layout_weight=\"1\"\n            android:layout_marginLeft=\"@dimen/default_8dp\"\n            android:orientation=\"vertical\"\n            android:layout_height=\"wrap_content\">\n\n            <TextView\n                android:id=\"@+id/accountName\"\n                android:fontFamily=\"@string/font_condensed\"\n                android:textStyle=\"bold\"\n                android:textColor=\"@color/body_text_1\"\n                android:textSize=\"@dimen/text_size_large\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\" />\n\n            <TextView\n                android:textSize=\"@dimen/text_size_medium\"\n                android:paddingBottom=\"@dimen/default_8dp\"\n                android:id=\"@+id/accountURL\"\n                android:fontFamily=\"@string/font_normal\"\n                android:textColor=\"@color/body_text_2\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\" />\n\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:orientation=\"horizontal\"\n                android:gravity=\"right\"\n                android:layout_height=\"wrap_content\">\n\n                <ImageView\n                    android:id=\"@+id/btnLogin\"\n                    android:padding=\"@dimen/default_8dp\"\n                    android:src=\"@drawable/ic_action_action_done_all\"\n                    android:background=\"@drawable/icon_bg_oval_green\"\n                    android:layout_width=\"40dp\"\n                    android:visibility=\"gone\"\n                    android:layout_marginRight=\"@dimen/default_8dp\"\n                    android:layout_height=\"40dp\" />\n\n                <ImageView\n                    android:visibility=\"gone\"\n                    android:id=\"@+id/btnLogout\"\n                    android:layout_marginRight=\"@dimen/default_8dp\"\n                    android:padding=\"@dimen/default_8dp\"\n                    android:src=\"@drawable/ic_action_logout\"\n                    android:background=\"@drawable/icon_bg_oval_orange\"\n                    android:layout_width=\"40dp\"\n                    android:layout_height=\"40dp\" />\n\n                <ImageView\n                    android:id=\"@+id/btnRemoveAccount\"\n                    android:padding=\"@dimen/default_8dp\"\n                    android:src=\"@drawable/ic_action_navigation_close\"\n                    android:background=\"@drawable/icon_bg_oval_red\"\n                    android:layout_width=\"40dp\"\n                    android:layout_height=\"40dp\" />\n            </LinearLayout>\n        </LinearLayout>\n    </LinearLayout>\n</android.support.v7.widget.CardView>"
  },
  {
    "path": "app/src/main/res/layout/base_account_quick_manage.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:orientation=\"vertical\"\n    android:layout_width=\"match_parent\"\n    android:id=\"@+id/layoutSavePassword\"\n    android:background=\"#fff\"\n    android:layout_height=\"match_parent\">\n\n    <ScrollView\n        android:layout_width=\"match_parent\"\n        android:layout_weight=\"1\"\n        android:layout_height=\"0dp\">\n\n        <LinearLayout\n            android:orientation=\"vertical\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\">\n\n            <ImageView\n                android:id=\"@+id/userAvatar\"\n                android:scaleType=\"centerCrop\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"250dp\" />\n\n            <LinearLayout\n                android:padding=\"@dimen/default_16dp\"\n                android:orientation=\"vertical\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\">\n\n                <TextView\n                    android:textColor=\"@color/body_text_2\"\n                    android:id=\"@+id/userName\"\n                    android:layout_marginBottom=\"@dimen/default_8dp\"\n                    android:textSize=\"@dimen/text_size_xlarge\"\n                    android:fontFamily=\"@string/font_condensed\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\" />\n\n                <TextView\n                    android:textColor=\"@color/body_text_3\"\n                    android:layout_marginBottom=\"@dimen/default_8dp\"\n                    android:textSize=\"@dimen/text_size_small\"\n                    android:textAllCaps=\"true\"\n                    android:text=\"New Password\"\n                    android:fontFamily=\"@string/font_normal\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\" />\n\n                <EditText\n                    android:id=\"@+id/newPassword\"\n                    android:hint=\"New Password\"\n                    android:inputType=\"textPassword\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\" />\n\n            </LinearLayout>\n        </LinearLayout>\n    </ScrollView>\n\n    <View style=\"@style/ViewSeparator\" />\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:showDividers=\"middle\"\n        android:divider=\"?android:attr/dividerVertical\"\n        android:orientation=\"horizontal\">\n\n        <Button\n            android:id=\"@+id/save_password\"\n            style=\"?android:attr/borderlessButtonStyle\"\n            android:layout_width=\"0dp\"\n            android:layout_weight=\"1\"\n            android:layout_height=\"match_parent\"\n            android:background=\"?android:selectableItemBackground\"\n            android:gravity=\"center\"\n            android:fontFamily=\"@string/font_normal\"\n            android:padding=\"@dimen/default_16dp\"\n            android:text=\"Save Password\"\n            android:textAllCaps=\"true\"\n            android:textColor=\"@color/body_text_1\"\n            android:textSize=\"@dimen/text_size_medium\" />\n\n        <Button\n            android:id=\"@+id/cancel\"\n            style=\"?android:attr/borderlessButtonStyle\"\n            android:layout_width=\"0dp\"\n            android:layout_weight=\"1\"\n            android:fontFamily=\"@string/font_normal\"\n            android:layout_height=\"match_parent\"\n            android:background=\"?android:selectableItemBackground\"\n            android:gravity=\"center\"\n            android:padding=\"@dimen/default_16dp\"\n            android:text=\"@string/label_cancel\"\n            android:textAllCaps=\"true\"\n            android:textColor=\"@color/body_text_2\"\n            android:textSize=\"@dimen/text_size_medium\" />\n    </LinearLayout>\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/base_attachment_item.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"100dp\"\n    android:layout_margin=\"2dp\"\n    android:layout_height=\"100dp\">\n\n    <ImageView\n        android:id=\"@+id/attachmentPreview\"\n        android:scaleType=\"centerCrop\"\n        android:layout_width=\"match_parent\"\n        android:src=\"@drawable/file\"\n        android:layout_height=\"match_parent\" />\n\n    <ImageView\n        android:layout_gravity=\"top|right\"\n        android:background=\"#99CC0000\"\n        android:src=\"@drawable/ic_action_navigation_close\"\n        android:id=\"@+id/btnRemoveAttachment\"\n        android:layout_width=\"wrap_content\"\n        android:padding=\"3dp\"\n        android:layout_height=\"wrap_content\" />\n\n    <TextView\n        android:id=\"@+id/attachmentFileName\"\n        android:layout_gravity=\"bottom\"\n        android:textColor=\"#ffffff\"\n        android:padding=\"4dp\"\n        android:background=\"#99000000\"\n        android:singleLine=\"true\"\n        android:ellipsize=\"middle\"\n        android:fontFamily=\"@string/font_condensed\"\n        android:textAppearance=\"?android:attr/textAppearanceSmall\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\" />\n</FrameLayout>"
  },
  {
    "path": "app/src/main/res/layout/base_control_searchable_layout.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:layout_marginTop=\"@dimen/statusBarHeight\"\n    android:background=\"#ebebeb\"\n    android:orientation=\"vertical\">\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"56dp\"\n        android:background=\"#ffffff\"\n        android:orientation=\"horizontal\"\n        android:paddingLeft=\"0dp\"\n        android:paddingRight=\"16dp\">\n\n        <ImageView\n            android:id=\"@+id/search_icon\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"match_parent\"\n            android:layout_gravity=\"center\"\n            android:background=\"?android:attr/selectableItemBackground\"\n            android:paddingLeft=\"16dp\"\n            android:paddingRight=\"16dp\"\n            android:src=\"@drawable/ic_action_search\"\n            android:tint=\"#414141\" />\n\n        <EditText\n            android:id=\"@+id/edt_searchable_input\"\n            android:layout_width=\"0dp\"\n            android:layout_height=\"match_parent\"\n            android:layout_weight=\"1\"\n            android:background=\"@android:color/transparent\"\n            android:ellipsize=\"end\"\n            android:fontFamily=\"@string/font_normal\"\n            android:gravity=\"center_vertical\"\n            android:hint=\"Search\"\n            android:singleLine=\"true\"\n            android:textAppearance=\"?android:attr/textAppearanceMedium\">\n\n            <requestFocus />\n        </EditText>\n    </LinearLayout>\n\n    <View style=\"@style/ViewSeparator\" />\n\n    <include\n        android:id=\"@+id/loading_progress\"\n        layout=\"@layout/listview_data_loading_progress\"\n        android:visibility=\"gone\" />\n\n    <ListView\n        android:id=\"@+id/searchable_items\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"></ListView>\n\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/base_control_template.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"horizontal\"\n    android:paddingBottom=\"12dp\"\n    android:paddingLeft=\"16dp\"\n    android:paddingRight=\"16dp\"\n    android:paddingTop=\"12dp\">\n\n    <ImageView\n        android:id=\"@android:id/icon\"\n        android:layout_width=\"32dp\"\n        android:layout_height=\"32dp\"\n        android:layout_marginRight=\"24dp\" />\n\n    <LinearLayout\n        android:id=\"@+id/control_container\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:gravity=\"center_vertical\"\n        android:orientation=\"vertical\"></LinearLayout>\n\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/base_drawer.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<com.odoo.core.utils.drawer.ODrawerScrollView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:id=\"@+id/navDrawer\"\n    android:layout_width=\"@dimen/drawerDefaultWidth\"\n    app:insetForeground=\"#4000\"\n    android:fillViewport=\"true\"\n    android:background=\"@color/drawerDefaultBackgroundColor\"\n    android:layout_gravity=\"start|left\"\n    android:fitsSystemWindows=\"@bool/fitToScreenWindow\"\n    android:layout_height=\"match_parent\">\n\n    <LinearLayout\n        android:clipToPadding=\"false\"\n        android:paddingTop=\"@dimen/statusBarHeight\"\n        android:background=\"@drawable/drawer_background_cover\"\n        android:orientation=\"vertical\"\n        android:fitsSystemWindows=\"@bool/fitToScreenWindow\"\n        android:layout_width=\"match_parent\"\n\n        android:layout_height=\"match_parent\">\n\n        <!-- Account View -->\n        <FrameLayout\n            android:id=\"@+id/drawerAccountView\"\n            android:foreground=\"?android:attr/selectableItemBackground\"\n            android:paddingLeft=\"16dp\"\n            android:paddingRight=\"16dp\"\n            android:paddingTop=\"16dp\"\n            android:paddingBottom=\"@dimen/drawerAccountBottomPadding\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\">\n\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:orientation=\"vertical\">\n\n                <odoo.controls.BezelImageView\n                    android:id=\"@+id/profile_image\"\n                    android:layout_width=\"@dimen/drawerAvatarWidthHeight\"\n                    android:layout_height=\"@dimen/drawerAvatarWidthHeight\"\n                    android:scaleType=\"centerCrop\"\n                    android:src=\"@drawable/avatar\"\n                    app:maskDrawable=\"@drawable/circle_mask\" />\n\n                <LinearLayout\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"56dp\"\n                    android:layout_marginBottom=\"5dp\"\n                    android:gravity=\"bottom\"\n                    android:orientation=\"vertical\"\n                    android:paddingTop=\"16dp\">\n\n                    <TextView\n                        android:id=\"@+id/profile_name_text\"\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"wrap_content\"\n                        android:ellipsize=\"end\"\n                        android:fontFamily=\"@string/font_normal\"\n                        android:singleLine=\"true\"\n                        android:textColor=\"@color/body_text_1_inverse\"\n                        android:textSize=\"@dimen/text_size_medium\"\n                        android:textStyle=\"bold\" />\n\n                    <LinearLayout\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"wrap_content\"\n                        android:orientation=\"horizontal\">\n\n                        <TextView\n                            android:id=\"@+id/profile_url_text\"\n                            android:layout_width=\"0dp\"\n                            android:layout_height=\"wrap_content\"\n                            android:layout_weight=\"1\"\n                            android:ellipsize=\"middle\"\n                            android:maxLines=\"1\"\n                            android:singleLine=\"true\"\n                            android:textColor=\"@color/body_text_1_inverse\"\n                            android:textSize=\"@dimen/text_size_medium\" />\n\n                        <ImageView\n                            android:id=\"@+id/expand_account_box_indicator\"\n                            android:layout_width=\"wrap_content\"\n                            android:layout_height=\"wrap_content\"\n                            android:scaleType=\"center\"\n                            android:src=\"@drawable/ic_drawer_accounts_expand\"\n                            android:tint=\"@android:color/white\"\n                            android:visibility=\"gone\" />\n                    </LinearLayout>\n                </LinearLayout>\n            </LinearLayout>\n        </FrameLayout>\n\n        <!-- Drawer Item Layout -->\n        <FrameLayout\n            android:layout_width=\"match_parent\"\n            android:layout_weight=\"1\"\n            android:background=\"@color/drawer_background\"\n            android:layout_height=\"0dp\">\n\n            <View\n                android:layout_width=\"match_parent\"\n                android:layout_marginTop=\"8dp\"\n                android:layout_height=\"1dp\" />\n            <!-- Account Items -->\n            <LinearLayout\n                android:id=\"@+id/accountList\"\n                android:layout_width=\"match_parent\"\n                android:orientation=\"vertical\"\n                android:visibility=\"invisible\"\n                android:background=\"@color/drawer_background\"\n                android:layout_height=\"wrap_content\">\n                <!-- Account added runtime  -->\n            </LinearLayout>\n\n            <!-- Drawer Items -->\n            <LinearLayout\n                android:background=\"@color/drawer_background\"\n                android:id=\"@+id/drawerItemList\"\n                android:layout_marginTop=\"8dp\"\n                android:layout_marginBottom=\"8dp\"\n                android:layout_width=\"match_parent\"\n                android:orientation=\"vertical\"\n                android:layout_height=\"wrap_content\">\n                <!--Drawer item added runtime -->\n            </LinearLayout>\n        </FrameLayout>\n    </LinearLayout>\n</com.odoo.core.utils.drawer.ODrawerScrollView>"
  },
  {
    "path": "app/src/main/res/layout/base_drawer_account_item.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:background=\"?android:selectableItemBackground\"\n    android:clickable=\"true\"\n    android:padding=\"@dimen/default_16dp\"\n    android:orientation=\"horizontal\"\n    android:focusable=\"true\">\n\n    <odoo.controls.BezelImageView\n        android:id=\"@+id/profile_image\"\n        android:layout_width=\"34dp\"\n        android:layout_height=\"34dp\"\n        android:layout_gravity=\"center_vertical\"\n        android:scaleType=\"centerCrop\"\n        android:layout_marginRight=\"@dimen/default_8dp\"\n        android:src=\"@drawable/avatar\"\n        app:maskDrawable=\"@drawable/circle_mask\" />\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:orientation=\"vertical\"\n        android:gravity=\"center_vertical\"\n        android:layout_gravity=\"center_vertical\"\n        android:layout_height=\"wrap_content\">\n\n        <TextView\n            android:id=\"@+id/profile_name_text\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"center_vertical\"\n            android:ellipsize=\"end\"\n            android:fontFamily=\"@string/font_light\"\n            android:singleLine=\"true\"\n            android:textColor=\"@color/body_text_1\"\n            android:textSize=\"@dimen/text_size_medium\" />\n\n        <TextView\n            android:id=\"@+id/profile_url_text\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"center_vertical\"\n            android:ellipsize=\"end\"\n            android:fontFamily=\"@string/font_light\"\n            android:singleLine=\"true\"\n            android:textColor=\"@color/body_text_2\"\n            android:textSize=\"@dimen/text_size_medium\" />\n    </LinearLayout>\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/base_drawer_group_layout.xml",
    "content": "<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n    <View\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"1dp\"\n        android:layout_marginTop=\"@dimen/default_8dp\"\n        android:background=\"@color/drawer_separator_background\"\n        android:gravity=\"start|center_vertical\" />\n\n    <TextView\n        android:id=\"@+id/group_title\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"48dp\"\n        android:fontFamily=\"@string/font_normal\"\n        android:gravity=\"center_vertical\"\n        android:paddingLeft=\"@dimen/default_16dp\"\n        android:singleLine=\"true\"\n        android:textAllCaps=\"true\"\n        android:textColor=\"@color/drawer_separator_text_color\"\n        android:textSize=\"@dimen/text_size_small\"\n        android:textStyle=\"bold\" />\n\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/base_drawer_menu_item.xml",
    "content": "<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"48dp\"\n    android:background=\"?android:selectableItemBackground\"\n    android:gravity=\"start|center_vertical\"\n    android:orientation=\"horizontal\"\n    android:paddingLeft=\"@dimen/default_16dp\"\n    android:clickable=\"true\"\n    android:paddingRight=\"@dimen/default_16dp\">\n\n    <ImageView\n        android:id=\"@+id/icon\"\n        android:tint=\"@color/drawer_icon_tint\"\n        android:layout_width=\"32dp\"\n        android:layout_marginRight=\"24dp\"\n        android:layout_height=\"32dp\" />\n\n    <TextView\n        android:id=\"@+id/title\"\n        android:layout_width=\"0dp\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"start|center_vertical\"\n        android:layout_weight=\"1\"\n        android:singleLine=\"true\"\n        android:fontFamily=\"@string/font_normal\"\n        android:textColor=\"@color/drawer_text_color\"\n        android:gravity=\"start|center_vertical\"\n        android:textSize=\"@dimen/text_size_medium\" />\n\n    <TextView\n        android:textColor=\"@color/drawer_text_color\"\n        android:id=\"@+id/counter\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"end|center_vertical\"\n        android:fontFamily=\"@string/font_normal\"\n        android:gravity=\"start|center_vertical\"\n        android:textSize=\"@dimen/text_size_medium\" />\n\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/base_instance_item.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:background=\"?attr/selectableItemBackground\"\n    android:gravity=\"center_horizontal\"\n    android:orientation=\"vertical\"\n    android:padding=\"5dp\">\n\n    <odoo.controls.BezelImageView\n        android:id=\"@+id/imgInstance\"\n        android:layout_width=\"48dp\"\n        android:layout_gravity=\"center_horizontal\"\n        android:layout_height=\"48dp\"\n        android:scaleType=\"fitCenter\" />\n\n    <TextView\n        android:id=\"@+id/txvInstanceName\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginTop=\"5dp\"\n        android:fontFamily=\"@string/font_condensed\"\n        android:gravity=\"center\"\n        android:singleLine=\"true\"\n        android:textAppearance=\"?android:attr/textAppearanceMedium\"\n        android:textColor=\"#414141\" />\n\n    <TextView\n        android:id=\"@+id/txvInstanceUrl\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginTop=\"5dp\"\n        android:fontFamily=\"@string/font_light\"\n        android:gravity=\"center\"\n        android:singleLine=\"true\"\n        android:textAppearance=\"?android:attr/textAppearanceSmall\"\n        android:textColor=\"#414141\" />\n\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/base_intro_slider_view.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:orientation=\"vertical\"\n    android:padding=\"@dimen/default_16dp\"\n    android:layout_width=\"match_parent\"\n    android:gravity=\"center_horizontal\"\n    android:layout_height=\"match_parent\">\n\n    <TextView\n        android:layout_marginTop=\"25dp\"\n        android:id=\"@+id/big_title\"\n        android:fontFamily=\"@string/font_light\"\n        android:gravity=\"center\"\n        android:textColor=\"@color/body_text_2\"\n        android:textSize=\"@dimen/text_size_xxlarge\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\" />\n\n    <ImageView\n        android:id=\"@+id/slider_image\"\n        android:layout_marginTop=\"25dp\"\n        android:layout_gravity=\"center\"\n        android:layout_width=\"250dp\"\n        android:layout_height=\"250dp\" />\n\n    <TextView\n        android:layout_marginTop=\"25dp\"\n        android:id=\"@+id/sub_title\"\n        android:fontFamily=\"@string/font_condensed\"\n        android:gravity=\"center\"\n        android:textStyle=\"bold\"\n        android:textColor=\"@color/theme_primary\"\n        android:textSize=\"@dimen/text_size_xlarge\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\" />\n\n    <TextView\n        android:layout_marginTop=\"@dimen/default_16dp\"\n        android:id=\"@+id/description\"\n        android:gravity=\"center\"\n        android:fontFamily=\"@string/font_normal\"\n        android:textColor=\"@color/body_text_2\"\n        android:textSize=\"@dimen/text_size_large\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\" />\n\n    <Button\n        android:visibility=\"gone\"\n        android:layout_marginTop=\"@dimen/default_16dp\"\n        android:id=\"@+id/btnSliderFinish\"\n        android:textColor=\"#ffffff\"\n        android:textAllCaps=\"true\"\n        android:textStyle=\"bold\"\n        android:paddingLeft=\"@dimen/default_16dp\"\n        android:paddingRight=\"@dimen/default_16dp\"\n        android:background=\"@color/theme_primary\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\" />\n\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/base_login.xml",
    "content": "<ScrollView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:background=\"@color/theme_primary\"\n    android:paddingTop=\"@dimen/statusBarHeight\"\n    android:fillViewport=\"true\">\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:paddingTop=\"@dimen/activity_vertical_margin\"\n        android:paddingBottom=\"@dimen/activity_vertical_margin\"\n        android:paddingLeft=\"@dimen/activity_horizontal_margin\"\n        android:orientation=\"vertical\"\n        android:gravity=\"center_horizontal\"\n        android:paddingRight=\"@dimen/activity_horizontal_margin\">\n\n        <ImageView\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginBottom=\"40dp\"\n            android:layout_marginTop=\"40dp\"\n            android:src=\"@drawable/odoo_small\"\n            android:tint=\"#ffffff\" />\n\n        <LinearLayout\n            android:id=\"@+id/controls\"\n            android:layout_width=\"match_parent\"\n            android:orientation=\"vertical\"\n            android:layout_height=\"wrap_content\">\n\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:background=\"@drawable/login_signup_control_bg\"\n                android:orientation=\"vertical\">\n\n                <!-- Self Hosted URL Input -->\n                <LinearLayout\n                    android:id=\"@+id/layoutSelfHosted\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:gravity=\"center_horizontal\"\n                    android:orientation=\"horizontal\"\n                    android:padding=\"10dp\"\n                    android:visibility=\"gone\">\n\n                    <ImageView\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"wrap_content\"\n                        android:layout_gravity=\"center_vertical\"\n                        android:layout_marginRight=\"5dp\"\n                        android:src=\"@drawable/ic_action_universe\"\n                        android:tint=\"@color/body_text_3\" />\n\n                    <EditText\n                        android:id=\"@+id/edtSelfHostedURL\"\n                        android:layout_width=\"0dp\"\n                        android:layout_height=\"match_parent\"\n                        android:layout_gravity=\"center_vertical\"\n                        android:layout_weight=\"1\"\n                        android:background=\"#ffffff\"\n                        android:fontFamily=\"@string/font_light\"\n                        android:gravity=\"center_vertical\"\n                        android:hint=\"@string/label_your_self_hosted_url\"\n                        android:singleLine=\"true\"\n                        android:textAppearance=\"?android:attr/textAppearanceMedium\"\n                        android:textColorHint=\"@color/body_text_3\" />\n\n                    <ProgressBar\n                        android:id=\"@+id/serverURLCheckProgress\"\n                        android:layout_width=\"24dp\"\n                        android:layout_height=\"24dp\"\n                        android:layout_gravity=\"center_vertical\"\n                        android:visibility=\"gone\" />\n\n                    <ImageView\n                        android:id=\"@+id/imgValidURL\"\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"wrap_content\"\n                        android:layout_gravity=\"center_vertical\"\n                        android:layout_marginRight=\"5dp\"\n                        android:src=\"@drawable/ic_action_done\"\n                        android:tint=\"@color/theme_primary\"\n                        android:visibility=\"gone\" />\n                </LinearLayout>\n\n                <View\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"1dp\"\n                    android:background=\"@color/theme_primary_dark\" />\n\n                <!-- Username Input -->\n                <LinearLayout\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:gravity=\"center_horizontal\"\n                    android:orientation=\"horizontal\"\n                    android:padding=\"10dp\">\n\n                    <ImageView\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"wrap_content\"\n                        android:layout_gravity=\"center_vertical\"\n                        android:layout_marginRight=\"5dp\"\n                        android:src=\"@drawable/ic_action_user\"\n                        android:tint=\"@color/body_text_3\" />\n\n                    <EditText\n                        android:id=\"@+id/edtUserName\"\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"match_parent\"\n                        android:layout_gravity=\"center_vertical\"\n                        android:background=\"#ffffff\"\n                        android:fontFamily=\"@string/font_light\"\n                        android:gravity=\"center_vertical\"\n                        android:hint=\"@string/label_username_or_email\"\n                        android:singleLine=\"true\"\n                        android:textAppearance=\"?android:attr/textAppearanceMedium\"\n                        android:textColorHint=\"@color/body_text_3\" />\n                </LinearLayout>\n\n                <View\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"1dp\"\n                    android:background=\"@color/theme_primary_dark\" />\n\n                <!-- User Password Input -->\n                <LinearLayout\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:gravity=\"center_horizontal\"\n                    android:orientation=\"horizontal\"\n                    android:padding=\"10dp\">\n\n                    <ImageView\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"wrap_content\"\n                        android:layout_gravity=\"center_vertical\"\n                        android:layout_marginRight=\"5dp\"\n                        android:src=\"@drawable/ic_action_lock\"\n                        android:tint=\"@color/body_text_3\" />\n\n                    <EditText\n                        android:id=\"@+id/edtPassword\"\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"match_parent\"\n                        android:layout_gravity=\"center_vertical\"\n                        android:background=\"#ffffff\"\n                        android:fontFamily=\"@string/font_light\"\n                        android:gravity=\"center_vertical\"\n                        android:hint=\"@string/label_password\"\n                        android:inputType=\"textPassword\"\n                        android:singleLine=\"true\"\n                        android:textAppearance=\"?android:attr/textAppearanceMedium\"\n                        android:textColorHint=\"@color/body_text_3\" />\n                </LinearLayout>\n\n                <View\n                    android:id=\"@+id/layoutBorderDB\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"1dp\"\n                    android:background=\"@color/theme_primary_dark\"\n                    android:visibility=\"gone\" />\n\n\n                <LinearLayout\n                    android:id=\"@+id/layoutDatabase\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:gravity=\"center_horizontal\"\n                    android:orientation=\"horizontal\"\n                    android:padding=\"10dp\"\n                    android:visibility=\"gone\">\n\n                    <ImageView\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"wrap_content\"\n                        android:layout_gravity=\"center_vertical\"\n                        android:layout_marginRight=\"5dp\"\n                        android:src=\"@drawable/ic_action_database\"\n                        android:tint=\"@color/body_text_3\" />\n\n                    <Spinner\n                        android:id=\"@+id/spinnerDatabaseList\"\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"match_parent\"\n                        android:background=\"#ffffff\"\n                        android:gravity=\"center_vertical\" />\n                </LinearLayout>\n\n            </LinearLayout>\n\n            <TextView\n                android:id=\"@+id/termsCondition\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:fontFamily=\"@string/font_light\"\n                android:gravity=\"center\"\n                android:padding=\"5dp\"\n                android:layout_marginTop=\"@dimen/default_8dp\"\n                android:text=\"@string/disclaimer_content\"\n                android:textAppearance=\"?android:attr/textAppearanceSmall\"\n                android:textColorLink=\"#ffffff\"\n                android:textColor=\"#ffffff\" />\n\n            <Button\n                android:id=\"@+id/btnLogin\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginBottom=\"5dp\"\n                android:layout_marginLeft=\"5dp\"\n                android:layout_marginRight=\"5dp\"\n                android:layout_marginTop=\"15dp\"\n                android:background=\"@drawable/login_signup_button\"\n                android:fontFamily=\"@string/font_light\"\n                android:text=\"@string/label_accept_login\"\n                android:textColor=\"#fff\" />\n\n            <TextView\n                android:id=\"@+id/forgot_password\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginBottom=\"20dp\"\n                android:fontFamily=\"@string/font_light\"\n                android:gravity=\"center\"\n                android:padding=\"5dp\"\n                android:text=\"@string/label_forgot_password\"\n                android:textAppearance=\"?android:attr/textAppearanceSmall\"\n                android:textColor=\"#ebebeb\" />\n\n            <TextView\n                android:id=\"@+id/txvAddSelfHosted\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginBottom=\"5dp\"\n                android:clickable=\"true\"\n                android:fontFamily=\"@string/font_light\"\n                android:gravity=\"center\"\n                android:padding=\"5dp\"\n                android:text=\"@string/label_add_self_hosted_url\"\n                android:textAppearance=\"?android:attr/textAppearanceMedium\"\n                android:textColor=\"#ffffff\" />\n\n            <TextView\n                android:id=\"@+id/create_account\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:fontFamily=\"@string/font_light\"\n                android:gravity=\"center\"\n                android:padding=\"5dp\"\n                android:text=\"@string/label_create_account\"\n                android:textAppearance=\"?android:attr/textAppearanceMedium\"\n                android:textColor=\"#ffffff\"\n                android:textStyle=\"bold\" />\n\n            <TextView\n                android:id=\"@+id/odoo_version\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_margin=\"10dp\"\n                android:fontFamily=\"@string/font_light\"\n                android:gravity=\"center\"\n                android:padding=\"10dp\"\n                android:textAppearance=\"?android:attr/textAppearanceSmall\"\n                android:textColor=\"#99ffffff\"\n                android:textStyle=\"bold\" />\n        </LinearLayout>\n\n        <LinearLayout\n            android:id=\"@+id/login_progress\"\n            android:orientation=\"vertical\"\n            android:visibility=\"gone\"\n            android:layout_marginTop=\"60dp\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\">\n\n            <TextView\n                android:id=\"@+id/login_process_status\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_margin=\"10dp\"\n                android:fontFamily=\"@string/font_light\"\n                android:gravity=\"center\"\n                android:padding=\"10dp\"\n                android:textAppearance=\"?android:attr/textAppearanceMedium\"\n                android:textColor=\"@color/body_text_1_inverse\" />\n\n            <ProgressBar\n                android:layout_marginTop=\"20dp\"\n                style=\"?android:attr/progressBarStyleHorizontal\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:indeterminate=\"true\" />\n\n        </LinearLayout>\n\n    </LinearLayout>\n\n\n</ScrollView>\n"
  },
  {
    "path": "app/src/main/res/layout/base_mail_chatter.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<com.odoo.base.addons.mail.widget.MailChatterView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_marginTop=\"@dimen/default_16dp\"\n    android:layout_height=\"wrap_content\">\n\n    <LinearLayout\n        android:background=\"@color/base_chatter_view_background\"\n        android:layout_width=\"match_parent\"\n        android:orientation=\"vertical\"\n        android:gravity=\"center\"\n        android:layout_height=\"wrap_content\">\n\n        <View style=\"@style/ViewSeparator\" />\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:orientation=\"horizontal\"\n            android:paddingTop=\"@dimen/default_8dp\"\n            android:gravity=\"center\"\n            android:layout_height=\"wrap_content\">\n\n            <TextView\n                android:id=\"@+id/chatterSendMessage\"\n                android:text=\"@string/label_send_message\"\n                android:background=\"?android:attr/selectableItemBackground\"\n                android:textAppearance=\"?android:textAppearanceSmall\"\n                android:padding=\"@dimen/default_8dp\"\n                android:layout_width=\"wrap_content\"\n                android:textColor=\"@color/android_blue_dark\"\n                android:fontFamily=\"@string/font_condensed\"\n                android:layout_height=\"wrap_content\" />\n\n            <ProgressBar\n                style=\"?android:attr/progressBarStyleSmall\"\n                android:layout_width=\"wrap_content\"\n                android:visibility=\"gone\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginLeft=\"@dimen/default_8dp\"\n                android:layout_marginRight=\"@dimen/default_8dp\"\n                android:id=\"@+id/chatterProgress\" />\n\n            <TextView\n                android:id=\"@+id/chatterOr\"\n                android:text=\"or\"\n                android:textColor=\"@color/body_text_3\"\n                android:textAppearance=\"?android:textAppearanceSmall\"\n                android:padding=\"@dimen/default_8dp\"\n                android:layout_width=\"wrap_content\"\n                android:layout_marginLeft=\"@dimen/default_8dp\"\n                android:layout_marginRight=\"@dimen/default_8dp\"\n                android:fontFamily=\"@string/font_normal\"\n                android:layout_height=\"wrap_content\" />\n\n            <TextView\n                android:id=\"@+id/chatterLogInternalNote\"\n                android:background=\"?android:attr/selectableItemBackground\"\n                android:textColor=\"@color/android_blue_dark\"\n                android:textAppearance=\"?android:textAppearanceSmall\"\n                android:padding=\"@dimen/default_8dp\"\n                android:text=\"@string/label_log_an_internal_note\"\n                android:fontFamily=\"@string/font_condensed\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\" />\n\n        </LinearLayout>\n\n        <odoo.controls.ExpandableListControl\n            android:id=\"@+id/chatterMessages\"\n            android:layout_width=\"match_parent\"\n            android:orientation=\"vertical\"\n            android:padding=\"@dimen/default_8dp\"\n            android:layout_height=\"wrap_content\">\n\n        </odoo.controls.ExpandableListControl>\n\n        <TextView\n            android:id=\"@+id/chatterLoadMoreMessages\"\n            android:text=\"Load more...\"\n            android:background=\"?android:attr/selectableItemBackground\"\n            android:textAppearance=\"?android:textAppearanceSmall\"\n            android:padding=\"@dimen/default_8dp\"\n            android:layout_marginBottom=\"@dimen/default_8dp\"\n            android:visibility=\"gone\"\n            android:layout_width=\"wrap_content\"\n            android:gravity=\"center\"\n            android:textColor=\"@color/body_text_2\"\n            android:fontFamily=\"@string/font_condensed\"\n            android:layout_height=\"wrap_content\" />\n    </LinearLayout>\n</com.odoo.base.addons.mail.widget.MailChatterView>\n"
  },
  {
    "path": "app/src/main/res/layout/base_mail_chatter_item.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:layout_width=\"match_parent\"\n    android:layout_marginBottom=\"4dp\"\n    android:background=\"#ffffff\"\n    android:orientation=\"vertical\"\n    android:layout_height=\"wrap_content\">\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:orientation=\"horizontal\"\n        android:gravity=\"top\"\n\n        android:layout_height=\"wrap_content\">\n\n        <odoo.controls.BezelImageView\n            android:id=\"@+id/authorImage\"\n            android:layout_width=\"32dp\"\n            android:src=\"@drawable/avatar\"\n            android:layout_marginTop=\"@dimen/default_16dp\"\n            android:layout_marginLeft=\"@dimen/default_8dp\"\n            app:maskDrawable=\"@drawable/circle_mask\"\n            android:layout_height=\"32dp\" />\n\n        <LinearLayout\n            android:orientation=\"vertical\"\n            android:paddingTop=\"@dimen/default_16dp\"\n            android:paddingBottom=\"@dimen/default_16dp\"\n            android:paddingRight=\"@dimen/default_16dp\"\n            android:paddingLeft=\"@dimen/default_8dp\"\n            android:layout_width=\"0dp\"\n            android:layout_weight=\"1\"\n            android:layout_height=\"wrap_content\">\n\n\n            <TextView\n                android:id=\"@+id/chatterSubject\"\n                android:textAppearance=\"?android:textAppearanceSmall\"\n                android:fontFamily=\"@string/font_normal\"\n                android:layout_marginBottom=\"5dp\"\n                android:layout_width=\"match_parent\"\n                android:singleLine=\"true\"\n                android:ellipsize=\"middle\"\n                android:textStyle=\"bold\"\n                android:textColor=\"@color/body_text_1\"\n                android:layout_height=\"wrap_content\" />\n\n            <TextView\n                android:id=\"@+id/chatterBody\"\n                android:textAppearance=\"?android:textAppearanceSmall\"\n                android:fontFamily=\"@string/font_normal\"\n                android:layout_width=\"match_parent\"\n                android:maxLines=\"3\"\n                android:textColor=\"#414141\"\n                android:layout_height=\"wrap_content\" />\n\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:orientation=\"horizontal\"\n                android:gravity=\"center_vertical\"\n                android:layout_marginTop=\"5dp\"\n                android:layout_height=\"wrap_content\">\n\n                <TextView\n                    android:id=\"@+id/chatterAuthor\"\n                    android:textAppearance=\"?android:textAppearanceSmall\"\n                    android:fontFamily=\"@string/font_condensed\"\n                    android:layout_width=\"0dp\"\n                    android:layout_weight=\"1\"\n                    android:singleLine=\"true\"\n                    android:ellipsize=\"middle\"\n                    android:textColor=\"@color/body_text_3\"\n                    android:layout_height=\"wrap_content\" />\n\n                <ImageView\n                    android:id=\"@+id/imgAttachments\"\n                    android:visibility=\"gone\"\n                    android:layout_gravity=\"right\"\n                    android:tint=\"@color/theme_secondary\"\n                    android:src=\"@drawable/ic_action_file_attachment\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\" />\n\n                <TextView\n                    android:singleLine=\"true\"\n                    android:id=\"@+id/chatterDate\"\n                    android:textAppearance=\"?android:textAppearanceSmall\"\n                    android:fontFamily=\"@string/font_condensed\"\n                    android:textColor=\"@color/body_text_3\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\" />\n            </LinearLayout>\n        </LinearLayout>\n    </LinearLayout>\n\n    <View style=\"@style/ViewSeparator\" />\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/base_mail_chatter_message_compose.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:orientation=\"vertical\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <LinearLayout\n        android:id=\"@+id/dialogHeader\"\n        android:layout_width=\"match_parent\"\n        android:orientation=\"horizontal\"\n        android:gravity=\"center_vertical\"\n        android:background=\"@color/theme_secondary_dark\"\n        android:layout_height=\"wrap_content\">\n\n        <TextView\n            android:id=\"@+id/recordName\"\n            android:textColor=\"#fff\"\n            android:padding=\"@dimen/default_16dp\"\n            android:fontFamily=\"@string/font_normal\"\n            android:textStyle=\"bold\"\n            android:singleLine=\"true\"\n            android:ellipsize=\"end\"\n            android:textAppearance=\"?android:attr/textAppearanceMedium\"\n            android:layout_width=\"0dp\"\n            android:layout_weight=\"1\"\n            android:layout_height=\"wrap_content\" />\n\n    </LinearLayout>\n\n    <ScrollView\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"0dp\"\n        android:layout_weight=\"1\"\n        android:fillViewport=\"true\">\n\n        <LinearLayout\n            android:orientation=\"vertical\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\">\n\n            <EditText\n                android:id=\"@+id/messageSubject\"\n                android:padding=\"@dimen/default_16dp\"\n                android:hint=\"Subject\"\n                android:background=\"@android:color/transparent\"\n                android:textAppearance=\"?android:textAppearanceMedium\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\" />\n\n            <View style=\"@style/ViewSeparator\" />\n\n            <EditText\n                android:padding=\"@dimen/default_16dp\"\n                android:gravity=\"top\"\n                android:textAppearance=\"?android:textAppearanceMedium\"\n                android:id=\"@+id/messageBody\"\n                android:hint=\"Message\"\n                android:minLines=\"10\"\n                android:background=\"@android:color/transparent\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\" />\n\n\n        </LinearLayout>\n    </ScrollView>\n\n    <View style=\"@style/ViewSeparator\" />\n\n    <TextView\n        android:id=\"@+id/btnAttachment\"\n        android:padding=\"@dimen/default_16dp\"\n        android:background=\"?attr/selectableItemBackground\"\n        android:textColor=\"@color/android_blue_dark\"\n        android:fontFamily=\"@string/font_condensed\"\n        android:text=\"@string/label_attach_a_file\"\n        android:textAppearance=\"?android:attr/textAppearanceSmall\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\" />\n\n    <HorizontalScrollView\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\">\n\n        <LinearLayout\n            android:id=\"@+id/attachmentsList\"\n            android:orientation=\"horizontal\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"match_parent\">\n\n\n        </LinearLayout>\n\n    </HorizontalScrollView>\n\n    <View style=\"@style/ViewSeparator\" />\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:showDividers=\"middle\"\n        android:divider=\"?android:attr/dividerVertical\"\n        android:orientation=\"horizontal\">\n\n\n        <Button\n            android:id=\"@+id/btnSend\"\n            style=\"?android:attr/borderlessButtonStyle\"\n            android:layout_width=\"0dp\"\n            android:layout_weight=\"1\"\n            android:fontFamily=\"@string/font_normal\"\n            android:layout_height=\"match_parent\"\n            android:background=\"?android:selectableItemBackground\"\n            android:gravity=\"center\"\n            android:padding=\"@dimen/default_16dp\"\n            android:text=\"@string/label_send\"\n            android:textAllCaps=\"true\"\n            android:textStyle=\"bold\"\n            android:textColor=\"@color/body_text_1\"\n            android:textSize=\"@dimen/text_size_medium\" />\n\n        <Button\n            android:id=\"@+id/btnCancel\"\n            style=\"?android:attr/borderlessButtonStyle\"\n            android:layout_width=\"0dp\"\n            android:layout_weight=\"1\"\n            android:layout_height=\"match_parent\"\n            android:background=\"?android:selectableItemBackground\"\n            android:gravity=\"center\"\n            android:fontFamily=\"@string/font_normal\"\n            android:padding=\"@dimen/default_16dp\"\n            android:text=\"@string/label_cancel\"\n            android:textAllCaps=\"true\"\n            android:textColor=\"@color/body_text_1\"\n            android:textSize=\"@dimen/text_size_medium\" />\n\n    </LinearLayout>\n</LinearLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/base_mail_chatter_message_detail.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:orientation=\"vertical\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <TextView\n        android:id=\"@+id/recordName\"\n        android:textColor=\"#fff\"\n        android:padding=\"@dimen/default_16dp\"\n        android:background=\"@color/android_blue_dark\"\n        android:fontFamily=\"@string/font_normal\"\n        android:textStyle=\"bold\"\n        android:textAppearance=\"?android:attr/textAppearanceMedium\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\" />\n\n    <ScrollView\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"0dp\"\n        android:layout_weight=\"1\"\n        android:fillViewport=\"true\">\n\n        <LinearLayout\n            android:orientation=\"vertical\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\">\n\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:paddingTop=\"@dimen/default_8dp\"\n                android:paddingBottom=\"@dimen/default_8dp\"\n                android:paddingLeft=\"@dimen/default_16dp\"\n                android:paddingRight=\"@dimen/default_16dp\"\n                android:background=\"#fff\"\n                android:orientation=\"horizontal\"\n                android:layout_height=\"wrap_content\">\n\n                <odoo.controls.BezelImageView\n                    android:id=\"@+id/author_image\"\n                    android:layout_width=\"40dp\"\n                    app:maskDrawable=\"@drawable/circle_mask\"\n                    android:layout_height=\"40dp\" />\n\n                <LinearLayout\n                    android:layout_width=\"0dp\"\n                    android:layout_weight=\"1\"\n                    android:paddingLeft=\"@dimen/default_8dp\"\n                    android:orientation=\"vertical\"\n                    android:layout_height=\"wrap_content\">\n\n                    <TextView\n                        android:id=\"@+id/authorName\"\n                        android:textColor=\"@color/body_text_2\"\n                        android:fontFamily=\"@string/font_condensed\"\n                        android:textAppearance=\"?android:attr/textAppearanceMedium\"\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"wrap_content\" />\n\n                    <TextView\n                        android:id=\"@+id/messageDate\"\n                        android:textColor=\"@color/body_text_3\"\n                        android:fontFamily=\"@string/font_condensed\"\n                        android:textAppearance=\"?android:attr/textAppearanceSmall\"\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"wrap_content\" />\n                </LinearLayout>\n            </LinearLayout>\n\n\n            <TextView\n                android:id=\"@+id/messageSubject\"\n                android:textColor=\"@color/body_text_1\"\n                android:textStyle=\"bold\"\n                android:padding=\"@dimen/default_16dp\"\n                android:background=\"#fff\"\n                android:fontFamily=\"@string/font_normal\"\n                android:textAppearance=\"?android:attr/textAppearanceSmall\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\" />\n\n            <View style=\"@style/ViewSeparator\" />\n\n            <WebView\n                android:id=\"@+id/messageBody\"\n                android:layout_marginLeft=\"12dp\"\n                android:layout_marginRight=\"12dp\"\n                android:background=\"@android:color/transparent\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\">\n\n            </WebView>\n\n\n        </LinearLayout>\n    </ScrollView>\n\n    <HorizontalScrollView\n        android:padding=\"@dimen/default_8dp\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\">\n\n        <LinearLayout\n            android:id=\"@+id/attachmentsList\"\n            android:orientation=\"horizontal\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"match_parent\">\n\n        </LinearLayout>\n\n    </HorizontalScrollView>\n\n    <View style=\"@style/ViewSeparator\" />\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:showDividers=\"middle\"\n        android:divider=\"?android:attr/dividerVertical\"\n        android:orientation=\"horizontal\">\n\n\n        <Button\n            android:id=\"@+id/btnReply\"\n            style=\"?android:attr/borderlessButtonStyle\"\n            android:layout_width=\"0dp\"\n            android:layout_weight=\"1\"\n            android:fontFamily=\"@string/font_normal\"\n            android:layout_height=\"match_parent\"\n            android:background=\"?android:selectableItemBackground\"\n            android:gravity=\"center\"\n            android:padding=\"@dimen/default_16dp\"\n            android:text=\"@string/label_reply\"\n            android:textAllCaps=\"true\"\n            android:textStyle=\"bold\"\n            android:textColor=\"@color/body_text_1\"\n            android:textSize=\"@dimen/text_size_medium\" />\n\n        <Button\n            android:id=\"@+id/btnClose\"\n            style=\"?android:attr/borderlessButtonStyle\"\n            android:layout_width=\"0dp\"\n            android:layout_weight=\"1\"\n            android:layout_height=\"match_parent\"\n            android:background=\"?android:selectableItemBackground\"\n            android:gravity=\"center\"\n            android:fontFamily=\"@string/font_normal\"\n            android:padding=\"@dimen/default_16dp\"\n            android:text=\"@string/label_close\"\n            android:textAllCaps=\"true\"\n            android:textColor=\"@color/body_text_1\"\n            android:textSize=\"@dimen/text_size_medium\" />\n\n    </LinearLayout>\n</LinearLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/base_manage_accounts.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:orientation=\"vertical\"\n    android:layout_height=\"match_parent\">\n\n    <View style=\"@style/StatusBarView\" />\n\n    <include layout=\"@layout/base_toolbar\" />\n\n    <odoo.controls.ExpandableListControl\n        android:id=\"@+id/accountList\"\n        android:layout_width=\"match_parent\"\n        android:orientation=\"vertical\"\n        android:layout_height=\"wrap_content\"></odoo.controls.ExpandableListControl>\n\n</LinearLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/base_no_items_view.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<ScrollView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:fillViewport=\"true\"\n    android:layout_height=\"match_parent\"\n    android:gravity=\"center\">\n\n    <LinearLayout\n        android:id=\"@+id/dashboard_no_item_view\"\n        android:layout_width=\"match_parent\"\n        android:gravity=\"center\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"vertical\">\n\n        <ImageView\n            android:id=\"@+id/icon\"\n            android:layout_width=\"80dp\"\n            android:layout_height=\"80dp\"\n            android:layout_gravity=\"center_horizontal\"\n            android:src=\"@drawable/ic_action_event\"\n            android:tint=\"#aaaaaa\" />\n\n        <TextView\n            android:id=\"@+id/title\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"center_horizontal\"\n            android:fontFamily=\"@string/font_light\"\n            android:text=\"Your day is wide open\"\n            android:textAppearance=\"?android:attr/textAppearanceLarge\"\n            android:textColor=\"#aaaaaa\"\n            android:textStyle=\"bold\" />\n\n        <TextView\n            android:id=\"@+id/subTitle\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"center_horizontal\"\n            android:fontFamily=\"@string/font_light\"\n            android:text=\"Tap to add meeting\"\n            android:textAppearance=\"?android:attr/textAppearanceSmall\"\n            android:textColor=\"#ababab\"\n            android:textStyle=\"bold\" />\n    </LinearLayout>\n</ScrollView>\n"
  },
  {
    "path": "app/src/main/res/layout/base_no_items_view.xml~",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<ScrollView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:fillViewport=\"true\"\n    android:layout_height=\"match_parent\"\n    android:gravity=\"center\">\n\n    <LinearLayout\n        android:id=\"@+id/dashboard_no_item_view\"\n        android:layout_width=\"match_parent\"\n        android:gravity=\"center\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"vertical\">\n\n        <ImageView\n            android:id=\"@+id/icon\"\n            android:layout_width=\"80dp\"\n            android:layout_height=\"80dp\"\n            android:layout_gravity=\"center_horizontal\"\n            android:src=\"@drawable/ic_action_event\"\n            android:tint=\"#aaaaaa\" />\n\n        <TextView\n            android:id=\"@+id/title\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"center_horizontal\"\n            android:fontFamily=\"@string/font_light\"\n            android:text=\"Your day is wide open\"\n            android:textAppearance=\"?android:attr/textAppearanceLarge\"\n            android:textColor=\"#aaaaaa\"\n            android:textStyle=\"bold\" />\n\n        <TextView\n            android:id=\"@+id/subTitle\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"center_horizontal\"\n            android:fontFamily=\"@string/font_light\"\n            android:text=\"Tap to add meeting\"\n            android:textAppearance=\"?android:attr/textAppearanceSmall\"\n            android:textColor=\"#ababab\"\n            android:textStyle=\"bold\" />\n    </LinearLayout>\n<<<<<<< HEAD:app/src/main/res/layout/base_no_items_view.xml\n</ScrollView>\n=======\n</ScrollView>\n>>>>>>> master-crm-studio-dpr:app/src/main/res/layout/calendar_dashboard_no_items.xml\n"
  },
  {
    "path": "app/src/main/res/layout/base_profile.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:layout_width=\"match_parent\"\n    android:orientation=\"vertical\"\n    android:background=\"#ffffff\"\n    android:layout_height=\"match_parent\">\n\n\n    <com.odoo.widgets.parallax.ParallaxScrollView\n        android:id=\"@+id/parallaxScrollView\"\n        android:layout_width=\"match_parent\"\n        android:paddingTop=\"@dimen/statusBarHeight\"\n        android:clipToPadding=\"false\"\n        android:layout_height=\"wrap_content\">\n\n        <RelativeLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\">\n\n            <FrameLayout\n                android:id=\"@+id/parallax_view\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginBottom=\"-56dp\">\n\n                <ImageView\n                    android:id=\"@android:id/icon\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"380dp\"\n                    android:scaleType=\"centerCrop\"\n                    android:src=\"@drawable/user_xlarge\" />\n            </FrameLayout>\n\n            <TextView\n                android:id=\"@android:id/title\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"56dp\"\n                android:layout_below=\"@+id/parallax_view\"\n                android:gravity=\"center_vertical\"\n                android:fontFamily=\"@string/font_normal\"\n                android:paddingLeft=\"@dimen/default_16dp\"\n                android:textColor=\"#ffffff\"\n                android:textSize=\"30sp\" />\n\n            <LinearLayout\n                android:layout_below=\"@android:id/title\"\n                android:orientation=\"vertical\"\n                android:background=\"#ffffff\"\n                android:paddingBottom=\"@dimen/default_16dp\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\">\n\n                <odoo.controls.OForm\n                    android:id=\"@+id/profileDetails\"\n                    android:layout_width=\"match_parent\"\n                    app:modelName=\"res.users\"\n                    android:orientation=\"vertical\"\n                    android:layout_height=\"wrap_content\">\n\n                    <odoo.controls.OField\n                        android:layout_width=\"match_parent\"\n                        app:fieldName=\"user_login\"\n                        app:controlLabel=\"USER LOGIN\"\n                        app:fieldLabelColor=\"@color/theme_primary\"\n                        app:fieldTextSize=\"@dimen/text_size_xmedium\"\n                        app:showIcon=\"false\"\n                        android:id=\"@+id/user_login\"\n                        android:layout_height=\"wrap_content\"></odoo.controls.OField>\n\n                    <odoo.controls.OField\n                        android:layout_width=\"match_parent\"\n                        app:fieldName=\"server_url\"\n                        app:controlLabel=\"SERVER URL\"\n                        app:fieldLabelColor=\"@color/theme_primary\"\n                        app:fieldTextSize=\"@dimen/text_size_xmedium\"\n                        app:showIcon=\"false\"\n                        android:layout_height=\"wrap_content\"></odoo.controls.OField>\n\n                    <odoo.controls.OField\n                        android:layout_width=\"match_parent\"\n                        app:fieldName=\"database\"\n                        app:controlLabel=\"DATABASE\"\n                        app:fieldLabelColor=\"@color/theme_primary\"\n                        app:fieldTextSize=\"@dimen/text_size_xmedium\"\n                        app:showIcon=\"false\"\n                        android:layout_height=\"wrap_content\"></odoo.controls.OField>\n\n                    <odoo.controls.OField\n                        android:layout_width=\"match_parent\"\n                        app:fieldName=\"version\"\n                        app:controlLabel=\"ODOO VERSION\"\n                        app:fieldLabelColor=\"@color/theme_primary\"\n                        app:fieldTextSize=\"@dimen/text_size_xmedium\"\n                        app:showIcon=\"false\"\n                        android:layout_height=\"wrap_content\"></odoo.controls.OField>\n\n                    <odoo.controls.OField\n                        android:layout_width=\"match_parent\"\n                        app:fieldName=\"timezone\"\n                        app:controlLabel=\"TIMEZONE\"\n                        app:fieldLabelColor=\"@color/theme_primary\"\n                        app:fieldTextSize=\"@dimen/text_size_xmedium\"\n                        app:showIcon=\"false\"\n                        android:layout_height=\"wrap_content\"></odoo.controls.OField>\n                </odoo.controls.OForm>\n            </LinearLayout>\n        </RelativeLayout>\n    </com.odoo.widgets.parallax.ParallaxScrollView>\n\n    <android.support.v7.widget.Toolbar\n        android:id=\"@+id/toolbar\"\n        android:paddingTop=\"@dimen/statusBarHeight\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:background=\"@color/android_orange\"\n        android:minHeight=\"?attr/actionBarSize\"\n        android:paddingRight=\"@dimen/default_8dp\"\n        app:popupTheme=\"@style/ThemeOverlay.AppCompat.Dark\"\n        app:theme=\"@style/ToolBarTheme\" />\n\n</RelativeLayout>"
  },
  {
    "path": "app/src/main/res/layout/base_setting_activity.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:orientation=\"vertical\"\n    android:paddingTop=\"@dimen/statusBarHeight\"\n    android:background=\"@color/theme_primary\"\n    android:layout_height=\"match_parent\">\n\n    <include layout=\"@layout/base_toolbar\" />\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_weight=\"1\"\n        android:background=\"@android:color/white\"\n        android:layout_height=\"0dp\">\n\n        <fragment\n            android:id=\"@+id/setting_activity_container\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            class=\"com.odoo.core.account.BaseSettings\">\n\n        </fragment>\n    </LinearLayout>\n</LinearLayout>\n\n\n"
  },
  {
    "path": "app/src/main/res/layout/base_simple_list_item_1.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:orientation=\"vertical\"\n    android:layout_width=\"match_parent\"\n    android:padding=\"@dimen/default_16dp\"\n    android:layout_height=\"match_parent\">\n\n    <TextView\n        android:textStyle=\"bold\"\n        android:id=\"@android:id/text1\"\n        android:textColor=\"@color/actionbar_spinner_text_color\"\n        android:layout_width=\"match_parent\"\n        android:textSize=\"@dimen/text_size_xmedium\"\n        android:layout_height=\"wrap_content\" />\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/base_simple_list_item_1_selected.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:orientation=\"vertical\"\n    android:layout_width=\"match_parent\"\n    android:paddingRight=\"@dimen/default_8dp\"\n    android:layout_height=\"match_parent\">\n\n    <TextView\n        android:textStyle=\"bold\"\n        android:id=\"@android:id/text1\"\n        android:textColor=\"@android:color/white\"\n        android:layout_width=\"match_parent\"\n        android:textSize=\"@dimen/text_size_xmedium\"\n        android:layout_height=\"wrap_content\" />\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/base_toolbar.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<android.support.v7.widget.Toolbar xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:id=\"@+id/toolbar\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:background=\"@color/theme_primary\"\n    android:minHeight=\"?attr/actionBarSize\"\n    app:titleMarginStart=\"@dimen/default_16dp\"\n    android:paddingRight=\"@dimen/default_8dp\"\n    app:popupTheme=\"@style/ThemeOverlay.AppCompat.Dark.ActionBar\"\n    app:theme=\"@style/ToolBarTheme\">\n\n    <Spinner\n        android:id=\"@+id/spinner_nav\"\n        android:visibility=\"gone\"\n        android:layout_marginLeft=\"@dimen/default_16dp\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\" />\n\n</android.support.v7.widget.Toolbar>"
  },
  {
    "path": "app/src/main/res/layout/calendar_dashboard.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:odoo=\"http://schemas.android.com/apk/res-auto\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <com.odoo.libs.calendar.view.OdooCalendar\n        android:id=\"@+id/dashboard_calendar\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"></com.odoo.libs.calendar.view.OdooCalendar>\n\n    <odoo.controls.fab.FloatingActionButton\n        android:id=\"@+id/fabButton\"\n        android:layout_width=\"72dp\"\n        android:layout_height=\"72dp\"\n        android:layout_gravity=\"bottom|right\"\n        android:layout_marginBottom=\"16dp\"\n        android:layout_marginRight=\"16dp\"\n        odoo:drawable=\"@drawable/ic_action_content_add\"\n        odoo:fabColor=\"@color/theme_primary\" />\n\n</FrameLayout>"
  },
  {
    "path": "app/src/main/res/layout/calendar_dashboard_item_separator.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:orientation=\"vertical\"\n    android:background=\"#ffffff\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <TextView\n        android:id=\"@+id/list_separator\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"35dp\"\n        android:fontFamily=\"@string/font_normal\"\n        android:gravity=\"bottom\"\n        android:paddingLeft=\"16dp\"\n        android:textColor=\"@color/theme_secondary_dark\"\n        android:textSize=\"14dp\"\n        android:textStyle=\"bold\" />\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/calendar_dashboard_item_view.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:background=\"#ffffff\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n    <LinearLayout\n        android:background=\"?android:attr/selectableItemBackground\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"horizontal\"\n        android:padding=\"16dp\">\n\n        <ImageView\n            android:id=\"@+id/event_icon\"\n            android:layout_width=\"40dp\"\n            android:layout_height=\"40dp\"\n            android:layout_gravity=\"center_horizontal\"\n            android:background=\"@drawable/circle_mask_secondary\"\n            android:padding=\"8dp\"\n            android:src=\"@drawable/ic_action_phone\"\n            android:tint=\"#ffffff\" />\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"8dp\"\n            android:orientation=\"vertical\"\n            android:paddingBottom=\"5dp\"\n            android:paddingLeft=\"5dp\"\n            android:paddingRight=\"5dp\">\n\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:orientation=\"horizontal\">\n\n                <TextView\n                    android:id=\"@+id/event_name\"\n                    android:layout_width=\"0dp\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_weight=\"1\"\n                    android:ellipsize=\"end\"\n                    android:paddingRight=\"8dp\"\n                    android:singleLine=\"true\"\n                    android:textAppearance=\"?android:attr/textAppearanceMedium\"\n                    android:textColor=\"#414141\" />\n\n                <TextView\n                    android:id=\"@+id/allDay\"\n                    android:paddingLeft=\"5dp\"\n                    android:visibility=\"gone\"\n                    android:text=\"All Day\"\n                    android:singleLine=\"true\"\n                    android:fontFamily=\"@string/font_normal\"\n                    android:textAppearance=\"?android:attr/textAppearanceSmall\"\n                    android:textColor=\"@color/theme_secondary\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\" />\n\n                <TextView\n                    android:id=\"@+id/event_time\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:singleLine=\"true\"\n                    android:fontFamily=\"@string/font_normal\"\n                    android:textAppearance=\"?android:attr/textAppearanceSmall\"\n                    android:textColor=\"@color/theme_secondary\" />\n            </LinearLayout>\n\n            <TextView\n                android:id=\"@+id/event_description\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:maxLines=\"2\"\n                android:textAppearance=\"?android:attr/textAppearanceSmall\"\n                android:textColor=\"#aaaaaa\" />\n        </LinearLayout>\n    </LinearLayout>\n\n    <View\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"1dp\"\n        android:layout_marginLeft=\"72dp\"\n        android:background=\"#ebebeb\" />\n\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/calendar_dashboard_items.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n    <include\n        android:id=\"@+id/dashboard_progress\"\n        layout=\"@layout/listview_data_loading_progress\" />\n\n    <android.support.v4.widget.SwipeRefreshLayout\n        android:id=\"@+id/dashboard_no_items\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:visibility=\"gone\">\n\n        <include layout=\"@layout/base_no_items_view\" />\n    </android.support.v4.widget.SwipeRefreshLayout>\n\n    <View style=\"@style/ViewSeparator\" />\n\n    <android.support.v4.widget.SwipeRefreshLayout\n        android:id=\"@+id/swipe_container\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\">\n\n        <ListView\n            android:id=\"@+id/items_container\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:divider=\"@null\"\n            android:dividerHeight=\"0dp\"\n            android:smoothScrollbar=\"true\"\n            android:visibility=\"gone\"></ListView>\n    </android.support.v4.widget.SwipeRefreshLayout>\n\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/calendar_event_detail_form.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n    <android.support.v7.widget.Toolbar\n        android:id=\"@+id/toolbar\"\n        android:paddingTop=\"@dimen/statusBarHeight\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:background=\"@color/theme_primary\"\n        android:minHeight=\"?attr/actionBarSize\"\n        app:titleMarginStart=\"@dimen/default_16dp\"\n        android:paddingRight=\"@dimen/default_16dp\"\n        app:popupTheme=\"@style/ThemeOverlay.AppCompat.Dark\"\n        app:theme=\"@style/ToolBarTheme\" />\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"0dp\"\n        android:layout_weight=\"1\"\n        android:background=\"#ffffff\"\n        android:orientation=\"vertical\">\n\n        <ScrollView\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\">\n\n            <odoo.controls.OForm\n                app:controlIconTint=\"@color/body_text_3\"\n                android:id=\"@+id/eventForm\"\n                android:layout_width=\"match_parent\"\n                android:orientation=\"vertical\"\n                app:editableMode=\"true\"\n                app:modelName=\"calendar.event\"\n                android:layout_height=\"wrap_content\">\n\n                <odoo.controls.OField\n                    android:layout_width=\"match_parent\"\n                    app:fieldName=\"name\"\n                    app:showIcon=\"false\"\n                    app:showLabel=\"false\"\n                    app:fieldTextAppearance=\"?android:textAppearanceLarge\"\n                    android:layout_height=\"wrap_content\"></odoo.controls.OField>\n\n                <View style=\"@style/ViewSeparator\" />\n\n                <odoo.controls.OField\n                    android:id=\"@+id/fieldAllDay\"\n                    android:layout_width=\"match_parent\"\n                    app:fieldName=\"allday\"\n                    app:widgetType=\"Switch\"\n                    app:showLabel=\"false\"\n                    app:fieldTextSize=\"@dimen/text_size_xmedium\"\n                    app:fieldTextColor=\"@color/body_text_2\"\n                    app:iconTint=\"@color/body_text_3\"\n                    app:iconResource=\"@drawable/ic_action_time_clock\"\n                    android:layout_height=\"wrap_content\">\n\n                </odoo.controls.OField>\n\n                <LinearLayout\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:paddingLeft=\"72dp\"\n                    android:paddingRight=\"@dimen/default_16dp\"\n                    android:orientation=\"vertical\">\n\n                    <LinearLayout\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"56dp\"\n                        android:orientation=\"horizontal\">\n\n                        <odoo.controls.OField\n                            android:id=\"@+id/event_date_start\"\n                            android:layout_width=\"0dp\"\n                            android:layout_weight=\"1\"\n                            app:fieldName=\"event_date_start\"\n                            app:defaultValue=\"now()\"\n                            app:parsePattern=\"EEEE, MMM dd, yyyy\"\n                            app:fieldType=\"Date\"\n                            app:fieldTextSize=\"@dimen/text_size_xmedium\"\n                            app:withOutSidePadding=\"false\"\n                            app:showLabel=\"false\"\n                            app:fieldTextColor=\"@color/body_text_2\"\n                            app:showIcon=\"false\"\n                            android:layout_height=\"match_parent\"></odoo.controls.OField>\n\n                        <odoo.controls.OField\n                            android:id=\"@+id/event_start_time\"\n                            android:layout_width=\"wrap_content\"\n                            app:fieldName=\"event_time_start\"\n                            app:defaultValue=\"now()\"\n                            app:parsePattern=\"hh:mm a\"\n                            app:fieldTextSize=\"@dimen/text_size_xmedium\"\n                            app:fieldTextColor=\"@color/body_text_2\"\n                            app:fieldType=\"Time\"\n                            app:withOutSidePadding=\"false\"\n                            app:showLabel=\"false\"\n                            app:showIcon=\"false\"\n                            android:layout_height=\"match_parent\"></odoo.controls.OField>\n\n                    </LinearLayout>\n\n                    <LinearLayout\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"56dp\"\n                        android:orientation=\"horizontal\">\n\n                        <odoo.controls.OField\n                            android:id=\"@+id/event_date_end\"\n                            android:layout_width=\"0dp\"\n                            android:layout_weight=\"1\"\n                            app:fieldName=\"event_date_end\"\n                            app:fieldTextSize=\"@dimen/text_size_xmedium\"\n                            app:defaultValue=\"now()\"\n                            app:fieldTextColor=\"@color/body_text_2\"\n                            app:parsePattern=\"EEEE, MMM dd, yyyy\"\n                            app:fieldType=\"Date\"\n                            app:withOutSidePadding=\"false\"\n                            app:showLabel=\"false\"\n                            app:showIcon=\"false\"\n                            android:layout_height=\"match_parent\"></odoo.controls.OField>\n\n                        <odoo.controls.OField\n                            android:id=\"@+id/event_end_time\"\n                            android:layout_width=\"wrap_content\"\n                            app:fieldName=\"event_time_end\"\n                            app:defaultValue=\"now()\"\n                            app:parsePattern=\"hh:mm a\"\n                            app:fieldTextSize=\"@dimen/text_size_xmedium\"\n                            app:fieldTextColor=\"@color/body_text_2\"\n                            app:fieldType=\"Time\"\n                            app:withOutSidePadding=\"false\"\n                            app:showLabel=\"false\"\n                            app:showIcon=\"false\"\n                            android:layout_height=\"match_parent\"></odoo.controls.OField>\n\n                    </LinearLayout>\n\n                </LinearLayout>\n\n                <View\n                    style=\"@style/ViewSeparator\"\n                    android:layout_marginLeft=\"72dp\" />\n\n                <odoo.controls.OField\n                    android:layout_width=\"match_parent\"\n                    app:iconTint=\"@color/body_text_3\"\n                    app:fieldName=\"class\"\n                    app:fieldTextAppearance=\"?android:textAppearanceMedium\"\n                    app:showLabel=\"false\"\n                    app:fieldTextSize=\"@dimen/text_size_xmedium\"\n                    app:iconResource=\"@drawable/ic_action_lock\"\n                    android:layout_height=\"wrap_content\"></odoo.controls.OField>\n\n                <View\n                    style=\"@style/ViewSeparator\"\n                    android:layout_marginLeft=\"72dp\" />\n\n                <odoo.controls.OField\n                    android:id=\"@+id/opportunity_id\"\n                    android:layout_width=\"match_parent\"\n                    app:fieldName=\"opportunity_id\"\n                    app:widgetType=\"Searchable\"\n                    android:visibility=\"gone\"\n                    app:iconResource=\"@drawable/ic_action_opportunities\"\n                    app:fieldTextSize=\"@dimen/text_size_xmedium\"\n                    android:layout_height=\"wrap_content\" />\n\n                <View\n                    style=\"@style/ViewSeparator\"\n                    android:layout_marginLeft=\"72dp\" />\n\n                <odoo.controls.OField\n                    android:layout_width=\"match_parent\"\n                    app:fieldName=\"location\"\n                    app:fieldTextAppearance=\"?android:textAppearanceMedium\"\n                    app:showLabel=\"false\"\n                    app:iconTint=\"@color/body_text_3\"\n                    app:fieldTextSize=\"@dimen/text_size_xmedium\"\n                    app:iconResource=\"@drawable/ic_action_location\"\n                    android:layout_height=\"wrap_content\"></odoo.controls.OField>\n\n                <View\n                    style=\"@style/ViewSeparator\"\n                    android:layout_marginLeft=\"72dp\" />\n\n                <LinearLayout\n                    android:id=\"@+id/reminderForEvent\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"56dp\"\n                    android:gravity=\"center_vertical|top\"\n                    android:background=\"?android:attr/selectableItemBackground\"\n                    android:orientation=\"horizontal\"\n                    android:paddingBottom=\"8dp\"\n                    android:paddingLeft=\"16dp\"\n                    android:paddingRight=\"16dp\"\n                    android:paddingTop=\"8dp\">\n\n                    <ImageView\n                        android:layout_width=\"40dp\"\n                        android:layout_height=\"40dp\"\n                        android:layout_gravity=\"top\"\n                        android:layout_marginRight=\"3dp\"\n                        android:paddingBottom=\"5dp\"\n                        android:src=\"@drawable/ic_action_bell\"\n                        android:tint=\"@color/body_text_3\" />\n\n                    <TextView\n                        android:id=\"@+id/reminderTypeName\"\n                        android:layout_width=\"0dp\"\n                        android:layout_height=\"match_parent\"\n                        android:layout_weight=\"1\"\n                        android:background=\"@android:color/transparent\"\n                        android:fontFamily=\"@string/font_normal\"\n                        android:gravity=\"center_vertical\"\n                        android:paddingLeft=\"16dp\"\n                        android:text=\"@string/at_the_time_of_event\"\n                        android:textSize=\"@dimen/text_size_xmedium\" />\n                </LinearLayout>\n\n                <View\n                    style=\"@style/ViewSeparator\"\n                    android:layout_marginLeft=\"72dp\" />\n\n                <LinearLayout\n                    android:id=\"@+id/event_color\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"56dp\"\n                    android:background=\"?android:attr/selectableItemBackground\"\n                    android:clickable=\"true\"\n                    android:gravity=\"center_vertical|top\"\n                    android:orientation=\"horizontal\"\n                    android:paddingBottom=\"8dp\"\n                    android:paddingLeft=\"16dp\"\n                    android:paddingRight=\"16dp\"\n                    android:paddingTop=\"8dp\">\n\n                    <ImageView\n                        android:id=\"@+id/event_color_view\"\n                        android:layout_width=\"40dp\"\n                        android:layout_height=\"40dp\"\n                        android:layout_gravity=\"top\"\n                        android:layout_marginRight=\"3dp\"\n                        android:paddingBottom=\"5dp\"\n                        android:src=\"@drawable/ic_action_dot\"\n                        android:tint=\"@color/theme_primary\" />\n\n                    <TextView\n                        android:id=\"@+id/event_color_label\"\n                        android:layout_width=\"0dp\"\n                        android:layout_height=\"match_parent\"\n                        android:layout_weight=\"1\"\n                        android:fontFamily=\"@string/font_normal\"\n                        android:gravity=\"center_vertical\"\n                        android:paddingLeft=\"16dp\"\n                        android:text=\"Default Color\"\n                        android:textSize=\"@dimen/text_size_xmedium\" />\n                </LinearLayout>\n\n                <View\n                    style=\"@style/ViewSeparator\"\n                    android:layout_marginLeft=\"72dp\" />\n\n                <odoo.controls.OField\n                    android:layout_width=\"match_parent\"\n                    app:fieldName=\"description\"\n                    app:showLabel=\"false\"\n                    app:iconTint=\"@color/body_text_3\"\n                    app:fieldTextSize=\"@dimen/text_size_xmedium\"\n                    app:fieldTextAppearance=\"?android:textAppearanceMedium\"\n                    app:iconResource=\"@drawable/ic_action_notes_content\"\n                    android:layout_height=\"wrap_content\"></odoo.controls.OField>\n            </odoo.controls.OForm>\n        </ScrollView>\n    </LinearLayout>\n\n    <LinearLayout\n        android:id=\"@+id/meetingDeleteLayout\"\n        android:visibility=\"gone\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"vertical\">\n\n        <View style=\"@style/ViewSeparator\" />\n\n        <TextView\n            android:background=\"@android:color/white\"\n            android:gravity=\"center\"\n            android:text=\"Delete\"\n            android:textAllCaps=\"true\"\n            android:layout_width=\"match_parent\"\n            android:textColor=\"@color/body_text_2\"\n            android:fontFamily=\"@string/font_normal\"\n            android:textAppearance=\"?android:textAppearanceSmall\"\n            android:layout_height=\"wrap_content\"\n            android:padding=\"@dimen/default_16dp\" />\n    </LinearLayout>\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/common_listview.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:odoo=\"http://schemas.android.com/apk/res-auto\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <include\n        layout=\"@layout/customer_filter_container\"\n        android:id=\"@+id/customer_data_filter_container\" />\n\n    <LinearLayout\n        android:id=\"@+id/data_list_container\"\n        android:layout_below=\"@+id/customer_data_filter_container\"\n        android:orientation=\"vertical\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\">\n\n        <android.support.v4.widget.SwipeRefreshLayout\n            android:id=\"@+id/customer_no_items\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:visibility=\"gone\">\n\n            <include layout=\"@layout/base_no_items_view\" />\n        </android.support.v4.widget.SwipeRefreshLayout>\n\n        <android.support.v4.widget.SwipeRefreshLayout\n            android:id=\"@+id/swipe_container\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:visibility=\"gone\">\n\n            <ListView\n                android:id=\"@+id/listview\"\n                android:layout_width=\"fill_parent\"\n                android:layout_height=\"fill_parent\"></ListView>\n        </android.support.v4.widget.SwipeRefreshLayout>\n\n        <include\n            android:id=\"@+id/loadingProgress\"\n            layout=\"@layout/listview_data_loading_progress\" />\n    </LinearLayout>\n\n    <odoo.controls.fab.FloatingActionButton\n        android:id=\"@+id/fabButton\"\n        android:layout_width=\"72dp\"\n        android:layout_height=\"72dp\"\n        android:layout_alignParentBottom=\"true\"\n        android:layout_alignParentRight=\"true\"\n        android:layout_marginBottom=\"@dimen/default_8dp\"\n        android:layout_marginRight=\"@dimen/default_8dp\"\n        odoo:drawable=\"@drawable/ic_action_content_add\"\n        odoo:fabColor=\"@color/theme_primary\" />\n</RelativeLayout>"
  },
  {
    "path": "app/src/main/res/layout/crm_caller_window_layout.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:orientation=\"vertical\"\n    android:layout_width=\"match_parent\"\n    android:background=\"#0288D1\"\n    android:layout_height=\"match_parent\">\n\n    <FrameLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\">\n\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:orientation=\"horizontal\"\n            android:layout_gravity=\"top\"\n            android:layout_height=\"wrap_content\">\n\n            <odoo.controls.BezelImageView\n                android:id=\"@+id/customerImage\"\n                android:layout_width=\"90dp\"\n                android:layout_marginRight=\"@dimen/default_8dp\"\n                android:scaleType=\"centerCrop\"\n                android:layout_height=\"90dp\" />\n\n            <LinearLayout\n                android:layout_width=\"0dp\"\n                android:layout_weight=\"1\"\n                android:padding=\"@dimen/default_16dp\"\n                android:orientation=\"vertical\"\n                android:layout_height=\"wrap_content\">\n\n                <LinearLayout\n                    android:layout_width=\"match_parent\"\n                    android:orientation=\"horizontal\"\n                    android:layout_height=\"wrap_content\">\n\n                    <TextView\n                        android:id=\"@+id/partner_name\"\n                        android:textAppearance=\"?android:textAppearanceMedium\"\n                        android:textColor=\"#ffffff\"\n                        android:fontFamily=\"@string/font_normal\"\n                        android:singleLine=\"true\"\n                        android:ellipsize=\"end\"\n                        android:layout_marginRight=\"5dp\"\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"wrap_content\" />\n\n                    <TextView\n                        android:id=\"@+id/company_name\"\n                        android:textAppearance=\"?android:textAppearanceSmall\"\n                        android:textColor=\"#ebebeb\"\n                        android:textStyle=\"italic\"\n                        android:fontFamily=\"@string/font_condensed\"\n                        android:singleLine=\"true\"\n                        android:ellipsize=\"end\"\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"wrap_content\" />\n\n                </LinearLayout>\n\n                <TextView\n                    android:id=\"@+id/leadName\"\n                    android:textAppearance=\"?android:textAppearanceSmall\"\n                    android:textColor=\"#99ffffff\"\n                    android:fontFamily=\"@string/font_normal\"\n                    android:maxLines=\"2\"\n                    android:ellipsize=\"middle\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\" />\n\n                <TextView\n                    android:id=\"@+id/oppProbability\"\n                    android:textAppearance=\"?android:textAppearanceSmall\"\n                    android:textColor=\"#bbffffff\"\n                    android:layout_marginTop=\"5dp\"\n                    android:fontFamily=\"@string/font_normal\"\n                    android:singleLine=\"true\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\" />\n\n                <TextView\n                    android:id=\"@+id/partner_contact\"\n                    android:textAppearance=\"?android:textAppearanceLarge\"\n                    android:textColor=\"#ffffff\"\n                    android:fontFamily=\"@string/font_normal\"\n                    android:singleLine=\"true\"\n                    android:ellipsize=\"end\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\" />\n\n            </LinearLayout>\n        </LinearLayout>\n\n\n        <ImageView\n            android:src=\"@drawable/odoo_small\"\n            android:tint=\"#ffffff\"\n            android:layout_marginRight=\"@dimen/default_16dp\"\n            android:layout_marginBottom=\"5dp\"\n            android:layout_width=\"60dp\"\n            android:layout_marginTop=\"@dimen/default_8dp\"\n            android:layout_marginLeft=\"@dimen/default_16dp\"\n            android:layout_gravity=\"bottom|left\"\n            android:layout_height=\"wrap_content\" />\n    </FrameLayout>\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/crm_convert_to_opportunity.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:orientation=\"vertical\"\n    android:layout_width=\"match_parent\"\n    android:background=\"@android:color/white\"\n    android:layout_height=\"match_parent\">\n\n    <TextView\n        android:id=\"@+id/title\"\n        android:textColor=\"@color/body_text_1\"\n        android:text=\"@string/label_convert_to_opportunity\"\n        android:layout_width=\"match_parent\"\n        android:textAppearance=\"?android:textAppearanceMedium\"\n        android:fontFamily=\"@string/font_normal\"\n        android:padding=\"@dimen/default_16dp\"\n        android:layout_height=\"wrap_content\" />\n\n    <View style=\"@style/ViewSeparator\" />\n\n    <ScrollView\n        android:layout_width=\"match_parent\"\n        android:layout_weight=\"1\"\n        android:fillViewport=\"true\"\n        android:layout_height=\"0dp\">\n\n        <LinearLayout\n            android:orientation=\"vertical\"\n            android:padding=\"@dimen/default_8dp\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\">\n\n            <odoo.controls.OForm\n                android:id=\"@+id/convert_form\"\n                android:layout_width=\"match_parent\"\n                app:modelName=\"crm.lead\"\n                android:orientation=\"vertical\"\n                android:layout_height=\"wrap_content\">\n\n                <odoo.controls.OField\n                    android:id=\"@+id/conversation_action\"\n                    app:fieldName=\"conversation_action\"\n                    app:showIcon=\"false\"\n                    app:controlLabel=\"@string/label_conversion_action\"\n                    app:fieldType=\"Selection\"\n                    app:defaultValue=\"2\"\n                    app:fieldLabelColor=\"@color/body_text_3\"\n                    app:fieldTextAppearance=\"?android:textAppearanceMedium\"\n                    app:valueArray=\"@array/array_conversation_actions\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"></odoo.controls.OField>\n\n                <LinearLayout\n                    android:id=\"@+id/opportunity_container\"\n                    android:layout_width=\"match_parent\"\n                    android:orientation=\"vertical\"\n                    android:layout_height=\"wrap_content\">\n\n                    <TextView\n                        android:textColor=\"@color/body_text_3\"\n                        android:text=\"@string/label_opportunities\"\n                        android:layout_width=\"match_parent\"\n                        android:textAllCaps=\"true\"\n                        android:paddingLeft=\"@dimen/default_16dp\"\n                        android:paddingRight=\"@dimen/default_16dp\"\n                        android:layout_height=\"wrap_content\" />\n\n                    <com.odoo.core.utils.controls.ExpandableHeightGridView\n                        android:layout_width=\"match_parent\"\n                        android:numColumns=\"1\"\n                        android:id=\"@+id/opportunities\"\n                        android:layout_height=\"wrap_content\">\n\n                        </com.odoo.core.utils.controls.ExpandableHeightGridView>\n                </LinearLayout>\n            </odoo.controls.OForm>\n        </LinearLayout>\n    </ScrollView>\n\n    <View style=\"@style/ViewSeparator\" />\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:showDividers=\"middle\"\n        android:divider=\"?android:attr/dividerHorizontal\"\n        android:orientation=\"horizontal\">\n\n        <Button\n            android:id=\"@+id/create_opportunity\"\n            style=\"?android:attr/borderlessButtonStyle\"\n            android:layout_width=\"0dp\"\n            android:layout_weight=\"1\"\n            android:layout_height=\"match_parent\"\n            android:background=\"?android:selectableItemBackground\"\n            android:gravity=\"center\"\n            android:fontFamily=\"@string/font_normal\"\n            android:padding=\"@dimen/default_16dp\"\n            android:text=\"@string/label_create_opportunity\"\n            android:textAllCaps=\"true\"\n            android:textColor=\"@color/body_text_1\"\n            android:textSize=\"@dimen/text_size_medium\" />\n\n        <Button\n            android:id=\"@+id/cancel\"\n            style=\"?android:attr/borderlessButtonStyle\"\n            android:layout_width=\"0dp\"\n            android:layout_weight=\"1\"\n            android:fontFamily=\"@string/font_normal\"\n            android:layout_height=\"match_parent\"\n            android:background=\"?android:selectableItemBackground\"\n            android:gravity=\"center\"\n            android:padding=\"@dimen/default_16dp\"\n            android:text=\"@string/label_cancel\"\n            android:textAllCaps=\"true\"\n            android:textColor=\"@color/body_text_2\"\n            android:textSize=\"@dimen/text_size_medium\" />\n    </LinearLayout>\n\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/crm_convert_to_opportunity_item.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:orientation=\"vertical\"\n    android:paddingRight=\"@dimen/default_16dp\"\n    android:paddingLeft=\"@dimen/default_16dp\"\n    android:paddingTop=\"@dimen/default_8dp\"\n    android:paddingBottom=\"@dimen/default_8dp\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:orientation=\"horizontal\"\n        android:gravity=\"center_vertical\"\n        android:layout_height=\"wrap_content\">\n\n        <TextView\n            android:id=\"@+id/name\"\n            android:textAppearance=\"?android:textAppearanceSmall\"\n            android:layout_width=\"0dp\"\n            android:textColor=\"@color/body_text_1\"\n            android:layout_weight=\"1\"\n            android:singleLine=\"true\"\n            android:ellipsize=\"marquee\"\n            android:paddingRight=\"5dp\"\n            android:layout_height=\"wrap_content\" />\n\n        <ImageView\n            android:id=\"@+id/remove_lead\"\n            android:padding=\"5dp\"\n            android:src=\"@drawable/ic_action_navigation_close\"\n            android:layout_width=\"wrap_content\"\n            android:tint=\"@color/android_red_dark\"\n            android:layout_height=\"wrap_content\" />\n    </LinearLayout>\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:orientation=\"horizontal\"\n        android:gravity=\"center_vertical\"\n        android:layout_height=\"wrap_content\">\n\n        <TextView\n            android:id=\"@+id/type\"\n            android:textAppearance=\"?android:textAppearanceSmall\"\n            android:layout_width=\"wrap_content\"\n            android:singleLine=\"true\"\n            android:textColor=\"@color/body_text_2\"\n            android:paddingRight=\"5dp\"\n            android:layout_height=\"wrap_content\" />\n\n        <TextView\n            android:id=\"@+id/stage\"\n            android:textAppearance=\"?android:textAppearanceSmall\"\n            android:layout_width=\"wrap_content\"\n            android:textColor=\"@color/android_violet_dark\"\n            android:paddingRight=\"5dp\"\n            android:layout_height=\"wrap_content\" />\n\n        <TextView\n            android:id=\"@+id/create_date\"\n            android:textAppearance=\"?android:textAppearanceSmall\"\n            android:layout_width=\"wrap_content\"\n            android:textColor=\"@color/body_text_2\"\n            android:layout_height=\"wrap_content\" />\n    </LinearLayout>\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/crm_convert_to_quotation.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:orientation=\"vertical\"\n    android:layout_width=\"match_parent\"\n    android:background=\"@android:color/white\"\n    android:layout_height=\"match_parent\">\n\n    <TextView\n        android:id=\"@+id/title\"\n        android:textColor=\"@color/body_text_1\"\n        android:text=\"@string/label_convert_to_quotation\"\n        android:layout_width=\"match_parent\"\n        android:textAppearance=\"?android:textAppearanceMedium\"\n        android:fontFamily=\"@string/font_normal\"\n        android:padding=\"@dimen/default_16dp\"\n        android:layout_height=\"wrap_content\" />\n\n    <View style=\"@style/ViewSeparator\" />\n\n    <ScrollView\n        android:layout_width=\"match_parent\"\n        android:layout_weight=\"1\"\n        android:fillViewport=\"true\"\n        android:layout_height=\"0dp\">\n\n        <LinearLayout\n            android:orientation=\"vertical\"\n            android:padding=\"@dimen/default_8dp\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\">\n\n            <odoo.controls.OForm\n                android:id=\"@+id/convert_form\"\n                android:layout_width=\"match_parent\"\n                app:modelName=\"crm.lead\"\n                android:orientation=\"vertical\"\n                android:layout_height=\"wrap_content\">\n\n                <odoo.controls.OField\n                    android:id=\"@+id/partner\"\n                    app:fieldName=\"partner_id\"\n                    app:showIcon=\"false\"\n                    app:showLabel=\"false\"\n                    app:widgetType=\"SearchableLive\"\n                    app:fieldLabelColor=\"@color/body_text_3\"\n                    app:fieldTextAppearance=\"?android:textAppearanceMedium\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"></odoo.controls.OField>\n\n                <odoo.controls.OField\n                    android:id=\"@+id/mark_won\"\n                    app:fieldName=\"mark_won\"\n                    app:showIcon=\"false\"\n                    app:showLabel=\"false\"\n                    app:controlLabel=\"Mark won\"\n                    app:fieldType=\"Boolean\"\n                    app:defaultValue=\"false\"\n                    app:fieldLabelColor=\"@color/body_text_3\"\n                    app:fieldTextAppearance=\"?android:textAppearanceMedium\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"></odoo.controls.OField>\n            </odoo.controls.OForm>\n        </LinearLayout>\n    </ScrollView>\n\n    <View style=\"@style/ViewSeparator\" />\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:showDividers=\"middle\"\n        android:divider=\"?android:attr/dividerHorizontal\"\n        android:orientation=\"horizontal\">\n\n        <Button\n            android:id=\"@+id/create_quotation\"\n            style=\"?android:attr/borderlessButtonStyle\"\n            android:layout_width=\"0dp\"\n            android:layout_weight=\"1\"\n            android:layout_height=\"match_parent\"\n            android:background=\"?android:selectableItemBackground\"\n            android:gravity=\"center\"\n            android:fontFamily=\"@string/font_normal\"\n            android:padding=\"@dimen/default_16dp\"\n            android:text=\"@string/label_create_quotation\"\n            android:textAllCaps=\"true\"\n            android:textColor=\"@color/body_text_1\"\n            android:textSize=\"@dimen/text_size_medium\" />\n\n        <Button\n            android:id=\"@+id/cancel\"\n            style=\"?android:attr/borderlessButtonStyle\"\n            android:layout_width=\"0dp\"\n            android:layout_weight=\"1\"\n            android:fontFamily=\"@string/font_normal\"\n            android:layout_height=\"match_parent\"\n            android:background=\"?android:selectableItemBackground\"\n            android:gravity=\"center\"\n            android:padding=\"@dimen/default_16dp\"\n            android:text=\"@string/label_cancel\"\n            android:textAllCaps=\"true\"\n            android:textColor=\"@color/body_text_2\"\n            android:textSize=\"@dimen/text_size_medium\" />\n    </LinearLayout>\n\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/crm_detail.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:orientation=\"vertical\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <android.support.v7.widget.Toolbar\n        android:id=\"@+id/toolbar\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:background=\"@color/theme_primary\"\n        android:minHeight=\"?attr/actionBarSize\"\n        app:titleMarginStart=\"@dimen/default_16dp\"\n        android:paddingTop=\"@dimen/statusBarHeight\"\n        android:paddingRight=\"@dimen/default_8dp\"\n        app:popupTheme=\"@style/ThemeOverlay.AppCompat.Dark\"\n        app:theme=\"@style/ToolBarTheme\" />\n\n    <ScrollView\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\">\n\n        <odoo.controls.OForm\n            android:id=\"@+id/crmLeadForm\"\n            android:orientation=\"vertical\"\n            app:controlIconTint=\"@color/body_text_3\"\n            app:modelName=\"crm.lead\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\">\n\n            <odoo.controls.OField\n                android:layout_width=\"match_parent\"\n                app:fieldName=\"name\"\n                app:showLabel=\"false\"\n                app:showIcon=\"false\"\n                app:fieldTextAppearance=\"?android:textAppearanceMedium\"\n                app:controlLabel=\"@string/label_define_lead\"\n                app:fieldTextSize=\"@dimen/text_size_xmedium\"\n                android:layout_height=\"wrap_content\">\n\n            </odoo.controls.OField>\n\n            <View style=\"@style/ViewSeparator\" />\n\n            <LinearLayout\n                android:id=\"@+id/opportunity_controls\"\n                android:layout_width=\"match_parent\"\n                android:orientation=\"vertical\"\n                android:visibility=\"gone\"\n                android:layout_height=\"wrap_content\">\n\n                <TextView\n                    android:textAppearance=\"?android:textAppearanceSmall\"\n                    android:text=\"@string/label_expected_revenue\"\n                    android:textAllCaps=\"true\"\n                    android:textColor=\"#414141\"\n                    android:paddingLeft=\"@dimen/default_16dp\"\n                    android:layout_width=\"match_parent\"\n                    android:paddingTop=\"@dimen/default_8dp\"\n                    android:layout_height=\"wrap_content\" />\n\n                <LinearLayout\n                    android:layout_width=\"match_parent\"\n                    android:orientation=\"horizontal\"\n                    android:paddingLeft=\"16dp\"\n                    android:paddingRight=\"@dimen/default_16dp\"\n                    android:paddingBottom=\"@dimen/default_16dp\"\n                    android:layout_height=\"56dp\">\n\n\n                    <odoo.controls.OField\n                        app:fieldLabelTextAppearance=\"?android:textAppearanceSmall\"\n                        android:layout_width=\"100dp\"\n                        app:fieldName=\"planned_revenue\"\n                        app:showLabel=\"false\"\n                        app:showIcon=\"false\"\n                        app:defaultValue=\"0.0\"\n                        app:withOutSidePadding=\"false\"\n                        app:fieldTextAppearance=\"?android:textAppearanceMedium\"\n                        app:fieldTextSize=\"@dimen/text_size_xmedium\"\n                        android:layout_height=\"wrap_content\"></odoo.controls.OField>\n\n                    <TextView\n                        android:id=\"@+id/currency_symbol\"\n                        android:textAppearance=\"?android:textAppearanceMedium\"\n                        android:gravity=\"center_vertical\"\n                        android:textColor=\"@color/body_text_2\"\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"match_parent\" />\n\n                    <TextView\n                        android:textAppearance=\"?android:textAppearanceMedium\"\n                        android:textStyle=\"bold\"\n                        android:text=\"@string/label_at\"\n                        android:paddingRight=\"@dimen/default_8dp\"\n                        android:paddingLeft=\"5dp\"\n                        android:gravity=\"center_vertical\"\n                        android:textColor=\"@color/body_text_3\"\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"match_parent\" />\n\n\n                    <odoo.controls.OField\n                        app:withOutSidePadding=\"false\"\n                        android:layout_width=\"100dp\"\n                        app:fieldName=\"probability\"\n                        app:showLabel=\"false\"\n                        app:defaultValue=\"0.0\"\n                        app:fieldTextAppearance=\"?android:textAppearanceMedium\"\n                        app:showIcon=\"false\"\n                        app:fieldTextSize=\"@dimen/text_size_xmedium\"\n                        android:layout_height=\"match_parent\"></odoo.controls.OField>\n\n                    <TextView\n                        android:textAppearance=\"?android:textAppearanceMedium\"\n                        android:text=\" % \"\n                        android:textColor=\"@color/body_text_2\"\n                        android:gravity=\"center_vertical\"\n                        android:layout_width=\"0dp\"\n                        android:layout_weight=\"1\"\n                        android:layout_height=\"match_parent\" />\n                </LinearLayout>\n\n                <View style=\"@style/ViewSeparator\" />\n\n                <odoo.controls.OField\n                    android:layout_width=\"match_parent\"\n                    app:fieldName=\"date_action\"\n                    app:parsePattern=\"MMM dd, yyyy\"\n                    app:fieldTextAppearance=\"?android:textAppearanceMedium\"\n                    app:iconResource=\"@drawable/ic_action_time_clock\"\n                    app:fieldTextSize=\"@dimen/text_size_xmedium\"\n                    android:layout_height=\"wrap_content\"></odoo.controls.OField>\n\n                <odoo.controls.OField\n                    android:layout_width=\"match_parent\"\n                    app:fieldName=\"title_action\"\n                    app:showLabel=\"false\"\n                    app:withTopPadding=\"false\"\n                    app:fieldTextAppearance=\"?android:textAppearanceMedium\"\n                    app:fieldTextSize=\"@dimen/text_size_xmedium\"\n                    android:layout_height=\"wrap_content\"></odoo.controls.OField>\n\n                <View\n                    style=\"@style/ViewSeparator\"\n                    android:layout_marginLeft=\"72dp\" />\n\n                <odoo.controls.OField\n                    android:layout_width=\"match_parent\"\n                    app:fieldName=\"date_deadline\"\n                    app:fieldTextAppearance=\"?android:textAppearanceMedium\"\n                    app:parsePattern=\"MMM dd, yyyy\"\n                    app:fieldTextSize=\"@dimen/text_size_xmedium\"\n                    android:layout_height=\"wrap_content\"></odoo.controls.OField>\n\n                <View style=\"@style/ViewSeparator\" />\n            </LinearLayout>\n\n            <odoo.controls.OField\n                app:iconResource=\"@drawable/ic_action_user\"\n                android:layout_width=\"match_parent\"\n                app:fieldName=\"contact_name\"\n                app:fieldTextAppearance=\"?android:textAppearanceMedium\"\n                app:fieldTextSize=\"@dimen/text_size_xmedium\"\n                android:layout_height=\"wrap_content\">\n\n            </odoo.controls.OField>\n\n            <odoo.controls.OField\n                android:layout_width=\"match_parent\"\n                app:fieldName=\"partner_name\"\n                app:fieldTextAppearance=\"?android:textAppearanceMedium\"\n                app:fieldTextSize=\"@dimen/text_size_xmedium\"\n                android:layout_height=\"wrap_content\">\n\n            </odoo.controls.OField>\n\n            <odoo.controls.OField\n                android:layout_width=\"match_parent\"\n                app:fieldName=\"partner_id\"\n                app:fieldTextAppearance=\"?android:textAppearanceMedium\"\n                app:fieldTextSize=\"@dimen/text_size_xmedium\"\n                app:widgetType=\"SearchableLive\"\n                android:layout_height=\"wrap_content\">\n\n            </odoo.controls.OField>\n\n            <View\n                style=\"@style/ViewSeparator\"\n                android:layout_marginLeft=\"72dp\" />\n\n\n            <odoo.controls.OField\n                android:layout_width=\"match_parent\"\n                app:fieldName=\"email_from\"\n                app:fieldTextAppearance=\"?android:textAppearanceMedium\"\n                app:fieldTextSize=\"@dimen/text_size_xmedium\"\n                app:iconResource=\"@drawable/ic_action_message\"\n                android:layout_height=\"wrap_content\">\n\n            </odoo.controls.OField>\n\n            <View\n                style=\"@style/ViewSeparator\"\n                android:layout_marginLeft=\"72dp\" />\n\n            <odoo.controls.OField\n                android:layout_width=\"match_parent\"\n                app:fieldName=\"phone\"\n                app:fieldTextAppearance=\"?android:textAppearanceMedium\"\n                app:iconResource=\"@drawable/ic_action_phone\"\n                app:fieldTextSize=\"@dimen/text_size_xmedium\"\n                android:layout_height=\"wrap_content\">\n\n            </odoo.controls.OField>\n\n            <odoo.controls.OField\n                android:layout_width=\"match_parent\"\n                app:fieldName=\"mobile\"\n                app:fieldTextAppearance=\"?android:textAppearanceMedium\"\n                app:iconResource=\"@drawable/ic_action_mobile\"\n                app:fieldTextSize=\"@dimen/text_size_xmedium\"\n                android:layout_height=\"wrap_content\">\n\n            </odoo.controls.OField>\n\n            <View\n                style=\"@style/ViewSeparator\"\n                android:layout_marginLeft=\"72dp\" />\n\n            <odoo.controls.OField\n                android:layout_width=\"match_parent\"\n                app:fieldName=\"description\"\n                app:fieldTextAppearance=\"?android:textAppearanceMedium\"\n                app:iconResource=\"@drawable/ic_action_notes_content\"\n                app:fieldTextSize=\"@dimen/text_size_xmedium\"\n                android:layout_height=\"wrap_content\">\n\n            </odoo.controls.OField>\n\n        </odoo.controls.OForm>\n    </ScrollView>\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/crm_item.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:orientation=\"vertical\"\n    android:layout_width=\"match_parent\"\n    android:padding=\"@dimen/default_16dp\"\n    android:layout_height=\"match_parent\">\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:orientation=\"horizontal\"\n        android:gravity=\"top\"\n        android:layout_height=\"wrap_content\">\n\n        <TextView\n            android:id=\"@+id/name\"\n            android:textAppearance=\"?android:textAppearanceMedium\"\n            android:fontFamily=\"@string/font_normal\"\n            android:textColor=\"@color/body_text_1\"\n            android:layout_width=\"0dp\"\n            android:layout_weight=\"1\"\n            android:ellipsize=\"end\"\n            android:layout_marginRight=\"5dp\"\n            android:layout_height=\"wrap_content\" />\n\n        <TextView\n            android:id=\"@+id/stage\"\n            android:background=\"@drawable/tag_background\"\n            android:fontFamily=\"@string/font_condensed\"\n            android:textColor=\"#ffffff\"\n            android:padding=\"3dp\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\" />\n\n        <ImageView\n            android:visibility=\"gone\"\n            android:id=\"@+id/stage_move\"\n            android:padding=\"3dp\"\n            android:tint=\"@color/theme_secondary\"\n            android:src=\"@drawable/ic_action_move_to\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\" />\n    </LinearLayout>\n\n    <TextView\n        android:id=\"@+id/display_name\"\n        android:textAppearance=\"?android:textAppearanceSmall\"\n        android:fontFamily=\"@string/font_normal\"\n        android:textColor=\"@color/body_text_3\"\n        android:layout_width=\"match_parent\"\n        android:singleLine=\"true\"\n        android:layout_height=\"wrap_content\" />\n\n    <!-- Used for opportunity -->\n    <LinearLayout\n        android:id=\"@+id/opportunity_controls\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"vertical\">\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:orientation=\"horizontal\">\n\n            <TextView\n                android:id=\"@+id/date_action\"\n                android:fontFamily=\"@string/font_normal\"\n                android:textColor=\"@color/body_text_2\"\n                android:textStyle=\"bold\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\" />\n\n\n            <TextView\n                android:id=\"@+id/title_action\"\n                android:fontFamily=\"@string/font_normal\"\n                android:textColor=\"@color/body_text_2\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\" />\n        </LinearLayout>\n    </LinearLayout>\n    <!-- Opportunity controls end//-->\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"horizontal\">\n\n        <TextView\n            android:id=\"@+id/assignee_name\"\n            android:textAppearance=\"?android:textAppearanceSmall\"\n            android:fontFamily=\"@string/font_normal\"\n            android:textColor=\"@color/theme_secondary\"\n            android:layout_width=\"0dp\"\n            android:layout_weight=\"1\"\n            android:singleLine=\"true\"\n            android:ellipsize=\"end\"\n            android:layout_marginRight=\"5dp\"\n            android:layout_height=\"wrap_content\" />\n\n        <TextView\n            android:id=\"@+id/create_date\"\n            android:fontFamily=\"@string/font_condensed\"\n            android:textColor=\"@color/body_text_2\"\n            android:padding=\"3dp\"\n            android:textStyle=\"bold\"\n            android:textAppearance=\"?android:textAppearanceSmall\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\" />\n    </LinearLayout>\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/crm_opportunity_pagger.xml",
    "content": "<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n    <android.support.v4.view.ViewPager\n        android:id=\"@+id/pager\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\">\n\n        <android.support.v4.view.PagerTabStrip\n            android:id=\"@+id/pager_title_strip\"\n            style=\"?android:attr/textAppearanceSmall\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"top\"\n            android:paddingLeft=\"16dp\"\n            android:background=\"@color/theme_primary\"\n            android:paddingBottom=\"@dimen/default_8dp\"\n            android:paddingRight=\"16dp\" />\n\n    </android.support.v4.view.ViewPager>\n\n    <android.support.v4.widget.SwipeRefreshLayout\n        android:id=\"@+id/no_items_found\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:visibility=\"gone\">\n\n        <include layout=\"@layout/base_no_items_view\" />\n    </android.support.v4.widget.SwipeRefreshLayout>\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/crm_phonecall_detail.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:orientation=\"vertical\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <android.support.v7.widget.Toolbar\n        android:id=\"@+id/toolbar\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:background=\"@color/theme_primary\"\n        android:minHeight=\"?attr/actionBarSize\"\n        app:titleMarginStart=\"@dimen/default_16dp\"\n        android:paddingTop=\"@dimen/statusBarHeight\"\n        android:paddingRight=\"@dimen/default_8dp\"\n        app:popupTheme=\"@style/ThemeOverlay.AppCompat.Dark\"\n        app:theme=\"@style/ToolBarTheme\" />\n\n    <ScrollView\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\">\n\n        <odoo.controls.OForm\n            android:id=\"@+id/phoneLogForm\"\n            app:modelName=\"crm.phonecall\"\n            app:controlIconTint=\"@color/body_text_2\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\">\n\n            <odoo.controls.OField\n                android:layout_width=\"match_parent\"\n                app:fieldName=\"name\"\n                app:showLabel=\"false\"\n                app:showIcon=\"false\"\n                app:fieldTextAppearance=\"?android:textAppearanceMedium\"\n                app:controlLabel=\"Define the lead\"\n                app:fieldTextSize=\"@dimen/text_size_xmedium\"\n                android:layout_height=\"wrap_content\">\n\n            </odoo.controls.OField>\n\n            <View style=\"@style/ViewSeparator\" />\n\n            <odoo.controls.OField\n                android:layout_width=\"match_parent\"\n                app:fieldName=\"partner_phone\"\n                app:iconResource=\"@drawable/ic_action_phone\"\n                app:fieldTextSize=\"@dimen/text_size_xmedium\"\n                android:layout_height=\"wrap_content\">\n\n            </odoo.controls.OField>\n\n            <View\n                style=\"@style/ViewSeparator\"\n                android:layout_marginLeft=\"72dp\" />\n\n            <odoo.controls.OField\n                android:id=\"@+id/partner_id\"\n                android:layout_width=\"match_parent\"\n                app:fieldName=\"partner_id\"\n                app:widgetType=\"SearchableLive\"\n                app:iconResource=\"@drawable/ic_action_user\"\n                app:fieldTextSize=\"@dimen/text_size_xmedium\"\n                android:layout_height=\"wrap_content\">\n\n            </odoo.controls.OField>\n\n            <View\n                style=\"@style/ViewSeparator\"\n                android:layout_marginLeft=\"72dp\" />\n\n            <odoo.controls.OField\n                android:id=\"@+id/opportunity_id\"\n                android:layout_width=\"match_parent\"\n                app:fieldName=\"opportunity_id\"\n                app:widgetType=\"Searchable\"\n                app:iconResource=\"@drawable/ic_action_opportunities\"\n                app:fieldTextSize=\"@dimen/text_size_xmedium\"\n                android:layout_height=\"wrap_content\">\n\n            </odoo.controls.OField>\n\n            <LinearLayout\n                android:visibility=\"gone\"\n                android:id=\"@+id/opportunity_action_container\"\n                android:layout_width=\"match_parent\"\n                android:orientation=\"vertical\"\n                android:layout_height=\"wrap_content\">\n\n                <odoo.controls.OForm\n                    android:id=\"@+id/opportunity_action_form\"\n                    android:layout_width=\"match_parent\"\n                    app:modelName=\"crm.lead\"\n                    android:orientation=\"vertical\"\n                    android:layout_height=\"wrap_content\">\n\n                    <odoo.controls.OField\n                        app:fieldName=\"date_action\"\n                        app:parsePattern=\"MMM dd, yyyy\"\n                        app:iconResource=\"@drawable/ic_action_next_action\"\n                        android:layout_width=\"match_parent\"\n                        app:iconTint=\"@color/body_text_3\"\n                        app:fieldTextSize=\"@dimen/text_size_xmedium\"\n                        android:layout_height=\"wrap_content\"></odoo.controls.OField>\n\n                    <odoo.controls.OField\n                        app:showLabel=\"false\"\n                        app:fieldTextSize=\"@dimen/text_size_xmedium\"\n                        app:fieldName=\"title_action\"\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"wrap_content\"></odoo.controls.OField>\n                </odoo.controls.OForm>\n            </LinearLayout>\n\n            <View\n                style=\"@style/ViewSeparator\"\n                android:layout_marginLeft=\"72dp\" />\n\n            <odoo.controls.OField\n                android:id=\"@+id/phoneCallDate\"\n                android:layout_width=\"match_parent\"\n                app:fieldName=\"date\"\n                app:parsePattern=\"MMM, dd hh:mm a\"\n                app:defaultValue=\"now()\"\n                app:iconResource=\"@drawable/ic_action_time_clock\"\n                app:fieldTextSize=\"@dimen/text_size_xmedium\"\n                android:layout_height=\"wrap_content\">\n\n            </odoo.controls.OField>\n\n            <LinearLayout\n                android:id=\"@+id/reminderForPhoneCall\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"56dp\"\n                android:gravity=\"center_vertical|top\"\n                android:background=\"?android:attr/selectableItemBackground\"\n                android:orientation=\"horizontal\"\n                android:paddingBottom=\"8dp\"\n                android:paddingLeft=\"16dp\"\n                android:paddingRight=\"16dp\"\n                android:paddingTop=\"8dp\">\n\n                <ImageView\n                    android:layout_width=\"40dp\"\n                    android:layout_height=\"40dp\"\n                    android:layout_gravity=\"top\"\n                    android:layout_marginRight=\"3dp\"\n                    android:paddingBottom=\"5dp\"\n                    android:src=\"@drawable/ic_action_bell\"\n                    android:tint=\"@color/body_text_2\" />\n\n                <TextView\n                    android:id=\"@+id/reminderTypeName\"\n                    android:layout_width=\"0dp\"\n                    android:layout_height=\"match_parent\"\n                    android:layout_weight=\"1\"\n                    android:textColor=\"@color/body_text_2\"\n                    android:background=\"@android:color/transparent\"\n                    android:fontFamily=\"@string/font_normal\"\n                    android:gravity=\"center_vertical\"\n                    android:paddingLeft=\"16dp\"\n                    android:text=\"@string/at_the_time_of_event\"\n                    android:textSize=\"@dimen/text_size_xmedium\" />\n            </LinearLayout>\n\n            <odoo.controls.OField\n                android:layout_width=\"match_parent\"\n                app:fieldName=\"duration\"\n                app:fieldTextSize=\"@dimen/text_size_xmedium\"\n                app:widgetType=\"Duration\"\n                android:layout_height=\"wrap_content\">\n\n            </odoo.controls.OField>\n\n            <View\n                style=\"@style/ViewSeparator\"\n                android:layout_marginLeft=\"72dp\" />\n\n            <odoo.controls.OField\n                android:layout_width=\"match_parent\"\n                app:fieldName=\"categ_id\"\n                app:iconResource=\"@drawable/ic_action_in_out\"\n                app:fieldTextSize=\"@dimen/text_size_xmedium\"\n                android:layout_height=\"wrap_content\">\n\n            </odoo.controls.OField>\n\n            <View\n                style=\"@style/ViewSeparator\"\n                android:layout_marginLeft=\"72dp\" />\n\n            <odoo.controls.OField\n                android:layout_width=\"match_parent\"\n                app:fieldName=\"description\"\n                app:iconResource=\"@drawable/ic_action_notes_content\"\n                app:fieldTextSize=\"@dimen/text_size_xmedium\"\n                android:layout_height=\"wrap_content\">\n\n            </odoo.controls.OField>\n        </odoo.controls.OForm>\n    </ScrollView>\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/customer_detail.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:layout_width=\"match_parent\"\n    android:orientation=\"vertical\"\n    android:background=\"#ffffff\"\n    android:layout_height=\"match_parent\">\n\n\n    <com.odoo.widgets.parallax.ParallaxScrollView\n        android:id=\"@+id/parallaxScrollView\"\n        android:layout_width=\"match_parent\"\n        android:paddingTop=\"@dimen/statusBarHeight\"\n        android:clipToPadding=\"false\"\n        android:layout_height=\"wrap_content\">\n\n        <RelativeLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\">\n\n            <FrameLayout\n                android:id=\"@+id/parallax_view\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginBottom=\"-56dp\">\n\n                <ImageView\n                    android:id=\"@android:id/icon\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"380dp\"\n                    android:scaleType=\"centerInside\"\n                    android:src=\"@drawable/user_xlarge\" />\n            </FrameLayout>\n\n            <TextView\n                android:id=\"@android:id/title\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"56dp\"\n                android:layout_below=\"@+id/parallax_view\"\n                android:gravity=\"center_vertical\"\n                android:fontFamily=\"@string/font_normal\"\n                android:singleLine=\"true\"\n                android:paddingLeft=\"@dimen/default_16dp\"\n                android:textColor=\"#ffffff\"\n                android:textSize=\"30sp\" />\n\n            <LinearLayout\n                android:layout_below=\"@android:id/title\"\n                android:orientation=\"vertical\"\n                android:background=\"#ffffff\"\n                android:paddingTop=\"@dimen/default_16dp\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\">\n                <odoo.controls.OForm\n                    android:id=\"@+id/customerForm\"\n                    android:layout_width=\"match_parent\"\n                    app:modelName=\"res.partner\"\n                    android:orientation=\"vertical\"\n                    android:layout_height=\"wrap_content\">\n\n                    <odoo.controls.OField\n                        android:id=\"@+id/is_company\"\n                        android:layout_width=\"match_parent\"\n                        app:fieldName=\"is_company\"\n                        app:showLabel=\"false\"\n                        app:fieldTextAppearance=\"?android:textAppearanceMedium\"\n                        android:layout_height=\"wrap_content\"></odoo.controls.OField>\n\n                    <odoo.controls.OField\n                        android:id=\"@+id/website\"\n                        app:fieldTextAppearance=\"?android:textAppearanceMedium\"\n                        app:fieldLabelColor=\"@color/theme_secondary\"\n                        app:iconResource=\"@drawable/ic_action_universe\"\n                        android:layout_width=\"match_parent\"\n                        app:fieldName=\"website\"\n                        android:layout_height=\"wrap_content\"></odoo.controls.OField>\n\n\n                    <odoo.controls.OField\n                        app:fieldTextAppearance=\"?android:textAppearanceMedium\"\n                        app:fieldLabelColor=\"@color/theme_secondary\"\n                        android:id=\"@+id/email\"\n                        app:iconResource=\"@drawable/ic_action_message\"\n                        android:layout_width=\"match_parent\"\n                        app:fieldName=\"email\"\n                        android:layout_height=\"wrap_content\"></odoo.controls.OField>\n\n                    <View\n                        style=\"@style/ViewSeparator\"\n                        android:layout_marginLeft=\"72dp\" />\n\n                    <odoo.controls.OField\n                        android:id=\"@+id/phone_number\"\n                        app:fieldLabelColor=\"@color/theme_secondary\"\n                        app:fieldTextAppearance=\"?android:textAppearanceMedium\"\n                        app:iconResource=\"@drawable/ic_action_phone\"\n                        android:layout_width=\"match_parent\"\n                        app:fieldName=\"phone\"\n                        android:layout_height=\"wrap_content\"></odoo.controls.OField>\n\n                    <odoo.controls.OField\n                        app:fieldTextAppearance=\"?android:textAppearanceMedium\"\n                        app:fieldLabelColor=\"@color/theme_secondary\"\n                        app:iconResource=\"@drawable/ic_action_mobile\"\n                        android:layout_width=\"match_parent\"\n                        app:fieldName=\"mobile\"\n                        android:id=\"@+id/mobile_number\"\n                        android:layout_height=\"wrap_content\"></odoo.controls.OField>\n\n                    <View\n                        style=\"@style/ViewSeparator\"\n                        android:layout_marginLeft=\"72dp\" />\n\n                    <odoo.controls.OField\n                        android:id=\"@+id/full_address\"\n                        android:layout_width=\"match_parent\"\n                        app:fieldName=\"full_address\"\n                        app:controlLabel=\"@string/label_address\"\n                        app:fieldLabelColor=\"@color/theme_secondary\"\n                        app:iconResource=\"@drawable/ic_action_location\"\n                        app:fieldTextAppearance=\"?android:textAppearanceMedium\"\n                        android:layout_height=\"wrap_content\"></odoo.controls.OField>\n\n                    <odoo.controls.OField\n                        android:layout_width=\"match_parent\"\n                        app:fieldName=\"country_id\"\n                        app:fieldLabelColor=\"@color/theme_secondary\"\n                        app:fieldTextAppearance=\"?android:textAppearanceMedium\"\n                        android:layout_height=\"wrap_content\"></odoo.controls.OField>\n\n\n                    <View\n                        style=\"@style/ViewSeparator\"\n                        android:layout_marginLeft=\"72dp\" />\n\n                    <odoo.controls.OField\n                        android:layout_width=\"match_parent\"\n                        app:iconResource=\"@drawable/ic_action_notes_content\"\n                        app:fieldName=\"comment\"\n                        app:fieldLabelColor=\"@color/theme_secondary\"\n                        app:fieldTextAppearance=\"?android:textAppearanceMedium\"\n                        android:layout_height=\"wrap_content\"></odoo.controls.OField>\n                </odoo.controls.OForm>\n            </LinearLayout>\n        </RelativeLayout>\n    </com.odoo.widgets.parallax.ParallaxScrollView>\n\n    <ScrollView\n        android:id=\"@+id/customerScrollViewEdit\"\n        android:layout_width=\"match_parent\"\n        android:layout_marginTop=\"56dp\"\n        android:paddingTop=\"@dimen/statusBarHeight\"\n        android:clipToPadding=\"false\"\n        android:visibility=\"gone\"\n        android:layout_height=\"wrap_content\">\n\n        <odoo.controls.OForm\n            android:id=\"@+id/customerFormEdit\"\n            app:modelName=\"res.partner\"\n            android:background=\"#ffffff\"\n            android:layout_width=\"match_parent\"\n            android:orientation=\"vertical\"\n            android:layout_height=\"wrap_content\">\n\n            <RelativeLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\">\n\n                <FrameLayout\n                    android:id=\"@+id/parallax_view_edit\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_marginBottom=\"-60dp\"\n                    android:layout_height=\"wrap_content\">\n\n                    <ImageView\n                        android:id=\"@android:id/icon1\"\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"250dp\"\n                        android:scaleType=\"centerInside\"\n                        android:src=\"@drawable/user_xlarge\" />\n\n                </FrameLayout>\n\n                <View\n                    android:layout_marginTop=\"60dp\"\n                    style=\"@style/ViewSeparator\"\n                    android:background=\"#f3f3f3\"\n                    android:layout_below=\"@+id/parallax_view_edit\" />\n\n                <ImageView\n                    android:id=\"@+id/captureImage\"\n                    android:layout_width=\"56dp\"\n                    android:elevation=\"4dp\"\n                    android:layout_below=\"@+id/parallax_view_edit\"\n                    android:tint=\"#ffffff\"\n                    android:padding=\"@dimen/default_8dp\"\n                    android:layout_alignParentRight=\"true\"\n                    android:layout_marginRight=\"@dimen/default_16dp\"\n                    android:src=\"@drawable/ic_action_camera\"\n                    android:layout_marginTop=\"28dp\"\n                    android:background=\"@drawable/circle_mask_primary\"\n                    android:layout_height=\"56dp\" />\n\n                <LinearLayout\n                    android:layout_marginTop=\"72dp\"\n                    android:layout_width=\"match_parent\"\n                    android:orientation=\"vertical\"\n                    android:layout_below=\"@+id/parallax_view_edit\"\n                    android:layout_height=\"wrap_content\">\n\n                    <odoo.controls.OField\n                        android:id=\"@android:id/title\"\n                        app:showIcon=\"false\"\n                        app:fieldName=\"name\"\n                        android:paddingLeft=\"@dimen/default_8dp\"\n                        app:showLabel=\"false\"\n                        app:fieldTextAppearance=\"?android:textAppearanceLarge\"\n                        android:layout_height=\"wrap_content\"\n                        android:layout_width=\"match_parent\"></odoo.controls.OField>\n\n                    <View style=\"@style/ViewSeparator\" />\n\n                    <odoo.controls.OField\n                        android:id=\"@+id/is_company_edit\"\n                        android:layout_width=\"match_parent\"\n                        app:fieldName=\"is_company\"\n                        app:fieldTextAppearance=\"?android:textAppearanceMedium\"\n                        app:showLabel=\"false\"\n                        android:layout_height=\"wrap_content\"></odoo.controls.OField>\n\n                    <odoo.controls.OField\n                        android:id=\"@+id/parent_id\"\n                        android:layout_width=\"match_parent\"\n                        app:fieldName=\"parent_id\"\n                        app:fieldTextAppearance=\"?android:textAppearanceMedium\"\n                        app:widgetType=\"SearchableLive\"\n                        app:showLabel=\"false\"\n                        android:layout_height=\"wrap_content\"></odoo.controls.OField>\n\n                    <View\n                        style=\"@style/ViewSeparator\"\n                        android:layout_marginLeft=\"72dp\" />\n\n                    <odoo.controls.OField\n                        android:layout_width=\"match_parent\"\n                        app:iconResource=\"@drawable/ic_action_location\"\n                        app:fieldName=\"street\"\n                        app:fieldTextAppearance=\"?android:textAppearanceMedium\"\n                        android:layout_height=\"wrap_content\"></odoo.controls.OField>\n\n                    <odoo.controls.OField\n                        android:layout_width=\"match_parent\"\n                        app:fieldName=\"street2\"\n                        app:fieldTextAppearance=\"?android:textAppearanceMedium\"\n                        android:layout_height=\"wrap_content\"></odoo.controls.OField>\n\n                    <odoo.controls.OField\n                        android:layout_width=\"match_parent\"\n                        app:fieldName=\"city\"\n                        app:fieldTextAppearance=\"?android:textAppearanceMedium\"\n                        android:layout_height=\"wrap_content\"></odoo.controls.OField>\n\n                    <odoo.controls.OField\n                        android:layout_width=\"match_parent\"\n                        app:fieldName=\"zip\"\n                        app:fieldTextAppearance=\"?android:textAppearanceMedium\"\n                        android:layout_height=\"wrap_content\"></odoo.controls.OField>\n\n                    <odoo.controls.OField\n                        android:layout_width=\"match_parent\"\n                        app:fieldName=\"country_id\"\n                        app:fieldTextAppearance=\"?android:textAppearanceMedium\"\n                        app:widgetType=\"SearchableLive\"\n                        android:layout_height=\"wrap_content\"></odoo.controls.OField>\n\n                    <View\n                        style=\"@style/ViewSeparator\"\n                        android:layout_marginLeft=\"72dp\" />\n\n                    <odoo.controls.OField\n                        android:layout_width=\"match_parent\"\n                        app:iconResource=\"@drawable/ic_action_message\"\n                        app:fieldName=\"email\"\n                        app:fieldTextAppearance=\"?android:textAppearanceMedium\"\n                        android:layout_height=\"wrap_content\"></odoo.controls.OField>\n\n                    <odoo.controls.OField\n                        android:layout_width=\"match_parent\"\n                        app:fieldName=\"website\"\n                        app:fieldTextAppearance=\"?android:textAppearanceMedium\"\n                        app:iconResource=\"@drawable/ic_action_universe\"\n                        android:layout_height=\"wrap_content\"></odoo.controls.OField>\n\n                    <View\n                        style=\"@style/ViewSeparator\"\n                        android:layout_marginLeft=\"72dp\" />\n\n\n                    <odoo.controls.OField\n                        android:layout_width=\"match_parent\"\n                        app:iconResource=\"@drawable/ic_action_phone\"\n                        app:fieldName=\"phone\"\n                        app:fieldTextAppearance=\"?android:textAppearanceMedium\"\n                        android:layout_height=\"wrap_content\"></odoo.controls.OField>\n\n                    <odoo.controls.OField\n                        android:layout_width=\"match_parent\"\n                        app:fieldName=\"mobile\"\n                        app:fieldTextAppearance=\"?android:textAppearanceMedium\"\n                        app:iconResource=\"@drawable/ic_action_mobile\"\n                        android:layout_height=\"wrap_content\"></odoo.controls.OField>\n\n                    <View\n                        style=\"@style/ViewSeparator\"\n                        android:layout_marginLeft=\"72dp\" />\n\n                    <odoo.controls.OField\n                        android:layout_width=\"match_parent\"\n                        app:iconResource=\"@drawable/ic_action_notes_content\"\n                        app:fieldName=\"comment\"\n                        app:fieldTextAppearance=\"?android:textAppearanceMedium\"\n                        android:layout_height=\"wrap_content\"></odoo.controls.OField>\n                </LinearLayout>\n            </RelativeLayout>\n        </odoo.controls.OForm>\n\n    </ScrollView>\n\n    <android.support.v7.widget.Toolbar\n        android:id=\"@+id/toolbar\"\n        android:paddingTop=\"@dimen/statusBarHeight\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:background=\"@color/android_orange\"\n        android:minHeight=\"?attr/actionBarSize\"\n        android:paddingRight=\"@dimen/default_8dp\"\n        app:popupTheme=\"@style/ThemeOverlay.AppCompat.Dark\"\n        app:theme=\"@style/ToolBarTheme\" />\n\n</RelativeLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/customer_filter_container.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:orientation=\"vertical\"\n    android:layout_gravity=\"top\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\">\n\n    <LinearLayout\n        android:orientation=\"vertical\"\n        android:id=\"@+id/customer_filterContainer\"\n        android:background=\"@android:color/white\"\n        android:layout_width=\"match_parent\"\n        android:visibility=\"gone\"\n        android:layout_height=\"wrap_content\">\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:orientation=\"horizontal\"\n            android:paddingLeft=\"@dimen/default_8dp\"\n            android:paddingRight=\"@dimen/default_8dp\"\n            android:gravity=\"center_vertical\"\n            android:layout_height=\"match_parent\">\n\n            <ImageView\n                android:src=\"@drawable/ic_action_filter\"\n                android:layout_width=\"wrap_content\"\n                android:padding=\"@dimen/default_8dp\"\n                android:adjustViewBounds=\"true\"\n                android:tint=\"@color/android_blue_dark\"\n                android:layout_height=\"wrap_content\" />\n\n            <TextView\n                android:id=\"@+id/customer_name\"\n                android:layout_gravity=\"center_vertical\"\n                android:gravity=\"center_vertical\"\n                android:paddingLeft=\"@dimen/default_16dp\"\n                android:layout_width=\"0dp\"\n                android:layout_weight=\"1\"\n                android:fontFamily=\"@string/font_normal\"\n                android:textStyle=\"bold\"\n                android:textAppearance=\"?android:textAppearanceMedium\"\n                android:layout_height=\"match_parent\" />\n\n            <ImageView\n                android:id=\"@+id/cancel_filter\"\n                android:background=\"?android:attr/selectableItemBackground\"\n                android:src=\"@drawable/ic_action_navigation_close\"\n                android:layout_width=\"wrap_content\"\n                android:padding=\"@dimen/default_8dp\"\n                android:tint=\"@color/android_blue_dark\"\n                android:layout_height=\"wrap_content\" />\n        </LinearLayout>\n\n        <View style=\"@style/ViewSeparator\" />\n    </LinearLayout>\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/customer_row_item.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:layout_width=\"match_parent\"\n    android:orientation=\"horizontal\"\n    android:layout_height=\"match_parent\">\n\n    <LinearLayout\n        android:id=\"@+id/customerView\"\n        android:layout_width=\"match_parent\"\n        android:orientation=\"horizontal\"\n        android:paddingLeft=\"@dimen/default_8dp\"\n        android:paddingTop=\"@dimen/default_8dp\"\n        android:paddingBottom=\"@dimen/default_8dp\"\n        android:paddingRight=\"@dimen/default_16dp\"\n        android:layout_height=\"match_parent\">\n\n        <odoo.controls.BezelImageView\n            android:id=\"@+id/image_small\"\n            android:layout_width=\"40dp\"\n            android:layout_margin=\"@dimen/default_8dp\"\n            app:maskDrawable=\"@drawable/circle_mask\"\n            android:layout_height=\"40dp\" />\n\n        <LinearLayout\n            android:layout_width=\"0dp\"\n            android:layout_weight=\"1\"\n            android:orientation=\"vertical\"\n            android:layout_marginLeft=\"@dimen/default_8dp\"\n            android:layout_height=\"wrap_content\">\n\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:orientation=\"horizontal\"\n                android:layout_height=\"wrap_content\">\n\n                <TextView\n                    android:id=\"@+id/name\"\n                    android:textAppearance=\"?android:textAppearanceMedium\"\n                    android:textColor=\"@color/body_text_1\"\n                    android:fontFamily=\"@string/font_normal\"\n                    android:layout_gravity=\"center_vertical\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"></TextView>\n\n                <TextView\n                    android:fontFamily=\"@string/font_normal\"\n                    android:id=\"@+id/company_name\"\n                    android:layout_marginLeft=\"5dp\"\n                    android:textAppearance=\"?android:textAppearanceSmall\"\n                    android:layout_gravity=\"center_vertical\"\n                    android:textColor=\"@color/body_text_2\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"></TextView>\n            </LinearLayout>\n\n            <TextView\n                android:id=\"@+id/email\"\n                android:textAppearance=\"?android:textAppearanceSmall\"\n                android:layout_gravity=\"center_vertical\"\n                android:fontFamily=\"@string/font_normal\"\n                android:textColor=\"@color/body_text_3\"\n                android:layout_width=\"match_parent\"\n                android:singleLine=\"true\"\n                android:layout_height=\"wrap_content\"></TextView>\n\n        </LinearLayout>\n    </LinearLayout>\n</LinearLayout>\n\n"
  },
  {
    "path": "app/src/main/res/layout/event_color_chooser_item.xml",
    "content": "<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"48dp\"\n    android:orientation=\"horizontal\"\n    android:padding=\"5dp\">\n\n    <ImageView\n        android:id=\"@+id/color_view\"\n        android:layout_width=\"40dp\"\n        android:layout_height=\"40dp\"\n        android:layout_gravity=\"center_vertical\"\n        android:padding=\"8dp\"\n        android:src=\"@drawable/ic_action_default_color\"\n        android:tint=\"@color/theme_primary\" />\n\n    <TextView\n        android:id=\"@+id/color_label\"\n        android:layout_width=\"0dp\"\n        android:layout_height=\"match_parent\"\n        android:layout_weight=\"1\"\n        android:fontFamily=\"@string/font_normal\"\n        android:gravity=\"center_vertical\"\n        android:text=\"Default Color\"\n        android:textSize=\"16dp\" />\n\n    <ImageView\n        android:id=\"@+id/color_view_selected\"\n        android:layout_width=\"40dp\"\n        android:layout_height=\"40dp\"\n        android:layout_gravity=\"center_vertical\"\n        android:padding=\"8dp\"\n        android:src=\"@drawable/ic_action_done\"\n        android:tint=\"@color/theme_secondary_dark\" />\n\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/event_color_grid.xml",
    "content": "<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:gravity=\"center\"\n    android:orientation=\"vertical\"\n    android:padding=\"15dp\">\n\n    <GridView\n        android:id=\"@+id/event_grid\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"match_parent\"\n        android:numColumns=\"1\"></GridView>\n\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/listview_data_loading_progress.xml",
    "content": "<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:id=\"@+id/messageHeaderView\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:gravity=\"center\"\n    android:orientation=\"vertical\" >\n\n    <ProgressBar\n        android:id=\"@+id/progressBar1\"\n        style=\"?android:attr/progressBarStyle\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"center\" />\n\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/news_detail.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<ScrollView\n    android:layout_height=\"match_parent\"\n    android:layout_width=\"match_parent\"\n    xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <LinearLayout\n        android:orientation=\"vertical\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\">\n\n\n        <TextView\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:textAppearance=\"?android:attr/textAppearanceLarge\"\n            android:textColor=\"@color/body_text_1\"\n            android:fontFamily=\"@string/font_normal\"\n            android:padding=\"@dimen/default_16dp\"\n            android:id=\"@+id/detailSubject\" />\n\n        <WebView\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:textAppearance=\"?android:attr/textAppearanceSmall\"\n            android:textColor=\"@color/body_text_2\"\n            android:fontFamily=\"@string/font_light\"\n            android:layout_margin=\"@dimen/default_8dp\"\n            android:id=\"@+id/detailMessage\" />\n    </LinearLayout>\n</ScrollView>"
  },
  {
    "path": "app/src/main/res/layout/news_list.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:orientation=\"vertical\" android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n<ListView\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:id=\"@+id/newsList\"></ListView>\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/odoo_activity.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<android.support.v4.widget.DrawerLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:id=\"@+id/drawer_layout\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:background=\"@color/theme_primary_dark\"\n    android:fitsSystemWindows=\"@bool/fitToScreenWindow\">\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:orientation=\"vertical\"\n        android:layout_height=\"match_parent\">\n\n        <!-- Base Toolbar -->\n        <include layout=\"@layout/base_toolbar\" />\n\n        <FrameLayout\n            android:id=\"@+id/fragment_container\"\n            android:layout_width=\"match_parent\"\n            android:layout_weight=\"1\"\n            android:background=\"@android:color/white\"\n            android:layout_height=\"0dp\">\n\n        </FrameLayout>\n    </LinearLayout>\n\n    <include layout=\"@layout/base_drawer\" />\n</android.support.v4.widget.DrawerLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/odoo_news.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:orientation=\"vertical\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:padding=\"@dimen/default_16dp\">\n\n\n    <TextView\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:id=\"@+id/subject\"\n        android:textAppearance=\"?android:attr/textAppearanceMedium\"\n        android:textColor=\"@color/body_text_1\"\n        android:fontFamily=\"@string/font_normal\" />\n\n    <TextView\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:id=\"@+id/message\"\n        android:textAppearance=\"?android:attr/textAppearanceSmall\"\n        android:maxLines=\"3\"\n        android:textColor=\"@color/body_text_2\"\n        android:fontFamily=\"@string/font_light\" />\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/phonecall_item.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:orientation=\"vertical\"\n    android:layout_width=\"match_parent\"\n    android:padding=\"@dimen/default_16dp\"\n    android:layout_height=\"match_parent\">\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:orientation=\"horizontal\"\n        android:gravity=\"center_vertical\"\n        android:layout_height=\"wrap_content\">\n\n\n        <TextView\n            android:id=\"@+id/name\"\n            android:textAppearance=\"?android:textAppearanceMedium\"\n            android:textColor=\"@color/body_text_1\"\n            android:fontFamily=\"@string/font_normal\"\n            android:singleLine=\"true\"\n            android:ellipsize=\"end\"\n            android:layout_marginRight=\"5dp\"\n            android:layout_width=\"0dp\"\n            android:layout_weight=\"1\"\n            android:layout_height=\"wrap_content\" />\n\n        <TextView\n            android:id=\"@+id/state\"\n            android:textAppearance=\"?android:textAppearanceSmall\"\n            android:textColor=\"@color/android_violet_dark\"\n            android:textStyle=\"bold\"\n            android:fontFamily=\"@string/font_condensed\"\n            android:textAllCaps=\"true\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\" />\n\n    </LinearLayout>\n\n    <TextView\n        android:id=\"@+id/lead_name\"\n        android:textAppearance=\"?android:textAppearanceMedium\"\n        android:textColor=\"@color/body_text_2\"\n        android:fontFamily=\"@string/font_normal\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\" />\n\n    <TextView\n        android:id=\"@+id/description\"\n        android:textAppearance=\"?android:textAppearanceSmall\"\n        android:textColor=\"@color/body_text_3\"\n        android:fontFamily=\"@string/font_normal\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\" />\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:orientation=\"horizontal\"\n        android:gravity=\"center_vertical\"\n        android:layout_height=\"wrap_content\">\n\n        <ImageView\n            android:id=\"@+id/call_type_icon\"\n            android:tint=\"@color/android_blue_dark\"\n            android:layout_width=\"32dp\"\n            android:layout_marginRight=\"5dp\"\n            android:layout_height=\"32dp\" />\n\n        <TextView\n            android:id=\"@+id/customer_name\"\n            android:textAppearance=\"?android:textAppearanceMedium\"\n            android:textColor=\"@color/body_text_2\"\n            android:fontFamily=\"@string/font_light\"\n            android:singleLine=\"true\"\n            android:ellipsize=\"end\"\n            android:layout_marginRight=\"5dp\"\n            android:layout_width=\"0dp\"\n            android:layout_weight=\"1\"\n            android:layout_height=\"wrap_content\" />\n\n        <TextView\n            android:id=\"@+id/date\"\n            android:textAppearance=\"?android:textAppearanceSmall\"\n            android:textColor=\"@color/body_text_2\"\n            android:textStyle=\"bold\"\n            android:fontFamily=\"@string/font_normal\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\" />\n    </LinearLayout>\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/reminder_custom_dialog_view.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:orientation=\"vertical\" android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/reminder_item_view.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:orientation=\"horizontal\"\n    android:layout_width=\"match_parent\"\n    android:padding=\"@dimen/default_16dp\"\n    android:layout_height=\"match_parent\">\n\n    <TextView\n        android:id=\"@+id/reminderTitle\"\n        android:textAppearance=\"?android:textAppearanceMedium\"\n        android:textColor=\"@color/body_text_2\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\" />\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/sale_add_item.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:layout_marginTop=\"@dimen/statusBarHeight\"\n    android:background=\"#ebebeb\"\n    android:orientation=\"vertical\">\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"56dp\"\n        android:background=\"#ffffff\"\n        android:orientation=\"horizontal\"\n        android:paddingLeft=\"0dp\"\n        android:paddingRight=\"0dp\">\n\n        <ImageView\n            android:id=\"@+id/search_icon\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"match_parent\"\n            android:layout_gravity=\"center\"\n            android:background=\"?android:attr/selectableItemBackground\"\n            android:paddingLeft=\"16dp\"\n            android:paddingRight=\"16dp\"\n            android:src=\"@drawable/ic_action_search\"\n            android:tint=\"#414141\" />\n\n        <EditText\n            android:id=\"@+id/edt_searchable_input\"\n            android:layout_width=\"0dp\"\n            android:layout_height=\"match_parent\"\n            android:layout_weight=\"1\"\n            android:background=\"@android:color/transparent\"\n            android:ellipsize=\"end\"\n            android:fontFamily=\"@string/font_normal\"\n            android:gravity=\"center_vertical\"\n            android:hint=\"@string/label_search\"\n            android:singleLine=\"true\"\n            android:textAppearance=\"?android:attr/textAppearanceMedium\">\n\n            <requestFocus />\n        </EditText>\n\n        <ImageView\n            android:id=\"@+id/done\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"match_parent\"\n            android:layout_gravity=\"center\"\n            android:background=\"?android:attr/selectableItemBackground\"\n            android:paddingLeft=\"16dp\"\n            android:paddingRight=\"16dp\"\n            android:src=\"@drawable/ic_action_action_done_all\"\n            android:tint=\"#414141\" />\n    </LinearLayout>\n\n    <View style=\"@style/ViewSeparator\" />\n\n    <include\n        android:id=\"@+id/loading_progress\"\n        layout=\"@layout/listview_data_loading_progress\"\n        android:visibility=\"gone\" />\n\n    <ListView\n        android:id=\"@+id/searchable_items\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"></ListView>\n\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/sale_detail.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:orientation=\"vertical\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <android.support.v7.widget.Toolbar\n        android:id=\"@+id/toolbar\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:background=\"@color/theme_primary\"\n        android:minHeight=\"?attr/actionBarSize\"\n        app:titleMarginStart=\"@dimen/default_16dp\"\n        android:paddingTop=\"@dimen/statusBarHeight\"\n        android:paddingRight=\"@dimen/default_8dp\"\n        app:popupTheme=\"@style/ThemeOverlay.AppCompat.Dark\"\n        app:theme=\"@style/ToolBarTheme\" />\n\n    <ScrollView\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\">\n\n        <odoo.controls.OForm\n            android:id=\"@+id/saleForm\"\n            android:orientation=\"vertical\"\n            app:controlIconTint=\"@color/body_text_3\"\n            app:modelName=\"sale.order\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\">\n\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:orientation=\"horizontal\"\n                android:layout_height=\"wrap_content\">\n\n                <TextView\n                    android:id=\"@+id/txvType\"\n                    android:layout_width=\"wrap_content\"\n                    android:gravity=\"right\"\n                    android:padding=\"@dimen/default_16dp\"\n                    android:textAppearance=\"?android:textAppearanceLarge\"\n                    android:layout_height=\"match_parent\" />\n\n                <odoo.controls.OField\n                    android:layout_width=\"match_parent\"\n                    android:id=\"@+id/fname\"\n                    app:defaultValue=\"/\"\n                    app:fieldName=\"name\"\n                    app:showLabel=\"false\"\n                    app:showIcon=\"false\"\n                    app:fieldTextAppearance=\"?android:textAppearanceLarge\"\n                    app:fieldTextSize=\"@dimen/text_size_xmedium\"\n                    android:layout_height=\"wrap_content\" />\n            </LinearLayout>\n\n            <View style=\"@style/ViewSeparator\" />\n\n            <odoo.controls.OField\n                android:layout_width=\"match_parent\"\n                app:fieldName=\"partner_id\"\n                app:showLabel=\"true\"\n                app:iconResource=\"@drawable/ic_action_user\"\n                app:widgetType=\"SearchableLive\"\n                app:fieldTextAppearance=\"?android:textAppearanceMedium\"\n                android:layout_height=\"wrap_content\" />\n\n            <View style=\"@style/ViewSeparator\" />\n\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:orientation=\"horizontal\"\n                android:showDividers=\"middle\"\n                android:divider=\"?android:attr/dividerHorizontal\"\n                android:layout_height=\"wrap_content\">\n\n                <odoo.controls.OField\n                    android:layout_width=\"0dp\"\n                    android:layout_weight=\"1\"\n                    app:fieldName=\"date_order\"\n                    app:defaultValue=\"now()\"\n                    app:showLabel=\"true\"\n                    app:iconResource=\"@drawable/ic_action_time_clock\"\n                    app:parsePattern=\"MMM dd yyyy, hh:MM a\"\n                    app:fieldTextSize=\"@dimen/text_size_medium\"\n                    app:fieldTextAppearance=\"?android:textAppearanceSmall\"\n                    android:layout_height=\"wrap_content\" />\n\n            </LinearLayout>\n\n            <View style=\"@style/ViewSeparator\" />\n\n            <odoo.controls.OField\n                android:layout_width=\"match_parent\"\n                app:fieldName=\"payment_term\"\n                app:showLabel=\"true\"\n                app:fieldTextSize=\"@dimen/text_size_xmedium\"\n                app:fieldTextAppearance=\"?android:textAppearanceMedium\"\n                app:showIcon=\"false\"\n                android:layout_height=\"wrap_content\" />\n\n\n            <View style=\"@style/ViewSeparator\" />\n\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:paddingLeft=\"@dimen/default_16dp\"\n                android:paddingRight=\"@dimen/default_16dp\"\n                android:id=\"@+id/layoutAddItem\"\n                android:paddingTop=\"@dimen/default_8dp\"\n                android:paddingBottom=\"@dimen/default_8dp\"\n                android:background=\"?android:attr/selectableItemBackground\"\n                android:layout_height=\"match_parent\">\n\n                <ImageView\n                    android:layout_width=\"wrap_content\"\n                    android:src=\"@drawable/ic_action_edit\"\n                    android:padding=\"2dp\"\n                    android:tint=\"@color/android_orange_dark\"\n                    android:layout_height=\"match_parent\" />\n\n                <TextView\n                    android:layout_width=\"0dp\"\n                    android:layout_weight=\"1\"\n                    android:gravity=\"center_vertical\"\n                    android:text=\"Manage order lines\"\n                    android:textAllCaps=\"true\"\n                    android:textColor=\"@color/android_orange_dark\"\n                    android:textStyle=\"bold\"\n                    android:textAppearance=\"?android:textAppearanceSmall\"\n                    android:layout_height=\"match_parent\" />\n\n            </LinearLayout>\n\n            <odoo.controls.ExpandableListControl\n                android:id=\"@+id/expListOrderLine\"\n                android:layout_width=\"match_parent\"\n                android:orientation=\"vertical\"\n                android:visibility=\"gone\"\n                android:layout_marginTop=\"@dimen/default_8dp\"\n                android:layout_marginBottom=\"@dimen/default_8dp\"\n                android:layout_height=\"wrap_content\">\n\n            </odoo.controls.ExpandableListControl>\n\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:orientation=\"horizontal\"\n                android:gravity=\"center_vertical\"\n                android:layout_height=\"match_parent\">\n\n                <TextView\n                    android:layout_width=\"0dp\"\n                    android:layout_weight=\"1\"\n                    android:padding=\"@dimen/default_8dp\"\n                    android:text=\"Untaxed Amount:\"\n                    android:gravity=\"center_vertical|right\"\n                    android:textAppearance=\"?android:textAppearanceSmall\"\n                    android:layout_height=\"match_parent\" />\n\n                <TextView\n                    android:id=\"@+id/untaxedTotal\"\n                    android:paddingBottom=\"@dimen/default_8dp\"\n                    android:paddingTop=\"@dimen/default_8dp\"\n                    android:layout_width=\"wrap_content\"\n                    android:gravity=\"center_vertical|right\"\n                    android:minWidth=\"80dp\"\n                    android:fontFamily=\"@string/font_normal\"\n                    android:textColor=\"@color/body_text_1\"\n                    android:textAppearance=\"?android:textAppearanceSmall\"\n                    android:layout_height=\"match_parent\" />\n\n                <TextView\n                    android:id=\"@+id/currency1\"\n                    android:paddingBottom=\"@dimen/default_8dp\"\n                    android:paddingTop=\"@dimen/default_8dp\"\n                    android:paddingRight=\"@dimen/default_16dp\"\n                    android:paddingLeft=\"@dimen/default_8dp\"\n                    android:layout_width=\"wrap_content\"\n                    android:gravity=\"center_vertical\"\n                    android:textAppearance=\"?android:textAppearanceSmall\"\n                    android:layout_height=\"match_parent\" />\n\n            </LinearLayout>\n\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:orientation=\"horizontal\"\n                android:gravity=\"center_vertical\"\n                android:layout_height=\"match_parent\">\n\n                <TextView\n                    android:layout_width=\"0dp\"\n                    android:layout_weight=\"1\"\n                    android:padding=\"@dimen/default_8dp\"\n                    android:text=\"Taxes :\"\n                    android:gravity=\"center_vertical|right\"\n                    android:textAppearance=\"?android:textAppearanceSmall\"\n                    android:layout_height=\"match_parent\" />\n\n                <TextView\n                    android:id=\"@+id/taxesTotal\"\n                    android:paddingBottom=\"@dimen/default_8dp\"\n                    android:paddingTop=\"@dimen/default_8dp\"\n                    android:layout_width=\"wrap_content\"\n                    android:gravity=\"center_vertical|right\"\n                    android:fontFamily=\"@string/font_normal\"\n                    android:minWidth=\"80dp\"\n                    android:textColor=\"@color/body_text_1\"\n                    android:textAppearance=\"?android:textAppearanceSmall\"\n                    android:layout_height=\"match_parent\" />\n\n                <TextView\n                    android:id=\"@+id/currency2\"\n                    android:paddingBottom=\"@dimen/default_8dp\"\n                    android:paddingTop=\"@dimen/default_8dp\"\n                    android:paddingRight=\"@dimen/default_16dp\"\n                    android:paddingLeft=\"@dimen/default_8dp\"\n                    android:layout_width=\"wrap_content\"\n                    android:gravity=\"center_vertical\"\n                    android:textAppearance=\"?android:textAppearanceSmall\"\n                    android:layout_height=\"match_parent\" />\n\n            </LinearLayout>\n\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:orientation=\"horizontal\"\n                android:gravity=\"center_vertical\"\n                android:layout_height=\"match_parent\">\n\n                <TextView\n                    android:layout_width=\"0dp\"\n                    android:layout_weight=\"1\"\n                    android:padding=\"@dimen/default_8dp\"\n                    android:textStyle=\"bold\"\n                    android:text=\"Total:\"\n                    android:gravity=\"center_vertical|right\"\n                    android:textAppearance=\"?android:textAppearanceMedium\"\n                    android:layout_height=\"match_parent\" />\n\n                <TextView\n                    android:id=\"@+id/fTotal\"\n                    android:paddingBottom=\"@dimen/default_8dp\"\n                    android:paddingTop=\"@dimen/default_8dp\"\n                    android:layout_width=\"wrap_content\"\n                    android:gravity=\"center_vertical|right\"\n                    android:fontFamily=\"@string/font_normal\"\n                    android:minWidth=\"80dp\"\n                    android:textStyle=\"bold\"\n                    android:textColor=\"@color/body_text_1\"\n                    android:textAppearance=\"?android:textAppearanceMedium\"\n                    android:layout_height=\"match_parent\" />\n\n                <TextView\n                    android:id=\"@+id/currency3\"\n                    android:paddingBottom=\"@dimen/default_8dp\"\n                    android:paddingTop=\"@dimen/default_8dp\"\n                    android:paddingRight=\"@dimen/default_16dp\"\n                    android:paddingLeft=\"@dimen/default_8dp\"\n                    android:layout_width=\"wrap_content\"\n                    android:gravity=\"center_vertical\"\n                    android:textStyle=\"bold\"\n                    android:textAppearance=\"?android:textAppearanceMedium\"\n                    android:layout_height=\"match_parent\" />\n\n            </LinearLayout>\n        </odoo.controls.OForm>\n    </ScrollView>\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/sale_order_item.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:orientation=\"vertical\"\n    android:layout_width=\"match_parent\"\n    android:padding=\"@dimen/default_16dp\"\n    android:layout_height=\"match_parent\">\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:orientation=\"horizontal\"\n        android:gravity=\"center_vertical\"\n        android:layout_height=\"wrap_content\">\n\n\n        <TextView\n            android:id=\"@+id/name\"\n            android:textAppearance=\"?android:textAppearanceMedium\"\n            android:textColor=\"@color/body_text_1\"\n            android:fontFamily=\"@string/font_normal\"\n            android:singleLine=\"true\"\n            android:ellipsize=\"end\"\n            android:layout_marginRight=\"5dp\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\" />\n\n        <TextView\n            android:id=\"@+id/order_lines\"\n            android:textAppearance=\"?android:textAppearanceSmall\"\n            android:textColor=\"@color/body_text_3\"\n            android:fontFamily=\"@string/font_normal\"\n\n            android:layout_width=\"0dp\"\n            android:layout_weight=\"1\"\n            android:layout_height=\"wrap_content\" />\n\n        <TextView\n            android:id=\"@+id/date_order\"\n            android:textAppearance=\"?android:textAppearanceSmall\"\n            android:textColor=\"@color/android_violet_dark\"\n            android:textStyle=\"bold\"\n            android:fontFamily=\"@string/font_condensed\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\" />\n\n    </LinearLayout>\n\n    <TextView\n        android:id=\"@+id/partner_name\"\n        android:textAppearance=\"?android:textAppearanceMedium\"\n        android:textColor=\"@color/body_text_2\"\n        android:fontFamily=\"@string/font_normal\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\" />\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:divider=\"#aaa\"\n        android:dividerPadding=\"8dp\"\n        android:gravity=\"right\"\n        android:orientation=\"horizontal\">\n\n        <TextView\n            android:id=\"@+id/state\"\n            android:textAppearance=\"?android:textAppearanceSmall\"\n            android:textColor=\"@color/theme_primary\"\n            android:fontFamily=\"@string/font_normal\"\n            android:layout_width=\"0dp\"\n            android:layout_weight=\"1\"\n            android:layout_height=\"wrap_content\" />\n\n        <TextView\n            android:id=\"@+id/amount_total\"\n            android:textAppearance=\"?android:textAppearanceSmall\"\n            android:textColor=\"@color/body_text_2\"\n            android:fontFamily=\"@string/font_normal\"\n            android:layout_width=\"wrap_content\"\n            android:layout_marginRight=\"5dp\"\n            android:layout_height=\"wrap_content\" />\n\n        <TextView\n            android:id=\"@+id/currency_symbol\"\n            android:textAppearance=\"?android:textAppearanceSmall\"\n            android:textColor=\"@color/body_text_2\"\n            android:fontFamily=\"@string/font_normal\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\" />\n    </LinearLayout>\n\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/sale_order_line_item.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:card_view=\"http://schemas.android.com/apk/res-auto\"\n    android:orientation=\"vertical\"\n    android:layout_width=\"match_parent\"\n    android:paddingLeft=\"@dimen/default_16dp\"\n    android:clickable=\"false\"\n    android:paddingRight=\"@dimen/default_16dp\"\n    android:layout_height=\"match_parent\">\n\n    <android.support.v7.widget.CardView\n        android:layout_width=\"match_parent\"\n        card_view:cardCornerRadius=\"4dp\"\n        android:layout_marginBottom=\"5dp\"\n        android:layout_height=\"wrap_content\">\n\n        <LinearLayout\n            android:padding=\"@dimen/default_8dp\"\n            android:layout_width=\"match_parent\"\n            android:orientation=\"vertical\"\n            android:gravity=\"center_vertical\"\n            android:layout_height=\"wrap_content\">\n\n\n            <TextView\n                android:id=\"@+id/edtName\"\n                android:textSize=\"@dimen/text_size_large\"\n                android:textColor=\"@color/body_text_1\"\n                android:layout_width=\"wrap_content\"\n                android:fontFamily=\"@string/font_normal\"\n                android:layout_height=\"wrap_content\" />\n\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:orientation=\"horizontal\"\n                android:gravity=\"center_vertical\"\n                android:showDividers=\"middle\"\n                android:divider=\"?android:attr/dividerHorizontal\"\n                android:layout_height=\"wrap_content\">\n\n\n                <LinearLayout\n                    android:layout_width=\"wrap_content\"\n                    android:orientation=\"vertical\"\n                    android:layout_marginRight=\"@dimen/default_16dp\"\n                    android:layout_height=\"wrap_content\">\n\n                    <TextView\n                        android:layout_width=\"match_parent\"\n                        android:textAllCaps=\"true\"\n                        android:textSize=\"@dimen/text_size_small\"\n                        android:fontFamily=\"@string/font_condensed\"\n                        android:textColor=\"@color/body_text_3\"\n                        android:layout_height=\"wrap_content\"\n                        android:text=\"Quantity\" />\n\n                    <TextView\n                        android:id=\"@+id/edtProductQty\"\n                        android:layout_width=\"match_parent\"\n                        android:textSize=\"@dimen/text_size_medium\"\n                        android:textColor=\"@color/body_text_2\"\n                        android:layout_height=\"wrap_content\" />\n                </LinearLayout>\n\n                <LinearLayout\n                    android:layout_width=\"0dp\"\n                    android:layout_weight=\"1\"\n                    android:layout_marginLeft=\"@dimen/default_16dp\"\n                    android:orientation=\"vertical\"\n                    android:layout_height=\"wrap_content\">\n\n                    <TextView\n                        android:layout_width=\"match_parent\"\n                        android:textAllCaps=\"true\"\n                        android:textSize=\"@dimen/text_size_small\"\n                        android:fontFamily=\"@string/font_condensed\"\n                        android:textColor=\"@color/body_text_3\"\n                        android:layout_height=\"wrap_content\"\n                        android:text=\"Unit Price\" />\n\n                    <TextView\n                        android:id=\"@+id/edtProductPrice\"\n                        android:layout_width=\"match_parent\"\n                        android:textSize=\"@dimen/text_size_medium\"\n                        android:textColor=\"@color/body_text_2\"\n                        android:layout_height=\"wrap_content\" />\n                </LinearLayout>\n\n                <LinearLayout\n                    android:layout_width=\"0dp\"\n                    android:layout_weight=\"1\"\n                    android:orientation=\"vertical\"\n                    android:layout_height=\"wrap_content\">\n\n                    <TextView\n                        android:layout_width=\"match_parent\"\n                        android:gravity=\"right\"\n                        android:textAllCaps=\"true\"\n                        android:textSize=\"@dimen/text_size_small\"\n                        android:fontFamily=\"@string/font_condensed\"\n                        android:textColor=\"@color/body_text_3\"\n                        android:layout_height=\"wrap_content\"\n                        android:text=\"Sub Total\" />\n\n\n                    <TextView\n                        android:id=\"@+id/edtSubTotal\"\n                        android:layout_width=\"match_parent\"\n                        android:gravity=\"right\"\n                        android:textSize=\"@dimen/text_size_medium\"\n                        android:textColor=\"@color/body_text_2\"\n                        android:layout_height=\"wrap_content\" />\n                </LinearLayout>\n\n            </LinearLayout>\n        </LinearLayout>\n    </android.support.v7.widget.CardView>\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/sale_product_line_item.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:orientation=\"horizontal\"\n    android:layout_width=\"match_parent\"\n    android:gravity=\"center_vertical\"\n    android:paddingLeft=\"@dimen/default_16dp\"\n    android:paddingTop=\"@dimen/default_16dp\"\n    android:paddingBottom=\"@dimen/default_16dp\"\n    android:layout_height=\"match_parent\">\n\n    <TextView\n        android:id=\"@+id/productQty\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"32dp\"\n        android:background=\"@drawable/circle_mask_secondary\"\n        android:fontFamily=\"@string/font_condensed\"\n        android:gravity=\"center\"\n        android:text=\"52\"\n        android:padding=\"5dp\"\n        android:layout_marginRight=\"@dimen/default_16dp\"\n        android:textColor=\"@android:color/white\"\n        android:textAppearance=\"?android:attr/textAppearanceSmall\" />\n\n    <TextView\n        android:id=\"@+id/productName\"\n        android:layout_width=\"0dp\"\n        android:layout_height=\"wrap_content\"\n        android:layout_weight=\"1\"\n        android:background=\"@android:color/transparent\"\n        android:ellipsize=\"end\"\n        android:fontFamily=\"@string/font_normal\"\n        android:textColor=\"@color/body_text_2\"\n        android:gravity=\"center_vertical\"\n        android:hint=\"@string/label_search\"\n        android:singleLine=\"true\"\n        android:textAppearance=\"?android:attr/textAppearanceMedium\" />\n\n    <ImageView\n        android:id=\"@+id/remove_qty\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"center_vertical\"\n        android:background=\"?android:attr/selectableItemBackground\"\n        android:paddingLeft=\"16dp\"\n        android:paddingRight=\"16dp\"\n        android:visibility=\"gone\"\n        android:paddingTop=\"@dimen/default_8dp\"\n        android:paddingBottom=\"@dimen/default_8dp\"\n        android:src=\"@drawable/ic_action_content_remove_circle\"\n        android:tint=\"@color/android_red_dark\" />\n\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/menu/menu_about.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/menu_about_our_apps\"\n        android:icon=\"@drawable/ic_action_play_store\"\n        android:title=\"@string/label_our_apps\"\n        app:showAsAction=\"always\"></item>\n    <item\n        android:id=\"@+id/menu_about_github\"\n        android:icon=\"@drawable/ic_action_github\"\n        android:title=\"@string/label_odoo_mobile_on_github\"\n        app:showAsAction=\"always\"></item>\n\n    <item\n        android:id=\"@+id/menu_developer_mode\"\n        android:icon=\"@drawable/ic_action_more\"\n        android:title=\"@string/label_odoo_developer_mode\"\n        app:showAsAction=\"always\"\n        android:visible=\"false\">\n        <menu>\n            <item\n                android:id=\"@+id/menu_export_db\"\n                android:icon=\"@drawable/ic_action_content_export\"\n                android:title=\"@string/label_export_db\"\n                app:showAsAction=\"always\">\n\n            </item>\n        </menu>\n    </item>\n</menu>"
  },
  {
    "path": "app/src/main/res/menu/menu_base_login.xml",
    "content": "<menu xmlns:tools=\"http://schemas.android.com/tools\"\n    tools:context=\"com.odoo.core.account.OdooLogin\"></menu>\n"
  },
  {
    "path": "app/src/main/res/menu/menu_calendar_dashboard.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\n    <item\n        android:id=\"@+id/menu_search\"\n        android:icon=\"@drawable/ic_action_search\"\n        android:title=\"@string/label_search\"\n        app:actionViewClass=\"android.support.v7.widget.SearchView\"\n        app:showAsAction=\"always|collapseActionView\">\n    </item>\n    <item\n        android:id=\"@+id/menu_dashboard_goto_today\"\n        android:icon=\"@drawable/ic_action_goto_today\"\n        android:title=\"@string/label_today\"\n        app:showAsAction=\"ifRoom|withText\">\n    </item>\n\n</menu>"
  },
  {
    "path": "app/src/main/res/menu/menu_calendar_detail.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/menu_calendar_detail_save\"\n        android:title=\"@string/label_save\"\n        app:showAsAction=\"always\" />\n</menu>"
  },
  {
    "path": "app/src/main/res/menu/menu_customer_detail.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/menu_customer_edit\"\n        android:icon=\"@drawable/ic_action_edit\"\n        android:title=\"@string/label_edit\"\n        app:showAsAction=\"always\" />\n    <item\n        android:id=\"@+id/menu_customer_save\"\n        android:title=\"@string/label_save\"\n        app:showAsAction=\"always\" />\n    <item\n        android:id=\"@+id/menu_customer_cancel\"\n        android:title=\"@string/label_cancel\"\n        app:showAsAction=\"always\" />\n    <item\n        android:id=\"@+id/menu_customer_detail_more\"\n        android:icon=\"@drawable/ic_action_more\"\n        app:showAsAction=\"always\"\n        android:title=\"@string/label_more\">\n        <menu>\n            <item\n                android:id=\"@+id/menu_customer_share\"\n                android:title=\"@string/label_share\" />\n            <item\n                android:id=\"@+id/menu_customer_import\"\n                android:title=\"@string/label_import_contact\" />\n        </menu>\n    </item>\n</menu>"
  },
  {
    "path": "app/src/main/res/menu/menu_dashboard_events.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item\n        android:id=\"@+id/menu_events_location\"\n        android:icon=\"@drawable/ic_action_location\"\n        android:title=\"@string/label_location\"></item>\n    <item\n        android:id=\"@+id/menu_events_reschedule\"\n        android:icon=\"@drawable/ic_action_reschedule\"\n        android:title=\"@string/label_re_schedule\"></item>\n    <item\n        android:id=\"@+id/menu_events_all_done\"\n        android:icon=\"@drawable/ic_action_done_all\"\n        android:title=\"@string/label_mark_done\"></item>\n\n</menu>"
  },
  {
    "path": "app/src/main/res/menu/menu_dashboard_opportunity.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item\n        android:id=\"@+id/menu_opp_call_customer\"\n        android:icon=\"@drawable/ic_action_phone\"\n        android:title=\"@string/label_call\"></item>\n    <item\n        android:id=\"@+id/menu_opp_customer_location\"\n        android:icon=\"@drawable/ic_action_location\"\n        android:title=\"@string/label_location\"></item>\n    <item\n        android:id=\"@+id/menu_opp_reschedule\"\n        android:icon=\"@drawable/ic_action_reschedule\"\n        android:title=\"@string/label_schedule_call\"></item>\n    <item\n        android:id=\"@+id/menu_opp_won\"\n        android:icon=\"@drawable/ic_action_mark_won\"\n        android:title=\"@string/label_mark_as_won\"></item>\n    <item\n        android:id=\"@+id/menu_opp_lost\"\n        android:icon=\"@drawable/ic_action_mark_lost\"\n        android:title=\"@string/label_mark_as_lost\"></item>\n    <item\n        android:id=\"@+id/menu_lead_convert_to_quotation\"\n        android:icon=\"@drawable/ic_action_quotation\"\n        android:title=\"@string/label_convert_to_quotation\"></item>\n\n</menu>"
  },
  {
    "path": "app/src/main/res/menu/menu_dashboard_phonecalls.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item\n        android:id=\"@+id/menu_phonecall_call\"\n        android:icon=\"@drawable/ic_action_phone\"\n        android:title=\"@string/label_call\"></item>\n    <item\n        android:id=\"@+id/menu_phonecall_reschedule\"\n        android:icon=\"@drawable/ic_action_reschedule\"\n        android:title=\"@string/label_schedule_call\"></item>\n    <item\n        android:id=\"@+id/menu_phonecall_all_done\"\n        android:icon=\"@drawable/ic_action_done_all\"\n        android:title=\"@string/label_call_held\"></item>\n\n</menu>"
  },
  {
    "path": "app/src/main/res/menu/menu_lead_detail.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\n    <item\n        android:id=\"@+id/menu_lead_save\"\n        android:title=\"@string/label_save\"\n        app:showAsAction=\"always\" />\n    <item\n        android:id=\"@+id/menu_lead_detail_more\"\n        android:icon=\"@drawable/ic_action_more\"\n        app:showAsAction=\"always\"\n        android:title=\"@string/label_more\">\n        <menu>\n            <item\n                android:id=\"@+id/menu_lead_convert_to_opportunity\"\n                android:title=\"@string/label_convert_to_opportunity\" />\n            <item\n                android:id=\"@+id/menu_mark_lost\"\n                android:title=\"@string/label_mark_as_lost\" />\n            <item\n                android:id=\"@+id/menu_mark_won\"\n                android:title=\"@string/label_mark_as_won\" />\n            <item\n                android:id=\"@+id/menu_lead_convert_to_quotation\"\n                android:title=\"@string/label_convert_to_quotation\" />\n        </menu>\n    </item>\n</menu>"
  },
  {
    "path": "app/src/main/res/menu/menu_lead_list_sheet.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item\n        android:id=\"@+id/menu_lead_convert_to_opportunity\"\n        android:icon=\"@drawable/ic_action_opportunities\"\n        android:title=\"@string/label_convert_to_opportunity\"></item>\n    <item\n        android:id=\"@+id/menu_lead_call_customer\"\n        android:icon=\"@drawable/ic_action_phone\"\n        android:title=\"@string/label_call\"></item>\n    <item\n        android:id=\"@+id/menu_lead_customer_location\"\n        android:icon=\"@drawable/ic_action_location\"\n        android:title=\"@string/label_location\"></item>\n\n    <item\n        android:id=\"@+id/menu_lead_lost\"\n        android:icon=\"@drawable/ic_action_mark_lost\"\n        android:title=\"@string/label_mark_as_lost\"></item>\n</menu>"
  },
  {
    "path": "app/src/main/res/menu/menu_leads.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/menu_lead_search\"\n        android:icon=\"@drawable/ic_action_search\"\n        android:title=\"@string/label_search\"\n        app:actionViewClass=\"android.support.v7.widget.SearchView\"\n        app:showAsAction=\"always|collapseActionView\"></item>\n</menu>"
  },
  {
    "path": "app/src/main/res/menu/menu_opp_list_sheet.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item\n        android:id=\"@+id/menu_lead_convert_to_quotation\"\n        android:icon=\"@drawable/ic_action_quotation\"\n        android:title=\"@string/label_convert_to_quotation\"></item>\n    <item\n        android:id=\"@+id/menu_lead_call_customer\"\n        android:icon=\"@drawable/ic_action_phone\"\n        android:title=\"@string/label_call\"></item>\n    <item\n        android:id=\"@+id/menu_lead_customer_location\"\n        android:icon=\"@drawable/ic_action_location\"\n        android:title=\"@string/label_location\"></item>\n    <item\n        android:id=\"@+id/menu_lead_reschedule\"\n        android:icon=\"@drawable/ic_action_reschedule\"\n        android:title=\"@string/label_schedule_call\"></item>\n    <item\n        android:id=\"@+id/menu_lead_won\"\n        android:icon=\"@drawable/ic_action_mark_won\"\n        android:title=\"@string/label_mark_as_won\"></item>\n    <item\n        android:id=\"@+id/menu_lead_lost\"\n        android:icon=\"@drawable/ic_action_mark_lost\"\n        android:title=\"@string/label_mark_as_lost\"></item>\n</menu>"
  },
  {
    "path": "app/src/main/res/menu/menu_partners.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/menu_partner_search\"\n        android:icon=\"@drawable/ic_action_search\"\n        android:title=\"@string/label_search\"\n        app:actionViewClass=\"android.support.v7.widget.SearchView\"\n        app:showAsAction=\"always|collapseActionView\"></item>\n</menu>"
  },
  {
    "path": "app/src/main/res/menu/menu_phonecall_detail.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/menu_phonecall_save\"\n        android:title=\"@string/label_save\"\n        app:showAsAction=\"always\" />\n</menu>"
  },
  {
    "path": "app/src/main/res/menu/menu_phonecalls.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/menu_phonecall_search\"\n        android:icon=\"@drawable/ic_action_search\"\n        android:title=\"@string/label_search\"\n        app:actionViewClass=\"android.support.v7.widget.SearchView\"\n        app:showAsAction=\"always|collapseActionView\"></item>\n</menu>"
  },
  {
    "path": "app/src/main/res/menu/menu_quotation_cancel_sheet.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <!--<item-->\n    <!--android:id=\"@+id/menu_so_send_by_email\"-->\n    <!--android:icon=\"@drawable/ic_action_message\"-->\n    <!--android:title=\"@string/label_send_by_email\"></item>-->\n\n    <item\n        android:id=\"@+id/menu_quotation_new\"\n        android:icon=\"@drawable/ic_action_add\"\n        android:title=\"@string/label_new_copy_quotation\"></item>\n</menu>"
  },
  {
    "path": "app/src/main/res/menu/menu_quotation_sheet.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <!--<item-->\n        <!--android:id=\"@+id/menu_so_send_by_email\"-->\n        <!--android:icon=\"@drawable/ic_action_message\"-->\n        <!--android:title=\"@string/label_send_by_email\"></item>-->\n    <item\n        android:id=\"@+id/menu_so_confirm_sale\"\n        android:icon=\"@drawable/ic_action_sale_order\"\n        android:title=\"@string/label_confirm_sale\"></item>\n    <item\n        android:id=\"@+id/menu_quotation_cancel\"\n        android:icon=\"@drawable/ic_action_navigation_close\"\n        android:title=\"@string/label_cancel\"></item>\n</menu>"
  },
  {
    "path": "app/src/main/res/menu/menu_sale_add_item.xml",
    "content": "<menu xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    tools:context=\"com.odoo.addons.sale.AddProductLineWizard\">\n    <item\n        android:id=\"@+id/menu_sale_add_item_done\"\n        android:title=\"Done\"\n        android:icon=\"@drawable/ic_action_done\"\n        app:showAsAction=\"always\" />\n</menu>\n"
  },
  {
    "path": "app/src/main/res/menu/menu_sale_detail.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/menu_sale_save\"\n        android:title=\"@string/label_save\"\n        app:showAsAction=\"always\" />\n    <item\n        android:id=\"@+id/menu_sale_detail_more\"\n        android:icon=\"@drawable/ic_action_more\"\n        app:showAsAction=\"always\"\n        android:title=\"@string/label_more\">\n        <menu>\n            <item\n                android:id=\"@+id/menu_sale_confirm_sale\"\n                android:title=\"@string/label_sale_confirm_sale\" />\n            <item\n                android:id=\"@+id/menu_sale_new_copy_of_quotation\"\n                android:title=\"@string/label_sale_new_copy_of_quotation\" />\n        </menu>\n    </item>\n</menu>"
  },
  {
    "path": "app/src/main/res/menu/menu_sales_order.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/menu_sales_search\"\n        android:icon=\"@drawable/ic_action_search\"\n        android:title=\"@string/label_search\"\n        app:actionViewClass=\"android.support.v7.widget.SearchView\"\n        app:showAsAction=\"always|collapseActionView\"></item>\n</menu>"
  },
  {
    "path": "app/src/main/res/menu/menu_sheet_customer.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item\n        android:id=\"@+id/menu_customer_opportunity\"\n        android:icon=\"@drawable/ic_action_opportunities\"\n        android:title=\"@string/label_opportunities\" />\n    <item\n        android:id=\"@+id/menu_customer_leads\"\n        android:icon=\"@drawable/ic_action_leads\"\n        android:title=\"@string/label_leads\" />\n    <item\n        android:id=\"@+id/menu_customer_location\"\n        android:icon=\"@drawable/ic_action_location\"\n        android:title=\"@string/label_location\" />\n    <item\n        android:id=\"@+id/menu_customer_call\"\n        android:icon=\"@drawable/ic_action_phone\"\n        android:title=\"@string/label_call\" />\n    <item\n        android:id=\"@+id/menu_customer_send_message\"\n        android:icon=\"@drawable/ic_action_message\"\n        android:title=\"@string/label_message\" />\n    <item\n        android:id=\"@+id/menu_customer_schedule_call\"\n        android:icon=\"@drawable/ic_action_reschedule\"\n        android:title=\"@string/label_schedule_call\" />\n    <!--<item-->\n    <!--android:id=\"@+id/menu_customer_meetings\"-->\n    <!--android:icon=\"@drawable/ic_action_calendar\"-->\n    <!--android:title=\"@string/label_meetings\" />-->\n</menu>"
  },
  {
    "path": "app/src/main/res/menu/menu_so_sheet.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <!--<item-->\n        <!--android:id=\"@+id/menu_so_send_by_email\"-->\n        <!--android:icon=\"@drawable/ic_action_message\"-->\n        <!--android:title=\"@string/label_send_by_email\"></item>-->\n    <item\n        android:id=\"@+id/menu_quotation_cancel\"\n        android:icon=\"@drawable/ic_action_navigation_close\"\n        android:title=\"@string/label_sale_cancel_order\"></item>\n</menu>"
  },
  {
    "path": "app/src/main/res/values/attrs.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <declare-styleable name=\"BezelImageView\">\n        <attr name=\"maskDrawable\" format=\"reference\" />\n        <attr name=\"borderDrawable\" format=\"reference\" />\n        <attr name=\"desaturateOnPress\" format=\"boolean\" />\n    </declare-styleable>\n    <declare-styleable name=\"ODrawerScrollView\">\n        <attr name=\"insetForeground\" format=\"reference|color\" />\n    </declare-styleable>\n\n    <!-- Custom Controls -->\n    <declare-styleable name=\"OField\">\n        <attr name=\"fieldName\" format=\"string\" />\n        <attr name=\"iconResource\" format=\"reference\" />\n        <attr name=\"showIcon\" format=\"boolean\" />\n        <attr name=\"showLabel\" format=\"boolean\" />\n        <attr name=\"iconTint\" format=\"reference|color\" />\n        <attr name=\"parsePattern\" format=\"string\" />\n        <attr name=\"withOutSidePadding\" format=\"boolean\" />\n        <attr name=\"fieldType\">\n            <enum name=\"Text\" value=\"0\" />\n            <enum name=\"Boolean\" value=\"1\" />\n            <enum name=\"ManyToOne\" value=\"2\" />\n            <enum name=\"Chips\" value=\"3\" />\n            <enum name=\"Selection\" value=\"4\" />\n            <enum name=\"Date\" value=\"5\" />\n            <enum name=\"DateTime\" value=\"6\" />\n            <enum name=\"Blob\" value=\"7\" />\n            <enum name=\"Time\" value=\"8\" />\n        </attr>\n        <attr name=\"widgetType\">\n            <enum name=\"Switch\" value=\"0\" />\n            <enum name=\"RadioGroup\" value=\"1\" />\n            <enum name=\"SelectionDialog\" value=\"2\" />\n            <enum name=\"Searchable\" value=\"3\" />\n            <enum name=\"SearchableLive\" value=\"4\" />\n            <enum name=\"Image\" value=\"5\" />\n            <enum name=\"ImageCircle\" value=\"6\" />\n            <enum name=\"Duration\" value=\"7\" />\n        </attr>\n        <attr name=\"widgetImageSize\" format=\"dimension\" />\n        <attr name=\"withBottomPadding\" format=\"boolean\" />\n        <attr name=\"withTopPadding\" format=\"boolean\" />\n        <attr name=\"controlLabel\" format=\"string|reference\" />\n        <attr name=\"defaultValue\" format=\"reference|string\" />\n        <attr name=\"defaultImage\" format=\"reference\" />\n        <attr name=\"valueArray\" format=\"reference\" />\n        <attr name=\"fieldTextAppearance\" format=\"reference\" />\n        <attr name=\"fieldTextSize\" format=\"dimension\" />\n        <attr name=\"fieldTextColor\" format=\"color\" />\n        <attr name=\"fieldLabelColor\" format=\"color\" />\n        <attr name=\"fieldLabelTextAppearance\" format=\"reference\" />\n        <attr name=\"fieldLabelSize\" format=\"dimension\" />\n    </declare-styleable>\n    <declare-styleable name=\"OForm\">\n        <attr name=\"editableMode\" format=\"boolean\" />\n        <attr name=\"modelName\" format=\"string\" />\n        <attr name=\"autoUIGenerate\" format=\"boolean\" />\n        <attr name=\"controlIconTint\" format=\"color\" />\n    </declare-styleable>\n    <declare-styleable name=\"FloatingActionButton\">\n        <attr name=\"drawable\" format=\"integer\" />\n        <attr name=\"fabColor\" format=\"color\" />\n        <attr name=\"shadowRadius\" format=\"float\" />\n        <attr name=\"shadowDx\" format=\"float\" />\n        <attr name=\"shadowDy\" format=\"float\" />\n        <attr name=\"shadowColor\" format=\"integer\" />\n    </declare-styleable>\n\n    <declare-styleable name=\"MailChatterView\">\n        <attr name=\"resModelName\" format=\"string\" />\n    </declare-styleable>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values/base-strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"label_accounts_settings\">Odoo</string>\n    <string name=\"label_login\">Login</string>\n    <string name=\"label_accept_login\">Accept &amp; Login</string>\n    <string name=\"label_your_self_hosted_url\">Your self-hosted URL</string>\n    <string name=\"label_username\">Username</string>\n    <string name=\"label_username_or_email\">Username or email</string>\n    <string name=\"label_password\">Password</string>\n    <string name=\"label_forgot_password\">Forgot password?</string>\n    <string name=\"label_add_self_hosted_url\">Add self-hosted URL</string>\n    <string name=\"label_login_with_odoo\">Login with Odoo.com</string>\n    <string name=\"label_create_account\">Create account</string>\n    <string name=\"label_select_database\">Select Database</string>\n    <string name=\"title_ssl_warning\">SSL Warning</string>\n    <string name=\"untrusted_ssl_warning\">The site\\'s security certificate is not trusted !</string>\n    <string name=\"error_invalid_odoo_url\">Invalid Odoo URL !</string>\n    <string name=\"error_invalid_username_or_password\">Invalid Username or Password</string>\n    <string name=\"error_invalid_password\">Invalid password</string>\n    <string name=\"error_provide_username\">Provide username</string>\n    <string name=\"error_provide_password\">Provide password</string>\n    <string name=\"error_provide_server_url\">Provide server URL</string>\n    <string name=\"status_connecting_to_server\">Connecting&#8230;</string>\n    <string name=\"status_connected_to_server\">Connected</string>\n    <string name=\"status_logging_in\">Logging in&#8230;</string>\n    <string name=\"status_logging_in_with_instance\">Logging in to instance&#8230;</string>\n    <string name=\"status_login_success\">Login Success</string>\n    <string name=\"status_logout_success\">Logout Success</string>\n    <string name=\"status_creating_account\">Creating account</string>\n    <string name=\"status_getting_instances\">Getting instances&#8230;</string>\n    <string name=\"status_redirecting\">Redirecting&#8230;</string>\n    <string name=\"title_instance_expired\">Instance Expired</string>\n    <string name=\"label_select_instance\">Select Instance</string>\n    <string name=\"label_select_user\">Login to User</string>\n    <string name=\"label_accounts\">Accounts</string>\n    <string name=\"label_settings\">Settings</string>\n    <string name=\"label_save\">Save</string>\n    <string name=\"label_edit\">Edit</string>\n    <string name=\"label_required\">required</string>\n    <string name=\"label_more\">More</string>\n    <string name=\"label_alert\">Alert</string>\n    <string name=\"label_warning\">Warning</string>\n    <string name=\"label_error\">Error</string>\n    <string name=\"label_share\">Share</string>\n    <string name=\"label_import_contact\">Import</string>\n    <string name=\"label_address\">Address</string>\n    <string name=\"label_reply\">Reply</string>\n    <string name=\"label_close\">Close</string>\n    <string name=\"label_send\">Send</string>\n    <!-- Drawer -->\n    <string name=\"label_drawer_account_add_account\">Add Account</string>\n    <string name=\"label_drawer_account_manage_accounts\">Manage Accounts</string>\n    <!-- Common Labels -->\n    <string name=\"title_application_settings\">\"Application Settings\"</string>\n    <string name=\"title_select_account\">\"Select Account\"</string>\n    <string name=\"title_settings\">Settings</string>\n    <string name=\"title_profile\">Profile</string>\n    <string name=\"title_general_settings\">General Settings</string>\n    <string name=\"title_accounts\">Accounts</string>\n    <string name=\"title_about\">About</string>\n    <string name=\"title_confirm\">Confirm</string>\n    <string name=\"title_user_profile\">Odoo User Profile</string>\n    <string name=\"title_configuration\">Configuration</string>\n    <string name=\"title_refresh_details\">Refresh Details</string>\n    <string name=\"title_add_account\">Add Account</string>\n    <string name=\"title_working\">Working&#8230;</string>\n    <string name=\"title_please_wait\">Please wait&#8230;</string>\n    <string name=\"label_new\">New</string>\n    <string name=\"label_ok\">OK</string>\n    <string name=\"label_yes\">Yes</string>\n    <string name=\"label_no\">No</string>\n    <string name=\"label_search\">Search</string>\n    <string name=\"label_delete\">Delete</string>\n    <string name=\"label_cancel\">Cancel</string>\n    <string name=\"label_logout\">Logout</string>\n    <string name=\"label_version\">Version</string>\n    <string name=\"label_update_info\">Update Info</string>\n    <string name=\"label_process_anyway\">Process Anyway</string>\n    <string name=\"label_read_more\">Read More</string>\n    <string name=\"label_read_less\">Read Less</string>\n    <string name=\"label_no_records_found\">No Records Found</string>\n    <string name=\"label_odoo_mobile_on_github\">Odoo Mobile on GitHub</string>\n    <string name=\"label_odoo_developer_mode\">Developer Mode</string>\n    <string name=\"label_export_db\">Export Database</string>\n    <string name=\"label_our_apps\">Our apps</string>\n    <string name=\"label_attach_a_file\"> + Attach a file</string>\n    <!-- Toasts -->\n    <string name=\"developer_2_tap\">Need 2 tap for developer mode</string>\n    <string name=\"developer_5_tap\">Developer mode activated</string>\n    <string name=\"toast_setting_saved\">Setting saved.</string>\n    <string name=\"toast_are_you_sure_logout\">Are you sure want to logout ?</string>\n    <string name=\"toast_are_you_sure_delete_account\">Are you sure want to delete account ?</string>\n    <string name=\"toast_user_already_exists\">User already exists</string>\n    <string name=\"toast_network_required\">Network required</string>\n    <string name=\"toast_account_removed\">Account Removed Successfully</string>\n    <string name=\"toast_no_activity_found_to_handle_file\">No activity found to handle file</string>\n    <string name=\"toast_updating_password\">Updating password</string>\n    <!-- Setting pref strings -->\n    <string-array name=\"syncInterval\">\n        <item name=\"5\">Every 5 minutes</item>\n        <item name=\"10\">Every 10 minutes</item>\n        <item name=\"20\">Every 20 minutes</item>\n        <item name=\"40\">Every 40 minutes</item>\n        <item name=\"60\">Every 60 minutes</item>\n        <item name=\"1440\">Once in a day</item>\n    </string-array>\n    <string-array name=\"syncIntervalValues\">\n        <item name=\"5\">5</item>\n        <item name=\"10\">10</item>\n        <item name=\"20\">20</item>\n        <item name=\"40\">40</item>\n        <item name=\"60\">60</item>\n        <item name=\"1440\">1440</item>\n    </string-array>\n    <string-array name=\"syncDataLimit\">\n        <item name=\"30\">1 month old</item>\n        <item name=\"60\">2 months old</item>\n        <item name=\"90\">3 months old</item>\n    </string-array>\n    <string-array name=\"syncDataLimitValues\">\n        <item name=\"30\">30</item>\n        <item name=\"60\">60</item>\n        <item name=\"90\">90</item>\n    </string-array>\n    <string name=\"general_settings\">General Settings</string>\n    <string name=\"application_settings_summary\">Sync settings, Interval settings, sync data limit, and more</string>\n    <string name=\"account_settings\">Account Settings</string>\n    <string name=\"add_account\">Add Account</string>\n    <string name=\"summary_about_odoo_mobile\">Odoo Mobile</string>\n    <string name=\"build_version\">Build Version</string>\n    <string name=\"label_powered_by\">Powered by</string>\n    <string name=\"odoo_mobile_framework\">Odoo Mobile framework</string>\n    <string name=\"supported_versions\">Supported versions</string>\n    <string name=\"supported_versions_names\">Odoo 7.0+</string>\n    <string name=\"label_access_odoo_mobile\">Connect Odoo Mobile</string>\n    <!-- About Company Fragment Strings -->\n    <string name=\"about_Company_line1\">Copyright © 2004-TODAY Odoo SA. All Rights Reserved.</string>\n    <string name=\"about_Company_line2\">Odoo is a trademark of the <a href=\"https://www.odoo.com/\">Odoo.com.</a></string>\n    <string name=\"about_Company_line3\">Licenced under the terms of <a href=\"http://www.gnu.org/licenses/agpl.html/\">GNU Affero General Public License</a></string>\n    <string name=\"about_Company_line4\">For more information visit <a href=\"https://www.odoo.com/\">Odoo.com</a>.</string>\n    <string name=\"app_version_name\">Version</string>\n    <string name=\"notification_default_ring_tone\">content://settings/system/notification_sound</string>\n    <string name=\"disclaimer_content\">By continuing, you agree to the <a href=\"http://www.odoo.com/\">Terms of Service</a> and <a href=\"http://www.odoo.com/\">Privacy Policy</a></string>\n</resources>\n\n    \n"
  },
  {
    "path": "app/src/main/res/values/bool.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <bool name=\"atLeastKitKat\">false</bool>\n</resources>"
  },
  {
    "path": "app/src/main/res/values/colors.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n\n    <color name=\"list_divider\">#ddd</color>\n\n    <!-- Odoo Theme Colors -->\n\n    <color name=\"odoo_primary\">#a24689</color>\n    <color name=\"odoo_secondary\">#8f8f8f</color>\n    <color name=\"odoo_optional\">#21b799</color>\n\n    <!-- Drawer Colors -->\n    <color name=\"drawer_text_color\">#282828</color>\n    <color name=\"drawer_text_color_selected\">#414141</color>\n    <color name=\"drawer_icon_tint\">#808080</color>\n    <color name=\"drawer_icon_tint_selected\">#414141</color>\n    <color name=\"drawer_focused\">#f3f3f3</color>\n    <color name=\"drawer_pressed\">#EBEBEB</color>\n    <color name=\"drawer_background\">#ffffffff</color>\n    <color name=\"drawer_separator_text_color\">#acacac</color>\n    <color name=\"drawer_separator_background\">#e5e5e5</color>\n\n    <!-- Android Style Colors -->\n    <color name=\"android_blue\">#33B5E5</color>\n    <color name=\"android_blue_dark\">#0099CC</color>\n    <color name=\"android_violet\">#AA66CC</color>\n    <color name=\"android_violet_dark\">#9933CC</color>\n    <color name=\"android_green\">#99CC00</color>\n    <color name=\"android_green_dark\">#669900</color>\n    <color name=\"android_orange\">#FFBB33</color>\n    <color name=\"android_orange_dark\">#FF8800</color>\n    <color name=\"android_red\">#FF4444</color>\n    <color name=\"android_red_dark\">#CC0000</color>\n\n    <color name=\"control_focused\">#e5e5e5</color>\n    <color name=\"control_pressed\">#acacac</color>\n\n\n    <array name=\"letter_tile_colors\">\n        <item>@color/android_blue</item>\n        <item>@color/android_violet_dark</item>\n        <item>@color/android_red</item>\n        <item>@color/android_green_dark</item>\n        <item>@color/android_blue_dark</item>\n        <item>@color/android_orange</item>\n        <item>@color/android_red_dark</item>\n        <item>@color/android_violet</item>\n        <item>@color/android_green</item>\n        <item>@color/android_orange_dark</item>\n    </array>\n\n    <color name=\"icon_tint\">#5e5e5e</color>\n    <color name=\"actionbar_spinner_text_color\">#414141</color>\n\n    <color name=\"base_chatter_view_background\">#f3f3f3</color>\n    <color name=\"base_chatter_view_note_background\">#dadada</color>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values/dimens.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <dimen name=\"activity_vertical_margin\">16dp</dimen>\n    <dimen name=\"activity_horizontal_margin\">16dp</dimen>\n\n    <dimen name=\"default_8dp\">8dp</dimen>\n    <dimen name=\"default_16dp\">16dp</dimen>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values/fonts.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n\n    <!-- Fonts -->\n    <string name=\"font_normal\">sans-serif</string>\n    <string name=\"font_light\">sans-serif-light</string>\n    <string name=\"font_condensed\">sans-serif-condensed</string>\n\n    <!-- Text colors -->\n    <color name=\"body_text_1\">#de000000</color>\n    <color name=\"body_text_2\">#8a000000</color>\n    <color name=\"body_text_3\">#60000000</color>\n    <color name=\"body_text_disabled\">#44000000</color>\n    <color name=\"body_text_1_inverse\">#deffffff</color>\n    <color name=\"body_text_2_inverse\">#8affffff</color>\n\n    <!-- Text Sizes -->\n    <dimen name=\"text_size_xsmall\">11sp</dimen>\n    <dimen name=\"text_size_xxsmall\">10sp</dimen>\n    <dimen name=\"text_size_small\">12sp</dimen>\n    <dimen name=\"text_size_medium\">14sp</dimen>\n    <dimen name=\"text_size_xmedium\">16sp</dimen>\n    <dimen name=\"text_size_large\">18sp</dimen>\n    <dimen name=\"text_size_xlarge\">20sp</dimen>\n    <dimen name=\"text_size_xxlarge\">25sp</dimen>\n\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n\n    <string name=\"app_name\">CRM</string>\n    <string name=\"label_today\">Today</string>\n    <!-- Sync Labels// -->\n    <string name=\"sync_label_customers\">Customers</string>\n    <string name=\"sync_label_calendar\">Calendar</string>\n    <string name=\"sync_label_lead_opportunities\">Leads/Opportunities</string>\n    <string name=\"sync_label_quotation_sales_orders\">Quotations/Sales Orders</string>\n    <string name=\"sync_label_phonecalls\">Logged Calls</string>\n    <string name=\"no_notification\">No Notification</string>\n    <string name=\"at_the_time_of_event\">At the time of event</string>\n    <string name=\"on_the_day_at\">On the day at %s</string>\n    <string name=\"on_your_working_day_start_time\">Next working day time</string>\n    <string name=\"day_before_at\">The day before at %s</string>\n    <string name=\"minutes_before\">%s minutes before</string>\n    <string name=\"custom\">Custom...</string>\n    <string name=\"error_end_date_small_than_start_date\">End date cannot be set before start date.</string>\n    <string name=\"label_all\">All</string>\n    <string name=\"label_leads\">Leads</string>\n    <string name=\"label_lead\">Lead</string>\n    <string name=\"label_opp\">Opportunity</string>\n    <string name=\"label_opportunities\">Opportunities</string>\n    <string name=\"label_quotation\">Quotations</string>\n    <string name=\"label_opportunity\">Opportunity</string>\n    <string name=\"label_sale_orders\">Sales Orders</string>\n    <string name=\"label_phone_calls\">Phone calls</string>\n    <string name=\"label_logged_calls\">Logged calls</string>\n    <string name=\"label_scheduled_calls\">Scheduled calls</string>\n    <string name=\"label_logged_call\">Logged call</string>\n    <string name=\"label_scheduled_call\">Scheduled call</string>\n    <string name=\"label_log_call\">Log Call</string>\n    <string name=\"label_convert_to_opportunity\">Convert to Opportunity</string>\n    <string name=\"label_create_opportunity\">Create Opportunity</string>\n    <string name=\"label_convert_to_quotation\">Create Quotation</string>\n    <string name=\"label_create_quotation\">@string/label_convert_to_quotation</string>\n    <string name=\"label_mark_as_lost\">Mark Lost</string>\n    <string name=\"label_mark_as_won\">Mark Won</string>\n    <string name=\"label_location\">Location</string>\n    <string name=\"label_call\">Call</string>\n    <string name=\"label_call_held\">Held</string>\n    <string name=\"label_message\">Message</string>\n    <string name=\"label_schedule_call\">Schedule</string>\n    <string name=\"label_meetings\">Meeting</string>\n    <string name=\"label_sale_confirm_sale\">Confirm Sale</string>\n    <string name=\"label_sale_create_invoice\">Create Invoice</string>\n    <string name=\"label_sale_cancel_order\">Cancel Order</string>\n    <string name=\"label_sale_new_copy_of_quotation\">New Copy of Quotation</string>\n    <string name=\"label_mark_done\">Mark Done</string>\n    <string name=\"label_tag_new\">New</string>\n    <string name=\"label_quotation_created\">Quotation Created for</string>\n    <string name=\"label_re_schedule\">Re-Schedule</string>\n    <string name=\"label_sync_warning\">Need to sync before converting to Opportunity</string>\n    <string name=\"label_no_customer_found\">No Customers Found</string>\n    <string name=\"label_no_location_found\">No location found !</string>\n    <string name=\"label_no_contact_found\">No contact found !</string>\n    <string name=\"label_no_opportunity_found\">No Opportunity Found !</string>\n    <string name=\"label_no_email_found\">No email found !</string>\n    <string name=\"label_no_logged_calls_found\">No Logged calls Found</string>\n    <string name=\"label_no_scheduled_calls_found\">No Scheduled calls Found</string>\n    <string name=\"label_event_marked\">Event marked</string>\n    <string name=\"label_new_meeting\">New Meeting</string>\n    <string name=\"label_edit_meeting\">Edit Meeting</string>\n    <string name=\"label_missed_call_from_customer\">Missed call from customer</string>\n    <string name=\"label_manage_order_lines\">Manage order lines</string>\n    <string name=\"label_define_lead\">Define the lead</string>\n    <string name=\"label_expected_revenue\">Expected Revenue</string>\n    <string name=\"label_at\"> at </string>\n    <string name=\"label_conversion_action\"> Conversion Action </string>\n    <string name=\"toast_information_saved\">Information Saved</string>\n    <string name=\"toast_phone_call_marked_done\">Phone call held</string>\n    <string name=\"toast_event_marked_done\">Event marked done</string>\n    <string name=\"toast_image_size_too_large\">Image size is too large.</string>\n    <string name=\"toast_marked\"> marked</string>\n    <string name=\"message_to\">Message to %s</string>\n    <string name=\"add_internal_note\">Add and internal note</string>\n    <string name=\"internal_note_hint\">Add an internal note that will not be sent to the followers</string>\n    <string name=\"label_log_note\">Log note</string>\n    <string name=\"label_send_message\"><u>Send a message</u></string>\n    <string name=\"label_log_an_internal_note\"><u>Log an internal note</u></string>\n    <string-array name=\"array_conversation_actions\">\n        <item>Convert to opportunity</item>\n        <item>Merge with existing opportunities</item>\n    </string-array>\n\n    <string name=\"label_send_by_email\">Send by email</string>\n    <string name=\"label_confirm_sale\">Confirm Sale</string>\n    <string name=\"label_copy_quotation\">Copy of quotation</string>\n    <string name=\"label_no_order_line\">You cannot confirm a sales order which has no line</string>\n    <string name=\"label_quotation_confirm\">Quotation confirmed !</string>\n    <string name=\"label_new_copy_quotation\">New Copy of Quotation</string>\n    <string name=\"label_opt_schedule_log_call\">Schedule/Log Call</string>\n    <string name=\"label_opt_schedule_meeting\">Meeting</string>\n\n    <!-- Working day start time -->\n    <string name=\"default_day_start_time\">09:00:00</string>\n\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values/strings.xml~",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n\n    <string name=\"app_name\">CRM</string>\n    <string name=\"label_today\">Today</string>\n    <!-- Sync Labels// -->\n    <string name=\"sync_label_customers\">Customers</string>\n    <string name=\"sync_label_calendar\">Calendar</string>\n    <string name=\"sync_label_lead_opportunities\">Leads/Opportunities</string>\n    <string name=\"sync_label_quotation_sales_orders\">Quotations/Sales Orders</string>\n    <string name=\"sync_label_phonecalls\">Logged Calls</string>\n    <string name=\"no_notification\">No Notification</string>\n    <string name=\"at_the_time_of_event\">At the time of event</string>\n    <string name=\"on_the_day_at\">On the day at %s</string>\n    <string name=\"day_before_at\">The day before at %s</string>\n    <string name=\"minutes_before\">%s minutes before</string>\n    <string name=\"custom\">Custom...</string>\n    <string name=\"error_end_date_small_than_start_date\">End date cannot be set before start date.</string>\n    <string name=\"label_leads\">Leads</string>\n    <string name=\"label_lead\">Lead</string>\n    <string name=\"label_opp\">Opportunity</string>\n    <string name=\"label_opportunities\">Opportunities</string>\n    <string name=\"label_quotation\">Quotations</string>\n    <string name=\"label_opportunity\">Opportunity</string>\n    <string name=\"label_sale_orders\">Sales Orders</string>\n    <string name=\"label_phone_calls\">Phone calls</string>\n    <string name=\"label_logged_calls\">Logged calls</string>\n    <string name=\"label_convert_to_opportunity\">Convert to Opportunity</string>\n    <string name=\"label_create_opportunity\">Create Opportunity</string>\n    <string name=\"label_convert_to_quotation\">Create Quotation</string>\n    <string name=\"label_create_quotation\">@string/label_convert_to_quotation</string>\n    <string name=\"label_mark_as_lost\">Mark Lost</string>\n    <string name=\"label_mark_as_won\">Mark Won</string>\n    <string name=\"label_location\">Location</string>\n    <string name=\"label_call\">Call</string>\n    <string name=\"label_message\">Message</string>\n    <string name=\"label_schedule_call\">Schedule Call</string>\n    <string name=\"label_meetings\">Meeting</string>\n    <string name=\"label_sale_confirm_sale\">Confirm Sale</string>\n    <string name=\"label_sale_create_invoice\">Create Invoice</string>\n    <string name=\"label_sale_cancel_order\">Cancel Order</string>\n    <string name=\"label_sale_new_copy_of_quotation\">New Copy of Quotation</string>\n    <string name=\"label_mark_done\">Mark Done</string>\n    <string name=\"label_tag_new\">New</string>\n    <string name=\"label_quotation_created\">Quotation Created for</string>\n    <string name=\"label_re_schedule\">Re-Schedule</string>\n<<<<<<< HEAD\n=======\n    <string name=\"label_sync_warning\">Need to sync before converting to Opportunity</string>\n\n    <string name=\"label_no_customer_found\">No Customers Found</string>\n    <string name=\"label_no_location_found\">No location found !</string>\n    <string name=\"label_no_contact_found\">No contact found !</string>\n    <string name=\"label_no_email_found\">No email found !</string>\n    <string name=\"label_no_logged_calls_found\">No Logged calls Found</string>\n    <string name=\"label_event_marked\">Event marked </string>\n    <string name=\"label_new_meeting\">New Meeting</string>\n    <string name=\"label_edit_meeting\">Edit Meeting</string>\n    <string name=\"label_missed_call_from_customer\">Missed call from customer</string>\n\n    <string name=\"toast_information_saved\">Information Saved</string>\n    <string name=\"toast_phone_call_marked_done\">Phone call marked done</string>\n    <string name=\"toast_event_marked_done\">Event marked done</string>\n    <string name=\"toast_image_size_too_large\">Image size is too large.</string>\n    <string name=\"toast_marked\"> marked</string>\n>>>>>>> master-crm-studio-dpr\n    <string-array name=\"array_conversation_actions\">\n        <item>Convert to opportunity</item>\n        <item>Merge with existing opportunities</item>\n    </string-array>\n    <string name=\"label_send_by_email\">Send by email</string>\n    <string name=\"label_confirm_sale\">Confirm Sale</string>\n    <string name=\"label_copy_quotation\">Copy of quotation</string>\n    <string name=\"label_no_order_line\">You cannot confirm a sales order which has no line</string>\n    <string name=\"label_quotation_confirm\">Quotation confirmed !</string>\n    <string name=\"label_new_copy_quotation\">New Copy of Quotation</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values/styles.xml",
    "content": "<resources>\n\n    <!-- Base application theme. -->\n    <style name=\"AppTheme\" parent=\"Theme.AppCompat.Light.NoActionBar\">\n        <!-- Customize your theme here. -->\n    </style>\n\n    <style name=\"ToolBarTheme\" parent=\"@style/ThemeOverlay.AppCompat.Dark.ActionBar\">\n        <item name=\"homeAsUpIndicator\">@drawable/ic_action_navigation_menu</item>\n        <item name=\"android:homeAsUpIndicator\">@drawable/ic_action_navigation_menu</item>\n    </style>\n\n    <style name=\"StatusBarView\">\n        <item name=\"android:layout_width\">match_parent</item>\n        <item name=\"android:layout_height\">@dimen/statusBarHeight</item>\n        <item name=\"android:background\">@color/colorPrimaryDark</item>\n    </style>\n\n    <style name=\"ViewSeparator\">\n        <item name=\"android:layout_width\">match_parent</item>\n        <item name=\"android:layout_height\">1dp</item>\n        <item name=\"android:background\">#cccccc</item>\n    </style>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values/theme-values.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n\n    <!-- Application Base Theme Colors -->\n    <color name=\"theme_primary\">#a24689</color>\n    <color name=\"theme_primary_dark\">#6d2f5c</color>\n    <color name=\"theme_primary_light\">#c272ac</color>\n    <color name=\"theme_secondary\">#009688</color>\n    <color name=\"theme_secondary_dark\">#00635a</color>\n    <color name=\"theme_secondary_light\">#00c9b6</color>\n\n    <color name=\"colorPrimary\">@color/theme_primary</color>\n    <color name=\"colorPrimaryDark\">@color/theme_primary_dark</color>\n    <color name=\"colorAccent\">@color/theme_primary_dark</color>\n\n    <!-- Drawer Properties -->\n    <color name=\"drawerDefaultBackgroundColor\">#ffffff</color>\n    <dimen name=\"drawerDefaultWidth\">280dp</dimen>\n    <dimen name=\"drawerAccountBottomPadding\">16dp</dimen>\n    <dimen name=\"drawerAvatarWidthHeight\">60dp</dimen>\n\n    <!-- Dimensions -->\n    <dimen name=\"statusBarHeight\">0dp</dimen>\n\n    <!-- Booleans -->\n    <bool name=\"fitToScreenWindow\">true</bool>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-v19/bool.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <bool name=\"atLeastKitKat\">true</bool>\n</resources>"
  },
  {
    "path": "app/src/main/res/values-v21/colors.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n\n <color name=\"actionbar_spinner_text_color\">#fff</color>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-v21/styles.xml",
    "content": "<resources xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <style name=\"AppBaseTheme\" parent=\"Theme.AppCompat.Light.NoActionBar\"></style>\n\n    <style name=\"AppTheme\" parent=\"AppBaseTheme\"> <!-- Application theme. -->\n        <!-- All customizations that are NOT specific to a particular API-level can go here. -->\n        <item name=\"android:windowContentOverlay\">@null</item>\n        <item name=\"android:colorPrimary\">@color/colorPrimary</item>\n        <item name=\"colorPrimary\">@color/colorPrimary</item>\n        <item name=\"android:colorPrimaryDark\">@color/colorPrimaryDark</item>\n        <item name=\"colorPrimaryDark\">@color/colorPrimaryDark</item>\n        <item name=\"colorAccent\">@color/colorAccent</item>\n        <item name=\"android:colorAccent\">@color/colorAccent</item>\n        <item name=\"android:windowTranslucentStatus\">@bool/fitToScreenWindow</item>\n        <item name=\"android:statusBarColor\">@android:color/transparent</item>\n        <item name=\"android:windowDrawsSystemBarBackgrounds\">true</item>\n        <item name=\"android:windowActionBarOverlay\">true</item>\n        <item name=\"windowActionBarOverlay\">true</item>\n    </style>\n\n</resources>"
  },
  {
    "path": "app/src/main/res/values-v21/theme-values.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n\n    <!-- Drawer Properties -->\n    <dimen name=\"drawerDefaultWidth\">295dp</dimen>\n    <dimen name=\"drawerAccountBottomPadding\">8dp</dimen>\n    <dimen name=\"statusBarHeight\">24dp</dimen>\n    <!-- Booleans -->\n    <bool name=\"fitToScreenWindow\">true</bool>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-w820dp/dimens.xml",
    "content": "<resources>\n    <!-- Example customization of dimensions originally defined in res/values/dimens.xml\n         (such as screen margins) for screens with more than 820dp of available width. This\n         would include 7\" and 10\" devices in landscape (~960dp and ~1280dp respectively). -->\n    <dimen name=\"activity_horizontal_margin\">64dp</dimen>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/xml/authenticator.xml",
    "content": "<account-authenticator xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:accountType=\"com.odoo.auth\"\n    android:icon=\"@drawable/ic_odoo\"\n    android:label=\"@string/label_accounts_settings\"\n    android:smallIcon=\"@drawable/ic_odoo\">\n\n</account-authenticator>"
  },
  {
    "path": "app/src/main/res/xml/base_preference.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<PreferenceScreen xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <PreferenceCategory\n        android:key=\"account_sync_settings\"\n        android:title=\"Sync Settings\">\n        <PreferenceScreen\n            android:key=\"account_settings\"\n            android:summary=\"Enable or disable data synchronization\"\n            android:title=\"Sync Settings\">\n            <intent android:action=\"android.settings.SYNC_SETTINGS\" />\n        </PreferenceScreen>\n    </PreferenceCategory>\n    <PreferenceCategory\n        android:key=\"sync_interval_settings\"\n        android:title=\"Sync interval\">\n        <ListPreference\n            android:defaultValue=\"1440\"\n            android:entries=\"@array/syncInterval\"\n            android:entryValues=\"@array/syncIntervalValues\"\n            android:key=\"sync_interval\"\n            android:summary=\"Define how often synchronization will be performed\"\n            android:title=\"Sync interval\" />\n    </PreferenceCategory>\n    <PreferenceCategory\n        android:key=\"sync_data_limit_settings\"\n        android:title=\"Data Sync Limit\">\n        <ListPreference\n            android:defaultValue=\"60\"\n            android:entries=\"@array/syncDataLimit\"\n            android:entryValues=\"@array/syncDataLimitValues\"\n            android:key=\"sync_data_limit\"\n            android:summary=\"Define how old data to be synchronized\"\n            android:title=\"Sync data limit\" />\n    </PreferenceCategory>\n\n    <PreferenceCategory\n        android:title=\"Notifications\"\n        android:key=\"notification_settings\">\n        <RingtonePreference\n            android:key=\"phonecall_notification_ringtone\"\n            android:title=\"Notification ring tone\"\n            android:ringtoneType=\"notification\"\n            android:defaultValue=\"@string/notification_default_ring_tone\"\n            android:summary=\"Set notification ring tone\" />\n        <SwitchPreference\n            android:key=\"hands_up_notification\"\n            android:title=\"Enable hands up notification\"\n            android:summary=\"Allow application to show quick notification on screen\"\n            android:summaryOff=\"Enable to allow application to show quick notification on screen\"\n            android:defaultValue=\"false\" />\n    </PreferenceCategory>\n    <PreferenceCategory\n        android:title=\"Lead/Opportunity\"\n        android:key=\"crm_lead_settings\">\n        <Preference\n            android:key=\"lead_work_day_start_time\"\n            android:title=\"Day start time\"\n            android:summary=\"Set your working day start time\" />\n    </PreferenceCategory>\n    <!--<PreferenceCategory-->\n    <!--android:title=\"Phone calls\"-->\n    <!--android:key=\"crm_phonecalls_settings\">-->\n    <!--<SwitchPreference-->\n    <!--android:key=\"phonecall_allow_caller_window\"-->\n    <!--android:title=\"Show caller window\"-->\n    <!--android:summary=\"Allow application to show caller window with customer opportunity\"-->\n    <!--android:summaryOff=\"Enable to show latest opportunity detail of caller customer\"-->\n    <!--android:defaultValue=\"true\" />-->\n    <!--</PreferenceCategory>-->\n\n    <PreferenceCategory\n        android:key=\"application_about\"\n        android:title=\"@string/title_about\">\n        <Preference\n            android:icon=\"@drawable/ic_odoo_o\"\n            android:title=\"@string/summary_about_odoo_mobile\">\n            <intent android:action=\"com.odoo.ACTION_ABOUT\" />\n        </Preference>\n    </PreferenceCategory>\n\n</PreferenceScreen>"
  },
  {
    "path": "app/src/main/res/xml/calendar_sync_adapter.xml",
    "content": "<sync-adapter xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:accountType=\"com.odoo.auth\"\n    android:contentAuthority=\"com.odoo.core.crm.provider.content.sync.calendar_event\"\n    android:supportsUploading=\"true\"\n    android:userVisible=\"true\" />\n"
  },
  {
    "path": "app/src/main/res/xml/crm_sync_adapter.xml",
    "content": "<sync-adapter xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:accountType=\"com.odoo.auth\"\n    android:contentAuthority=\"com.odoo.core.crm.provider.content.sync.crm_lead\"\n    android:supportsUploading=\"true\"\n    android:userVisible=\"true\" />\n"
  },
  {
    "path": "app/src/main/res/xml/customer_sync_adapter.xml",
    "content": "<sync-adapter xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:accountType=\"com.odoo.auth\"\n    android:contentAuthority=\"com.odoo.core.crm.provider.content.sync.res_partner\"\n    android:supportsUploading=\"true\"\n    android:userVisible=\"true\" />\n"
  },
  {
    "path": "app/src/main/res/xml/phonecall_sync_adapter.xml",
    "content": "<sync-adapter xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:accountType=\"com.odoo.auth\"\n    android:contentAuthority=\"com.odoo.core.crm.provider.content.sync.crm_phonecall\"\n    android:supportsUploading=\"true\"\n    android:userVisible=\"true\" />\n"
  },
  {
    "path": "app/src/main/res/xml/sale_sync_adapter.xml",
    "content": "<sync-adapter xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:accountType=\"com.odoo.auth\"\n    android:contentAuthority=\"com.odoo.core.crm.provider.content.sync.sale_order\"\n    android:supportsUploading=\"true\"\n    android:userVisible=\"true\" />\n"
  },
  {
    "path": "bottom-sheet-lib/bottom-sheet-lib.iml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<module external.linked.project.id=\":bottom-sheet-lib\" external.linked.project.path=\"$MODULE_DIR$\" external.root.project.path=\"$MODULE_DIR$/..\" external.system.id=\"GRADLE\" external.system.module.group=\"master-crm\" external.system.module.version=\"unspecified\" type=\"JAVA_MODULE\" version=\"4\">\n  <component name=\"FacetManager\">\n    <facet type=\"android-gradle\" name=\"Android-Gradle\">\n      <configuration>\n        <option name=\"GRADLE_PROJECT_PATH\" value=\":bottom-sheet-lib\" />\n      </configuration>\n    </facet>\n    <facet type=\"java-gradle\" name=\"Java-Gradle\">\n      <configuration>\n        <option name=\"BUILD_FOLDER_PATH\" value=\"$MODULE_DIR$/build\" />\n        <option name=\"BUILDABLE\" value=\"false\" />\n      </configuration>\n    </facet>\n  </component>\n  <component name=\"NewModuleRootManager\" inherit-compiler-output=\"true\">\n    <exclude-output />\n    <content url=\"file://$MODULE_DIR$\">\n      <excludeFolder url=\"file://$MODULE_DIR$/.gradle\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build\" />\n    </content>\n    <orderEntry type=\"inheritedJdk\" />\n    <orderEntry type=\"sourceFolder\" forTests=\"false\" />\n  </component>\n</module>"
  },
  {
    "path": "bottom-sheet-lib/build.gradle",
    "content": "configurations.create(\"default\")\nartifacts.add(\"default\", file('bottom-sheet-lib.aar'))"
  },
  {
    "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:1.0.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        jcenter()\n    }\n}\n"
  },
  {
    "path": "calendar-lib/build.gradle",
    "content": "configurations.create(\"default\")\nartifacts.add(\"default\", file('calendar-lib.aar'))"
  },
  {
    "path": "calendar-lib/calendar-lib.iml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<module external.linked.project.id=\":calendar-lib\" external.linked.project.path=\"$MODULE_DIR$\" external.root.project.path=\"$MODULE_DIR$/..\" external.system.id=\"GRADLE\" external.system.module.group=\"master-crm\" external.system.module.version=\"unspecified\" type=\"JAVA_MODULE\" version=\"4\">\n  <component name=\"FacetManager\">\n    <facet type=\"android-gradle\" name=\"Android-Gradle\">\n      <configuration>\n        <option name=\"GRADLE_PROJECT_PATH\" value=\":calendar-lib\" />\n      </configuration>\n    </facet>\n    <facet type=\"java-gradle\" name=\"Java-Gradle\">\n      <configuration>\n        <option name=\"BUILD_FOLDER_PATH\" value=\"$MODULE_DIR$/build\" />\n        <option name=\"BUILDABLE\" value=\"false\" />\n      </configuration>\n    </facet>\n  </component>\n  <component name=\"NewModuleRootManager\" inherit-compiler-output=\"true\">\n    <exclude-output />\n    <content url=\"file://$MODULE_DIR$\">\n      <excludeFolder url=\"file://$MODULE_DIR$/.gradle\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build\" />\n    </content>\n    <orderEntry type=\"inheritedJdk\" />\n    <orderEntry type=\"sourceFolder\" forTests=\"false\" />\n  </component>\n</module>"
  },
  {
    "path": "gradle/wrapper/gradle-wrapper.properties",
    "content": "#Wed Apr 10 15:27:10 PDT 2013\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-2.2.1-all.zip\n"
  },
  {
    "path": "gradle.properties",
    "content": "# Project-wide Gradle settings.\n\n# IDE (e.g. Android Studio) users:\n# Gradle settings configured through the IDE *will override*\n# any settings specified in this file.\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\n# org.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"
  },
  {
    "path": "gradlew",
    "content": "#!/usr/bin/env bash\n\n##############################################################################\n##\n##  Gradle start up script for UN*X\n##\n##############################################################################\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\nAPP_NAME=\"Gradle\"\nAPP_BASE_NAME=`basename \"$0\"`\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\ncase \"`uname`\" in\n  CYGWIN* )\n    cygwin=true\n    ;;\n  Darwin* )\n    darwin=true\n    ;;\n  MINGW* )\n    msys=true\n    ;;\nesac\n\n# For Cygwin, ensure paths are in UNIX format before anything is touched.\nif $cygwin ; then\n    [ -n \"$JAVA_HOME\" ] && JAVA_HOME=`cygpath --unix \"$JAVA_HOME\"`\nfi\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\\\"`/\" >&-\nAPP_HOME=\"`pwd -P`\"\ncd \"$SAVED\" >&-\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\" ] ; 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\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\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\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\nset DIRNAME=%~dp0\r\nif \"%DIRNAME%\" == \"\" set DIRNAME=.\r\nset APP_BASE_NAME=%~n0\r\nset APP_HOME=%DIRNAME%\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 Windowz variants\r\n\r\nif not \"%OS%\" == \"Windows_NT\" goto win9xME_args\r\nif \"%@eval[2+2]\" == \"4\" goto 4NT_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\ngoto execute\r\n\r\n:4NT_args\r\n@rem Get arguments from the 4NT Shell from JP Software\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": "intro-slider-lib/app.iml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<module external.linked.project.path=\"$MODULE_DIR$\" external.root.project.path=\"$MODULE_DIR$/..\" external.system.id=\"GRADLE\" type=\"JAVA_MODULE\" version=\"4\">\n  <component name=\"FacetManager\">\n    <facet type=\"android-gradle\" name=\"Android-Gradle\">\n      <configuration>\n        <option name=\"GRADLE_PROJECT_PATH\" value=\":app\" />\n      </configuration>\n    </facet>\n    <facet type=\"android\" name=\"Android\">\n      <configuration>\n        <option name=\"SELECTED_BUILD_VARIANT\" value=\"debug\" />\n        <option name=\"ASSEMBLE_TASK_NAME\" value=\"assembleDebug\" />\n        <option name=\"COMPILE_JAVA_TASK_NAME\" value=\"compileDebugSources\" />\n        <option name=\"ASSEMBLE_TEST_TASK_NAME\" value=\"assembleDebugTest\" />\n        <option name=\"SOURCE_GEN_TASK_NAME\" value=\"generateDebugSources\" />\n        <option name=\"TEST_SOURCE_GEN_TASK_NAME\" value=\"generateDebugTestSources\" />\n        <option name=\"ALLOW_USER_CONFIGURATION\" value=\"false\" />\n        <option name=\"MANIFEST_FILE_RELATIVE_PATH\" value=\"/src/main/AndroidManifest.xml\" />\n        <option name=\"RES_FOLDER_RELATIVE_PATH\" value=\"/src/main/res\" />\n        <option name=\"RES_FOLDERS_RELATIVE_PATH\" value=\"file://$MODULE_DIR$/src/main/res\" />\n        <option name=\"ASSETS_FOLDER_RELATIVE_PATH\" value=\"/src/main/assets\" />\n        <option name=\"LIBRARY_PROJECT\" value=\"true\" />\n      </configuration>\n    </facet>\n  </component>\n  <component name=\"NewModuleRootManager\" inherit-compiler-output=\"false\">\n    <output url=\"file://$MODULE_DIR$/build/intermediates/classes/debug\" />\n    <exclude-output />\n    <content url=\"file://$MODULE_DIR$\">\n      <sourceFolder url=\"file://$MODULE_DIR$/build/generated/source/r/debug\" isTestSource=\"false\" generated=\"true\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/build/generated/source/aidl/debug\" isTestSource=\"false\" generated=\"true\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/build/generated/source/buildConfig/debug\" isTestSource=\"false\" generated=\"true\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/build/generated/source/rs/debug\" isTestSource=\"false\" generated=\"true\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/build/generated/res/rs/debug\" type=\"java-resource\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/build/generated/res/generated/debug\" type=\"java-resource\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/build/generated/source/r/test/debug\" isTestSource=\"true\" generated=\"true\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/build/generated/source/aidl/test/debug\" isTestSource=\"true\" generated=\"true\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/build/generated/source/buildConfig/test/debug\" isTestSource=\"true\" generated=\"true\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/build/generated/source/rs/test/debug\" isTestSource=\"true\" generated=\"true\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/build/generated/res/rs/test/debug\" type=\"java-test-resource\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/build/generated/res/generated/test/debug\" type=\"java-test-resource\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/debug/res\" type=\"java-resource\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/debug/resources\" type=\"java-resource\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/debug/assets\" type=\"java-resource\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/debug/aidl\" isTestSource=\"false\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/debug/java\" isTestSource=\"false\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/debug/jni\" isTestSource=\"false\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/debug/rs\" isTestSource=\"false\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/main/res\" type=\"java-resource\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/main/resources\" type=\"java-resource\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/main/assets\" type=\"java-resource\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/main/aidl\" isTestSource=\"false\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/main/java\" isTestSource=\"false\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/main/jni\" isTestSource=\"false\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/main/rs\" isTestSource=\"false\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/androidTest/res\" type=\"java-test-resource\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/androidTest/resources\" type=\"java-test-resource\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/androidTest/assets\" type=\"java-test-resource\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/androidTest/aidl\" isTestSource=\"true\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/androidTest/java\" isTestSource=\"true\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/androidTest/jni\" isTestSource=\"true\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/androidTest/rs\" isTestSource=\"true\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/assets\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/bundles\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/classes\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/coverage-instrumented-classes\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/dependency-cache\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/dex\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/dex-cache\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/incremental\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/jacoco\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/javaResources\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/libs\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/lint\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/manifests\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/ndk\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/pre-dexed\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/proguard\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/res\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/rs\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/symbols\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/outputs\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/tmp\" />\n    </content>\n    <orderEntry type=\"jdk\" jdkName=\"Android API 21 Platform\" jdkType=\"Android SDK\" />\n    <orderEntry type=\"sourceFolder\" forTests=\"false\" />\n    <orderEntry type=\"library\" exported=\"\" name=\"support-annotations-21.0.3\" level=\"project\" />\n    <orderEntry type=\"library\" exported=\"\" name=\"support-v4-21.0.3\" level=\"project\" />\n  </component>\n</module>\n\n"
  },
  {
    "path": "intro-slider-lib/build.gradle",
    "content": "apply plugin: 'com.android.library'\n\nandroid {\n    compileSdkVersion 21\n    buildToolsVersion \"21.1.2\"\n\n    defaultConfig {\n        minSdkVersion 8\n        targetSdkVersion 21\n    }\n\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'\n        }\n    }\n}\n\ndependencies {\n    compile 'com.android.support:support-v4:21.0.3'\n}\n"
  },
  {
    "path": "intro-slider-lib/src/main/AndroidManifest.xml",
    "content": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.odoo.widgets.slider\"\n    android:versionCode=\"1\"\n    android:versionName=\"1.0\" >\n\n    <uses-sdk\n        android:minSdkVersion=\"8\"\n        android:targetSdkVersion=\"21\" />\n\n    <application\n        android:allowBackup=\"true\"\n        android:icon=\"@drawable/ic_launcher\"\n        android:label=\"@string/app_name\"\n        android:theme=\"@style/AppTheme\" >\n    </application>\n\n</manifest>\n"
  },
  {
    "path": "intro-slider-lib/src/main/java/com/odoo/widget/slider/navigator/PagerNavigatorAdapter.java",
    "content": "package com.odoo.widget.slider.navigator;\n\nimport android.annotation.SuppressLint;\nimport android.content.Context;\nimport android.graphics.drawable.GradientDrawable;\nimport android.os.Handler;\nimport android.view.View;\nimport android.widget.LinearLayout;\n\nimport com.odoo.widgets.slider.R;\nimport com.odoo.widgets.slider.R.color;\n\npublic class PagerNavigatorAdapter {\n\n\tprivate Context mContext = null;\n\tprivate LinearLayout mParent;\n\n\tpublic PagerNavigatorAdapter(Context context) {\n\t\tsuper();\n\t\tmContext = context;\n\t}\n\n\tpublic void navigator(int totalCount, View container) {\n\t\tmParent = (LinearLayout) container;\n\t\tpageNavigationDots(totalCount);\n\t}\n\n\tprivate void pageNavigationDots(int totalPage) {\n\t\twhile (totalPage > 0) {\n\t\t\tView v = new View(mContext);\n\t\t\tLinearLayout.LayoutParams params = new LinearLayout.LayoutParams(\n\t\t\t\t\tgetHeightWidth(false), getHeightWidth(false));\n\t\t\tv.setLayoutParams(params);\n\t\t\tmParent.addView(v);\n\t\t\ttotalPage--;\n\t\t}\n\t\tnew Handler().postDelayed(new Runnable() {\n\t\t\t@Override\n\t\t\tpublic void run() {\n\t\t\t\tfocusOnPagerDot(0);\n\t\t\t}\n\t\t}, 500);\n\t}\n\n\t@SuppressLint(\"NewApi\")\n\tpublic void focusOnPagerDot(int position) {\n\t\tfor (int i = 0; i < mParent.getChildCount(); i++) {\n\t\t\tGradientDrawable shapeBg = (GradientDrawable) mContext\n\t\t\t\t\t.getResources().getDrawable(R.drawable.intro_slider_dot_bg);\n\t\t\tView child = mParent.getChildAt(i);\n\t\t\tLinearLayout.LayoutParams params;\n\t\t\tif (i == position) {\n\t\t\t\tparams = new LinearLayout.LayoutParams(getHeightWidth(true),\n\t\t\t\t\t\tgetHeightWidth(true));\n\t\t\t\tshapeBg.setColor(mContext.getResources().getColor(\n\t\t\t\t\t\tcolor.theme_primary));\n\t\t\t} else {\n\t\t\t\tparams = new LinearLayout.LayoutParams(getHeightWidth(false),\n\t\t\t\t\t\tgetHeightWidth(false));\n\t\t\t\tshapeBg.setColor(mContext.getResources().getColor(\n\t\t\t\t\t\tcolor.theme_primary_trans));\n\t\t\t}\n\t\t\tparams.setMargins(getLeftRightMargin(), getTopBottomMargin(),\n\t\t\t\t\tgetLeftRightMargin(), getTopBottomMargin());\n\t\t\tchild.setLayoutParams(params);\n\t\t\tchild.setBackground(shapeBg);\n\t\t\tchild.invalidate();\n\t\t}\n\t}\n\n\tprivate int getHeightWidth(boolean focused) {\n\t\tif (focused)\n\t\t\treturn (int) mContext.getResources().getDimension(\n\t\t\t\t\tR.dimen.dot_focused_height_width);\n\t\telse\n\t\t\treturn (int) mContext.getResources().getDimension(\n\t\t\t\t\tR.dimen.dot_normal_height_width);\n\t}\n\n\tprivate int getTopBottomMargin() {\n\t\treturn (int) mContext.getResources().getDimension(\n\t\t\t\tR.dimen.dot_top_bottom_margin);\n\t}\n\n\tprivate int getLeftRightMargin() {\n\t\treturn (int) mContext.getResources().getDimension(\n\t\t\t\tR.dimen.dot_left_right_margin);\n\t}\n}\n"
  },
  {
    "path": "intro-slider-lib/src/main/java/com/odoo/widgets/slider/SliderHelper.java",
    "content": "package com.odoo.widgets.slider;\n\nimport android.content.Context;\nimport android.support.v4.app.FragmentManager;\nimport android.support.v4.view.ViewPager;\nimport android.util.AttributeSet;\nimport android.view.View;\nimport android.view.ViewGroup;\n\nimport com.odoo.widget.slider.navigator.PagerNavigatorAdapter;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class SliderHelper extends ViewPager {\n\n    private Context mContext;\n    private List<SliderItem> mItems = new ArrayList<SliderItem>();\n    private SliderPagerAdapter mPagerAdapter = null;\n    private PagerNavigatorAdapter mPagerNavigatorAdapter;\n\n    public SliderHelper(Context context) {\n        super(context);\n        mContext = context;\n        _init(context);\n    }\n\n    public SliderHelper(Context context, AttributeSet attrs) {\n        super(context, attrs);\n        _init(context);\n    }\n\n    private void _init(Context context) {\n        mContext = context;\n        mPagerNavigatorAdapter = new PagerNavigatorAdapter(mContext);\n    }\n\n    public void init(FragmentManager fragmentManager, List<SliderItem> items) {\n        mItems.clear();\n        mItems.addAll(items);\n        mPagerAdapter = new SliderPagerAdapter(mContext, fragmentManager);\n        mPagerAdapter.initPager(mContext, items);\n        setAdapter(mPagerAdapter);\n\n        setOnPageChangeListener(mPageChangeListener);\n\n        setPageTransformer(true, new ZoomOutPageTransformer() );\n    }\n\n    OnPageChangeListener mPageChangeListener = new OnPageChangeListener() {\n\n        @Override\n        public void onPageSelected(int position) {\n            mPagerNavigatorAdapter.focusOnPagerDot(position);\n        }\n\n        @Override\n        public void onPageScrolled(int arg0, float arg1, int arg2) {\n\n        }\n\n        @Override\n        public void onPageScrollStateChanged(int arg0) {\n\n        }\n    };\n\n    public void initNavigator(ViewGroup parent) {\n        mPagerNavigatorAdapter.navigator(mPagerAdapter.getCount(), parent);\n    }\n\n    public class ZoomOutPageTransformer implements ViewPager.PageTransformer {\n        private static final float MIN_SCALE = 0.85f;\n        private static final float MIN_ALPHA = 0.5f;\n\n        public void transformPage(View view, float position) {\n            int pageWidth = view.getWidth();\n            int pageHeight = view.getHeight();\n\n            if (position < -1) { // [-Infinity,-1)\n                // This page is way off-screen to the left.\n                view.setAlpha(0);\n\n            } else if (position <= 1) { // [-1,1]\n                // Modify the default slide transition to shrink the page as well\n                float scaleFactor = Math.max(MIN_SCALE, 1 - Math.abs(position));\n                float vertMargin = pageHeight * (1 - scaleFactor) / 2;\n                float horzMargin = pageWidth * (1 - scaleFactor) / 2;\n                if (position < 0) {\n                    view.setTranslationX(horzMargin - vertMargin / 2);\n                } else {\n                    view.setTranslationX(-horzMargin + vertMargin / 2);\n                }\n\n                // Scale the page down (between MIN_SCALE and 1)\n                view.setScaleX(scaleFactor);\n                view.setScaleY(scaleFactor);\n\n                // Fade the page relative to its size.\n                view.setAlpha(MIN_ALPHA +\n                        (scaleFactor - MIN_SCALE) /\n                                (1 - MIN_SCALE) * (1 - MIN_ALPHA));\n\n            } else { // (1,+Infinity]\n                // This page is way off-screen to the right.\n                view.setAlpha(0);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "intro-slider-lib/src/main/java/com/odoo/widgets/slider/SliderItem.java",
    "content": "package com.odoo.widgets.slider;\n\nimport com.odoo.widgets.slider.SliderPagerAdapter.SliderBuilderListener;\n\nimport java.util.HashMap;\n\npublic class SliderItem {\n\n    private String content = null;\n    private String title = null;\n    private int image = 0;\n    private SliderBuilderListener mSliderBuilderListener = null;\n    private HashMap<String, Object> extras = new HashMap<>();\n\n    public SliderItem(String title, String content, int image,\n                      SliderBuilderListener listener) {\n        super();\n        this.content = content;\n        this.title = title;\n        this.image = image;\n        mSliderBuilderListener = listener;\n    }\n\n    public SliderItem putExtra(String key, Object value) {\n        extras.put(key, value);\n        return this;\n    }\n\n    public SliderItem setExtras(HashMap<String, Object> extras) {\n        this.extras = extras;\n        return this;\n    }\n\n    public HashMap<String, Object> getExtras() {\n        return extras;\n    }\n\n    public String getContent() {\n        return content;\n    }\n\n    public void setContent(String mContent) {\n        this.content = mContent;\n    }\n\n    public String getTitle() {\n        return title;\n    }\n\n    public void setTitle(String mTitle) {\n        this.title = mTitle;\n    }\n\n    public int getImagePath() {\n        return image;\n    }\n\n    public void setImagePath(int image) {\n        this.image = image;\n    }\n\n    public void setSliderCustomViewListener(SliderBuilderListener listener) {\n        mSliderBuilderListener = listener;\n    }\n\n    public SliderBuilderListener getSliderCustomViewListener() {\n        return mSliderBuilderListener;\n    }\n}\n"
  },
  {
    "path": "intro-slider-lib/src/main/java/com/odoo/widgets/slider/SliderPagerAdapter.java",
    "content": "package com.odoo.widgets.slider;\n\nimport android.content.Context;\nimport android.os.Bundle;\nimport android.support.annotation.Nullable;\nimport android.support.v4.app.Fragment;\nimport android.support.v4.app.FragmentManager;\nimport android.support.v4.app.FragmentStatePagerAdapter;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.ImageView;\nimport android.widget.LinearLayout;\nimport android.widget.TextView;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class SliderPagerAdapter extends FragmentStatePagerAdapter {\n\n    public static final String KEY_POSITION = \"key_pos\";\n    Context mContext = null;\n    List<SliderItem> mItems = new ArrayList<SliderItem>();\n\n    public SliderPagerAdapter(Context context, FragmentManager fm) {\n        super(fm);\n    }\n\n    @Override\n    public Fragment getItem(int position) {\n        PageFragment frag = new PageFragment();\n        Bundle bundle = new Bundle();\n        bundle.putInt(KEY_POSITION, position);\n        frag.setArguments(bundle);\n        return frag;\n\n    }\n\n    public void initPager(Context context, List<SliderItem> items) {\n        mContext = context;\n        mItems.clear();\n        mItems.addAll(items);\n        notifyDataSetChanged();\n    }\n\n    @Override\n    public int getCount() {\n        return mItems.size();\n    }\n\n    class PageFragment extends Fragment {\n        @Override\n        public View onCreateView(LayoutInflater inflater,\n                                 @Nullable ViewGroup container,\n                                 @Nullable Bundle savedInstanceState) {\n            View layout = null;\n            int pos = getPosition();\n            SliderItem item = mItems.get(pos);\n            if (item.getSliderCustomViewListener() != null) {\n                layout = item.getSliderCustomViewListener().getCustomView(\n                        mContext, item, container);\n            } else {\n                layout = (LinearLayout) inflater.inflate(R.layout.default_ui,\n                        container, false);\n            }\n            return layout;\n        }\n\n        @Override\n        public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {\n            int pos = getPosition();\n            SliderItem item = mItems.get(pos);\n            if (item.getSliderCustomViewListener() == null) {\n                ImageView imgPic = (ImageView) view\n                        .findViewById(R.id.view_image);\n                TextView txvTitle, txvContent;\n                txvTitle = (TextView) view.findViewById(R.id.view_title);\n                txvContent = (TextView) view.findViewById(R.id.view_content);\n                imgPic.setImageResource(item.getImagePath());\n                txvTitle.setText(item.getTitle());\n                txvContent.setText(item.getContent());\n            }\n        }\n\n        private int getPosition() {\n            return getArguments().getInt(KEY_POSITION);\n        }\n\n    }\n\n    public interface SliderBuilderListener {\n        public View getCustomView(Context context, SliderItem item,\n                                  ViewGroup parent);\n    }\n\n}\n"
  },
  {
    "path": "intro-slider-lib/src/main/java/com/odoo/widgets/slider/SliderView.java",
    "content": "package com.odoo.widgets.slider;\n\nimport java.util.List;\n\nimport android.annotation.SuppressLint;\nimport android.content.Context;\nimport android.support.v4.app.FragmentManager;\nimport android.util.AttributeSet;\nimport android.view.LayoutInflater;\nimport android.view.ViewGroup;\nimport android.widget.LinearLayout;\n\nimport com.odoo.widgets.slider.R;\n\npublic class SliderView extends LinearLayout {\n\n\tprivate Context mContext;\n\tprivate SliderHelper mSlider;\n\n\t@SuppressLint(\"NewApi\")\n\tpublic SliderView(Context context, AttributeSet attrs, int defStyleAttr,\n\t\t\tint defStyleRes) {\n\t\tsuper(context, attrs, defStyleAttr, defStyleRes);\n\t\tinit(context);\n\t}\n\n\t@SuppressLint(\"NewApi\")\n\tpublic SliderView(Context context, AttributeSet attrs, int defStyleAttr) {\n\t\tsuper(context, attrs, defStyleAttr);\n\t\tinit(context);\n\t}\n\n\tpublic SliderView(Context context, AttributeSet attrs) {\n\t\tsuper(context, attrs);\n\t\tinit(context);\n\t}\n\n\tpublic SliderView(Context context) {\n\t\tsuper(context);\n\t\tinit(context);\n\t}\n\n\tprivate void init(Context context) {\n\t\tmContext = context;\n\t\tsetOrientation(LinearLayout.VERTICAL);\n\t\taddView(LayoutInflater.from(mContext).inflate(\n\t\t\t\tR.layout.slider_default_view, this, false));\n\t}\n\n\tpublic void setItems(FragmentManager fragmentManager, List<SliderItem> items) {\n\t\tmSlider = (SliderHelper) findViewById(R.id.default_view_helper);\n\t\tmSlider.init(fragmentManager, items);\n\t\tmSlider.initNavigator((ViewGroup) findViewById(R.id.footer_dot));\n\t}\n\n}\n"
  },
  {
    "path": "intro-slider-lib/src/main/res/drawable/intro_slider_dot_bg.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\r\n    android:shape=\"oval\" >\r\n\r\n</shape>"
  },
  {
    "path": "intro-slider-lib/src/main/res/layout/default_ui.xml",
    "content": "<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:background=\"#7e8a9e\"\n    android:orientation=\"vertical\" >\n\n    <ImageView\n        android:id=\"@+id/view_image\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"center_horizontal\"\n        android:src=\"@drawable/device_frame\" />\n\n    <LinearLayout\n        android:id=\"@+id/bg_color_view\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"0dp\"\n        android:layout_weight=\"1\"\n        android:orientation=\"vertical\"\n        android:padding=\"2dp\" >\n\n        <TextView\n            android:id=\"@+id/view_title\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:background=\"#0099cc\"\n            android:fontFamily=\"sans-serif-light\"\n            android:gravity=\"center\"\n            android:padding=\"10dp\"\n            android:textAppearance=\"?android:attr/textAppearanceLarge\"\n            android:textColor=\"#ffffff\"\n            android:textStyle=\"bold\" />\n\n        <TextView\n            android:id=\"@+id/view_content\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"0dp\"\n            android:layout_weight=\"1\"\n            android:gravity=\"center\"\n            android:background=\"#99cc00\"\n            android:textAppearance=\"?android:attr/textAppearanceMedium\"\n            android:textColor=\"#ffffff\" />\n    </LinearLayout>\n\n</LinearLayout>"
  },
  {
    "path": "intro-slider-lib/src/main/res/layout/slider_default_view.xml",
    "content": "<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <com.odoo.widgets.slider.SliderHelper\n        android:id=\"@+id/default_view_helper\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\" />\n\n    <LinearLayout\n        android:id=\"@+id/footer_dot\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_alignParentBottom=\"true\"\n        android:layout_gravity=\"bottom\"\n        android:gravity=\"center\"\n        android:orientation=\"horizontal\"\n        android:padding=\"16dp\"></LinearLayout>\n\n</RelativeLayout>"
  },
  {
    "path": "intro-slider-lib/src/main/res/values/colors.xml",
    "content": "<resources>\n\n    <color name=\"theme_primary\">#a24689</color>\n    <color name=\"theme_primary_trans\">#55414141</color>\n</resources>\n"
  },
  {
    "path": "intro-slider-lib/src/main/res/values/dimens.xml",
    "content": "<resources>\n\n    <!-- Default screen margins, per the Android Design guidelines. -->\n    <dimen name=\"activity_horizontal_margin\">16dp</dimen>\n    <dimen name=\"activity_vertical_margin\">16dp</dimen>\n    <dimen name=\"dot_normal_height_width\">8dp</dimen>\n    <dimen name=\"dot_focused_height_width\">8dp</dimen>\n    <dimen name=\"dot_top_bottom_margin\">5dp</dimen>\n    <dimen name=\"dot_left_right_margin\">5dp</dimen>\n\n</resources>"
  },
  {
    "path": "intro-slider-lib/src/main/res/values/strings.xml",
    "content": "<resources>\n\n    <string name=\"app_name\">OdooWidgets</string>\n\n</resources>\n"
  },
  {
    "path": "intro-slider-lib/src/main/res/values/styles.xml",
    "content": "<resources>\n\n    <!--\n        Base application theme, dependent on API level. This theme is replaced\n        by AppBaseTheme from res/values-vXX/styles.xml on newer devices.\n    -->\n    <style name=\"AppBaseTheme\" parent=\"android:Theme.Light\">\n        <!--\n            Theme customizations available in newer API levels can go in\n            res/values-vXX/styles.xml, while customizations related to\n            backward-compatibility can go here.\n        -->\n    </style>\n\n    <!-- Application theme. -->\n    <style name=\"AppTheme\" parent=\"AppBaseTheme\">\n        <!-- All customizations that are NOT specific to a particular API-level can go here. -->\n    </style>\n\n</resources>\n"
  },
  {
    "path": "intro-slider-lib/src/main/res/values-v11/styles.xml",
    "content": "<resources>\n\n    <!--\n        Base application theme for API 11+. This theme completely replaces\n        AppBaseTheme from res/values/styles.xml on API 11+ devices.\n    -->\n    <style name=\"AppBaseTheme\" parent=\"android:Theme.Holo.Light\">\n        <!-- API 11 theme customizations can go here. -->\n    </style>\n\n</resources>\n"
  },
  {
    "path": "intro-slider-lib/src/main/res/values-v14/styles.xml",
    "content": "<resources>\n\n    <!--\n        Base application theme for API 14+. This theme completely replaces\n        AppBaseTheme from BOTH res/values/styles.xml and\n        res/values-v11/styles.xml on API 14+ devices.\n    -->\n    <style name=\"AppBaseTheme\" parent=\"android:Theme.Holo.Light.DarkActionBar\">\n        <!-- API 14 theme customizations can go here. -->\n    </style>\n\n</resources>\n"
  },
  {
    "path": "local.properties",
    "content": "## This file is automatically generated by Android Studio.\n# Do not modify this file -- YOUR CHANGES WILL BE ERASED!\n#\n# This file must *NOT* be checked into Version Control Systems,\n# as it contains information specific to your local configuration.\n#\n# Location of the SDK. This is only used by Gradle.\n# For customization when using a Version Control System, please read the\n# header note.\n#Fri Apr 10 15:32:08 IST 2015\nsdk.dir=/home/dpr/eclipse-adt/sdk\n"
  },
  {
    "path": "master-crm-studio-dpr.iml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<module external.linked.project.path=\"$MODULE_DIR$\" external.root.project.path=\"$MODULE_DIR$\" external.system.id=\"GRADLE\" external.system.module.group=\"\" external.system.module.version=\"unspecified\" type=\"JAVA_MODULE\" version=\"4\">\n  <component name=\"FacetManager\">\n    <facet type=\"java-gradle\" name=\"Java-Gradle\">\n      <configuration>\n        <option name=\"BUILD_FOLDER_PATH\" value=\"$MODULE_DIR$/build\" />\n      </configuration>\n    </facet>\n  </component>\n  <component name=\"NewModuleRootManager\" inherit-compiler-output=\"true\">\n    <exclude-output />\n    <content url=\"file://$MODULE_DIR$\">\n      <excludeFolder url=\"file://$MODULE_DIR$/.gradle\" />\n    </content>\n    <orderEntry type=\"inheritedJdk\" />\n    <orderEntry type=\"sourceFolder\" forTests=\"false\" />\n  </component>\n</module>\n\n"
  },
  {
    "path": "odoo-rpc-v2/build.gradle",
    "content": "configurations.create(\"default\")\nartifacts.add(\"default\", file('odoo-rpc-v2.aar'))"
  },
  {
    "path": "parallax-effect-lib/build.gradle",
    "content": "configurations.create(\"default\")\nartifacts.add(\"default\", file('parallax-effect-lib.aar'))"
  },
  {
    "path": "settings.gradle",
    "content": "include ':app', ':calendar-lib', ':bottom-sheet-lib', ':snackbar-lib', ':parallax-effect-lib', ':intro-slider-lib', ':odoo-rpc-v2'\n"
  },
  {
    "path": "snackbar-lib/build.gradle",
    "content": "configurations.create(\"default\")\nartifacts.add(\"default\", file('snackbar-lib.aar'))"
  },
  {
    "path": "snackbar-lib/snackbar-lib.iml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<module external.linked.project.id=\":snackbar-lib\" external.linked.project.path=\"$MODULE_DIR$\" external.root.project.path=\"$MODULE_DIR$/..\" external.system.id=\"GRADLE\" external.system.module.group=\"master-crm\" external.system.module.version=\"unspecified\" type=\"JAVA_MODULE\" version=\"4\">\n  <component name=\"FacetManager\">\n    <facet type=\"android-gradle\" name=\"Android-Gradle\">\n      <configuration>\n        <option name=\"GRADLE_PROJECT_PATH\" value=\":snackbar-lib\" />\n      </configuration>\n    </facet>\n    <facet type=\"java-gradle\" name=\"Java-Gradle\">\n      <configuration>\n        <option name=\"BUILD_FOLDER_PATH\" value=\"$MODULE_DIR$/build\" />\n        <option name=\"BUILDABLE\" value=\"false\" />\n      </configuration>\n    </facet>\n  </component>\n  <component name=\"NewModuleRootManager\" inherit-compiler-output=\"true\">\n    <exclude-output />\n    <content url=\"file://$MODULE_DIR$\">\n      <excludeFolder url=\"file://$MODULE_DIR$/.gradle\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build\" />\n    </content>\n    <orderEntry type=\"inheritedJdk\" />\n    <orderEntry type=\"sourceFolder\" forTests=\"false\" />\n  </component>\n</module>"
  }
]