Odoo Mobile
Odoo Mobile
Odoo Mobile
Release 2.0alpha
Dharmang Soni
Contents
Contents:
1.1 About Framework . . . . . . .
1.2 Setting up IDE . . . . . . . . .
1.3 Getting Started with Framework
1.4 Contributing . . . . . . . . . .
Indices and tables
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
1
1
1
3
74
75
ii
CHAPTER 1
Contents:
Chapter 1. Contents:
Here you can find all the repositories developed by Odoo S.A.
Click on Framework
https://github.com/Odoo-mobile/framework
You
can
also
choose
another
repository
source
code
such
as
crm,
notes
Chapter 1. Contents:
Test Framework application build for loading customers, suppliers and companies
After successfully load your project to Android Studio you can run it by pressing Run App button from toolbar.
Chapter 1. Contents:
This framework contains its own ORM to handle mobiles 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.
Here is some of the application build with Odoo Mobile Framework (Also available on PlayStore):
Understanding architecture
Framework Architecture
Chapter 1. Contents:
10
Chapter 1. Contents:
Form
Fields
Boolean
Text
Radio
Checkbox
ManyToOne
Spinner
DateTime
and more...
FAB Button
11
Blue layer contais all your addons model (database table) archicture, business logic for your addon, code behind for
your activities and fragments.
Also, there are loaders for your listviews, works with your model content provider. You can also create your custom
content provider for custom queries and data loading.
Orange Layer Orange layer is repsonsible to get data from odoo server and provide it to framework synchronization
base adapter. Framework will take care for offline data. It will compare your latest updated record and synchronize
them as well update record in local and server. We have tried to give 100% offline support, but in some cases you need
to override synchronization and have to put your own mechanism. Yes, of-course its customizable. :P
Red Layer Red layer contains all the core components used by the frameworks. ORM, Synchronization base
adapters, Base service providers, base content model providers and some utilitity classes. Red layer also responsible to manage application accounts, synchronization settings.
Red layer and Orange layer are dependend part.
Danger: Change in this fiels causes system flow break. Kindly take copy before changes in red layer part.
Framework will create separate database for each of different account. By creating separate database it is possible to
create different database version as per odoo versions.
Directory structure
Directory structure is same as standard android studio android application structure. Framework has organized some
of the packages for faster development and easy understandability of addons (modules).
12
Chapter 1. Contents:
13
All the modules are created under addons package along with module package name as shown in figure.
@See Working with addons
Addons Registry Each addons has its parent view. Such as List of customers, which loaded when user
click on Drawer menu item. We have to register each of the parent class for addon in Addons.java under
com.odoo.config package.
14
Chapter 1. Contents:
Create your feature object with OAddon class named with your feature and provide your feature class (which extends
BaseFragment) as below:
public class Addons extends AddonsHelper {
/**
* Declare your required module here
* NOTE: For maintain sequence use object name in asc order.
* Ex.:
* OAddon partners = new OAddon(Partners.class).setDefault();
*/
OAddon customers = new OAddon(Customers.class).setDefault();
}
If you want to make your addons default to load when application starts. Just add chaining method setDefault()
You can create multiple object as member in this class.
15
Tips: For shorting your features just put alphabetical ordered name to your features.
E.g:
OAddon a_sales = new OAddon(Sale.class).setDefault();
OAddon b_messaging = new OAddon(Messaging.class);
OAddon c_customers = new OAddon(Customer.class);
Note: System automatically create database as you applied in your BaseFragment.java but if some of the model
are not creating automaticallly then you can add thoes models in BaseModels.java
Base models Odoo mobile framework comes with some of base models, such as res.partners, res.users,
mail.message, ir.attachments and more..
16
Chapter 1. Contents:
17
Contains all the base models (database models) used by framework itself.
You can modify it (add or update columns as you required). Default it contains, ir.attachment, ir.model, mail.message
(for chatter), res_* related models such as res_partner, res_users and so on.
You can also add your base model; after adding your model you need to register it in BaseModels.java file.
public class BaseModels {
public static final String TAG = BaseModels.class.getSimpleName();
public static List<OModel> baseModels(Context context, OUser user) {
List<OModel> models = new ArrayList<>();
models.add(new OdooNews(context, user));
models.add(new IrModel(context, user));
models.add(new ResPartner(context, user));
models.add(new ResUsers(context, user));
models.add(new ResCompany(context, user));
models.add(new IrAttachment(context, user));
models.add(new MailMessage(context, user));
return models;
}
}
18
Chapter 1. Contents:
You can integrate mail chatter widget with OForm control by providing setHasChatter(true); in models constructor.
...
public ResPartner(Context context, OUser user) {
super(context, "res.partner", user);
setHasMailChatter(true);
}
...
19
We must have to create one file that extends BaseFragment.java which will be registered in Addons.java
These two methods are used by framework for creating database and drawer menu. Here, <T> indicate your model
class type. We will see it in OModel.java
BaseFragment.java contains some of usefull methods we can used in our fragment. As below:
setTitle() Syntax:
Void setTitle(String title)
Used for setting actionbar title:
setTitle("My Title");
db() Syntax:
OModel db()
Used to get current db object returned in database() method which implemented in our fragment class.
db().select();
OValues values = new OValues();
...
...
db().insert(values);
user() Syntax:
OUser user()
Used to get current active user object. It is easy when you want to do some operation with current user.
user().getName();
user().getPartner_id();
user().getUser_id();
...
20
Chapter 1. Contents:
parent() Syntax:
OdooActivity parent()
Returns parent activity (i.e., getActivity()). It will automatically cast Activity object to OdooActivity
So you can easyliy access public methods of OdooActivity
parent().closeDrawer();
parent().refreshDrawer();
parent().setOnActivityResultListener(callback);
startFragment() Syntax:
Void startFragment(Fragment fragment, boolean addToBackState)
Void startFragment(Fragment fragment, boolean addToBackState, Bundle data)
Used to start another fragment from current fragment. You can also specify backstate when starting another fragment.
startFragment(new MyNewFragment(), true); // Starting fragment with backstate
Bundle data = new Bundle();
...
...
startFragment(new MyNewFragment(), false, data); // Starting new fragment without backstate but with
setHasFloatingButton() Syntax:
void setHasFloatingButton(View view, int viewId, ListView listViewObj,
View.OnClickListener callback)
By default floating button is hidden. You need to activate floating button to use. It will auto add callback method. Also
you need to add ListView object as parameter so when you scroll your listview FAB will automatically hide/visible on
listview scroll.
setHasFloatingButton(view, R.id.fabButton, listViewObj, this);
// this will implement onClick(View v) method
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.fabButton:
// Do your stuff
break;
21
}
}
setHasSearchView() Syntax:
void setHasSearchView(IOnSearchViewChangeListener callback, Menu menu, int
menu_id)
If there is a menu with search option. You can directly set setHasSearchView() and framework will work for
you. It will give you callback on search text changed and search view close.
It takes callback to its first paramenter of IOnSearchViewChangeListener interface which has following methods:
public interface IOnSearchViewChangeListener {
public static final String TAG = IOnSearchViewChangeListener.class.getSimpleName();
public boolean onSearchViewTextChange(String newFilter);
public void onSearchViewClose();
}
To apply search view callback just call method when you create your menu:
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
menu.clear();
inflater.inflate(R.menu.menu_partners, menu);
setHasSearchView(this, menu, R.id.menu_partner_search);
}
22
Chapter 1. Contents:
setHasSwipeRefreshView() Syntax:
void setHasSwipeRefreshView(View parentView, int resourceId,
SwipeRefreshLayout.OnRefreshListener callback)
When using swipe refresh view, you can easyly set its call back by calling setHasSwipeRefreshView
setHasSwipeRefreshView(view, R.id.swipe_container, this);
setHasSyncStatusObserver() Syntax:
void setHasSyncStatusObserver(String menuKEY, ISyncStatusObserverListener
callback, OModel model)
Used when any of your data are synchronizing in background and you need to notify when sync finished or data set
update. By calling this method it is easy to notify on dataset change.
setHasSyncStatusObserver(KEY, this, db());
1. It takes drawer KEY or TAG which passed when creating drawer menu
2. Callback for data set change. Implement onStatusChange() method
3. database object on which you need to set observer
@Override
public void onStatusChange(Boolean changed) {
if(changed){
getLoaderManager().restartLoader(0, null, this); // Updating listview
}
}
23
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.common_listview, container,false);
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
setTitle(_s(R.string.title_messages));
}
@Override
public Class<MailMessage> database() {
return MailMessage.class;
}
@Override
public List<ODrawerItem> drawerMenus(Context context) {
return null;
}
}
Here,
1. label indicate column label. It auto load in form control as control title.
2. type type of datatype. (Basic type + Relation type)
3. relationType [optional] if type is related to another model class
Possible Types
24
Chapter 1. Contents:
OneToMany
ManyToOne
ManyToMany
Some chaining methods
each method returns, OColumn object with updated value.
setName() Syntax:
OColumn setName(String name)
Used to set column name. Generally variable name is considered as column name but if you want to change its name
runtime you can change it.
OColumn dummy_column = new OColumn("Name", OVarchar.class).setName("name");
Danger: Remeber that, You can not change column name after models constructor call finish. If you trying to
change outside of constructor, it will affect your local database.
setRecordSyncLimit() Syntax:
OColumn setRecordSyncLimit(int limit)
Limiting syncing record for OneToMany and ManyToMany.
OColumn tag_ids = new OColumn("Tags", NoteTag.class, RelationType.ManyToMany)
.setRecordSyncLimit(10);
Note: Not all records are synced for OneToMany and ManyToMany if you set record sync limit.
setLabel() Syntax:
OColumn setLabel(String label)
Sets label for column name. Used as title for column.
OColumn name = new OColumn("Dummy Name", OVarchar.class).setLabel("Name");
setRelatedColumn() Syntax:
OColumn setRelatedColumn(String related_column)
Used when you have created OneToMany relation column. OneToMany required related column to maintain
relation.
OColumn child_ids = new OColumn("Contacts", ResPartner.class, RelationType.OneToMany)
.setRelatedColumn("parent_id");
setSize() Syntax:
OColumn setSize(int size)
Used to set column size. Takes integer value.
25
setDefaultValue() Syntax:
OColumn setDefaultValue(Object value)
Sets default value for column. Will store into database if user not pass value for column
OColumn published = new OColumn("Published", OBoolean.class).setDefaultValue(false);
setRequired() Syntax:
OColumn setRequired()
Sets column value required. OForm will automatically show validation error if column is required.
OColumn name = new OColumn("Name", OVarchar.class).setRequired();
setLocalColumn() Syntax:
OColumn setLocalColumn()
Sometime you need some local column that will not available on server. You can make any column local only.
OColumn total_amount = new OColumn("Total Amount", OInteger.class).setLocalColumn();
setType() Syntax:
OColumn setType(Class<?> type)
Sets data type for column. You can change data type for column as runtime but only in constructor. In some cases,
such as different type for different odoo version.
OColumn date = new OColumn("Date", ODate.class);
public ResPartner(Context context, OUser user) {
super(context, "crm.lead", user);
if(getOdooVersion().getVersion_number() > 7){
date.setType(ODateTime.class);
}
}
addDomain() Adds default filter domain for column. Basically you need ManyToOne column to be filter on
some conditions.
Syntax:
addDomain(String column_name, String operator, Object value);
addDomain(String conditional_operator);
Example:
OColumn parent_id = new OColumn("Related Company", ResPartner.class, RelationType.ManyToOne)
.addDomain("is_company","=",true);
26
Chapter 1. Contents:
addSelection() Syntax:
OColumn addSelection(String key, String value)
Used to add key value selection pair. Used with OSelection data type.
OColumn state = new OColumn("State", OSelection.class)
.addSelection("draft","Draft")
.addSelection("confirm","Confirmed")
.addSelection("close","Canceled")
.addSelection("done","Done");
Column annotations
@Odoo.api.v7, @Odoo.api.v8 and @Odoo.api.v9alpha api annotations are used when your column
name is different in odoo versions. Or may be it is possible that some of column not present in older version and newer
version. Framework column annotation provide feature for making your model compitible for different odoo versions.
You need to just add annotation on column with your supported version.
@Odoo.api.v7
OColumn to_read = new OColumn("To Read", OBoolean.class);
@Odoo.api.v8
OColumn is_read = new Column("Is read", OBoolean.class);
Here, api.v7 column will created only if connected odoo server is version 7.0, same as for api.v8
@Odoo.SyncColumnName() Some time you need to create column name that is not supported in SQLite (such
as limit) or some variable name are not allowed in java such as class
By using SyncColumnName annotation framework will treat that column in different behaviour. For example, just
create _class column and add annotation named with class.
Synchronization will done with class column name but stored in _class also you can treat it with _class name
locally.
@Odoo.SyncColumnName("class")
OColumn _class = new OColumn("Class", OVarchar.class);
@Odoo.SyncColumnName("limit")
OColumn _limit = new OColumn("Limit", OInteger.class);
27
Info:
For ManyToOne, ManyToMany and OneToMany values will be different.
ManyToOne
public String storeManyToOne(OValues values){
String manyToOne = "";
if(!values.getString("parent_id").equals("false")){
List<Object> parent_id = (ArrayList<Object>) value.get("parent_id");
// Here, list index 0 contain record id (server id), and
// list index 1 contains record name
manyToOne = parent_id.get(1).toString();
}
return manyToOne;
}
ManyToMany or OneToMany
public int storeChildCount(OValues values){
if(!values.getString("child_ids").equals("false")){
// Contains list of ids (server ids)
return ((ArrayList<Object>) values.get("child_ids")).size();
}
return 0;
}
@Odoo.hasDomainFilter() In some cases, you need to filter your record depended on some value change at
runtime. For example, by changing country, states are loaded related to country.
By using hasDomainFilter annotation you can deal with it.
28
Chapter 1. Contents:
Add column domain, and annotation. If system found domains with hasDomainFilter annotation it will be treated
runtime. Note: it works with OForm control only
OColumn country_id = new OColumn("Country", ResCountry.class, RelationType.ManyToOne);
@Odoo.hasDomainFilter()
OColumn state_id = new OColumn("State", ResStates.class, RelationType.ManyToOne)
.addDomain("country_id","=", this);
OModel.java All the model (database class) extends OModel class. It contains all database required methods. Also
allow you to add column easily by declaring as member variable type OColumn
It automatically create relation tables and maintain relations for records.
Works with ContentProvider so faster performance for loading data from SQLite database.
Properly maintain local relation.
OModel is binded with own ORM. It easy and fast.
OModel support different datatypes which will create dynamic table with its type and return records as per its column
type.
Basic Data Types
OVarchar A string of limited length. Default length : 64
OColumn name = new OColumn("Name", OVarchar.class).setSize(100).setRequired();
OInteger An integer
OColumn counter = new OColumn("Counter", OInteger.class);
ODate A date. Stores yyyy-MM-dd formatted date or false if value not set
29
ODateTime Allows to store a date and the time of day in the same field. Stores yyyy-MM-dd HH:mm:ss
formatted date or false if value not set
OColumn date = new OColumn("Date", ODateTime.class);
OSelection Allows to store a string value (i.e., key for selection). Used selection for parsing Label for stored
key.
OColumn state = new OColumn("State", OSelection.class)
.addSelection("draft","Draft")
.addSelection("confirm","Confirmed")
.addSelection("close","Canceled")
.addSelection("done","Done");
Relation tyeps
OneToMany One2many field; the value of such a field is the recordset of all the records in comodel_name such that
the field inverse_name is equal to the current record.
It required Type as another models class type and also required realted column (as ManyToOne in related model)
OColumn parent_id = new OColumn("Company", ResPartner.class, RelationType.ManyToOne);
OColumn child_ids = new OColumn("Contacts", ResPartner.class, RelationType.OneToMany).
setRelatedColumn("parent_id");
ManyToOne The value of such a field is a recordset of size 0 (no record) or 1 (a single record).
OColumn parent_id = new OColumn("Company", ResPartner.class, RelationType.ManyToOne);
30
Chapter 1. Contents:
Constructor with Context and OUser parameter only. Pass model name in super.
This will create table with some base columns _id, id, create_date, write_date and more..
Note: Note that database is created when you first time run your application, or when you clean your data from app
setting. You need to clean application data everytime when you update your database column.
Note that, if you pass second parameter null while creating model object. It will take current active user object and
treat all operation to current user database only.
You can add columns as your requirement. Framework will create each relation column table automatically. But
if there is no any relation column for specific model and you need to create that table. You need to register it in
BaseModels.java @See Base models
Methods
setDefaultNameColumn() Syntax:
void setDefaultNameColumn(String nameColumn)
Used when default name column is different. Default takes name. Used for storing name column when ManyToOne
record arrive.
public class ResPartner extends OModel {
OColumn display_name = new OColumn("Name", OVarchar.class);
public ResPartner(Context context, OUser user){
super(context, "res.partner", user);
setDefaultNameColumn("display_name");
}
}
31
getDefaultNameColumn() Syntax:
String getDefaultNameColumn()
Alternative of setDefaultNameColumn() override getDefaultNameColumn() method for return default
name column.
public class ResPartner extends OModel {
OColumn display_name = new OColumn("Name", OVarchar.class);
public ResPartner(Context context, OUser user){
super(context, "res.partner", user);
}
@Override
public String getDefaultNameColumn(){
return "display_name";
}
}
setModelName() Syntax:
void setModelName(String modelName)
In some cases, you need to change model name (before just creating database table) depends on odoo version.
public class CalendarEvent extends OModel {
...
...
public CalendarEvent(Context context, OUser user){
super(context, "calendar.event", user);
// Model name different for calendar.event in odoo version 7.0
if(getOdooVersion().getVersionNumber() ==7){
setModelName("crm.meeting");
}
}
}
getTableName() Syntax:
String getTableName()
Returns, table name for model. (Generally, res.partner become res_partner)
ResPartner partner = new ResPartner(mContext, null);
String tableName = partner.getTableName();
setHasMailChatter() Syntax:
void setHasMailChatter(boolean hasChatter)
Used to enable mail chatter below OForm view. takes boolean parameter
public class ResPartner extends OModel {
...
...
32
Chapter 1. Contents:
getUser() Syntax:
OUser getUser()
Used to get current active User object. returns OUser object
ResPartner partner = new ResPartner(mContext, null);
OUser user = partner.getUser();
String userName = user.getName();
int userId = user.getUserId();
getOdooVersion() Syntax:
OdooVersion getOdooVersion()
Used to get current users odoo version information.
ResPartner partner = new ResPartner(mContext, null);
OdooVersion odooVersion = partner.getOdooVersion();
int versionNumber = getOdooVersion().getVersionNumber();
String versionType = getOdooVersion().getVersionType();
getColumns() Syntax:
List<OColumn> getColumns()
List<OColumn> getColumns(boolean local)
Used to get list of models column. returns, ArrayList<OColumn>
Takes one optional parameter boolean, If you want to get only local column or server columns
local boolean
ResPartner partner = new ResPartner(mContext, null);
// Getting all columns
for(OColumn column: partner.getColumns()){
Log.i(column.getName() , column.getLabel());
}
// Getting local columns
for(OColumn column: partner.getColumns(true)){
Log.i(column.getName() , column.getLabel());
}
// Getting server columns
for(OColumn column: partner.getColumns(false)){
33
Log.i(column.getName() , column.getLabel());
}
getRelationColumns() Syntax:
List<OColumn> getRelationColumns()
Used when you need to get all relation columns, ManyToMany, ManyToOne and OneToMany
ResPartner partner = new ResPartner(mContext, null);
for(OColumn column : partner.getRelationColumns()){
Log.i(column.getName(), column.getLabel());
}
getColumn() Syntax:
OColumn getColumn(String columnName)
Used to get OColumn object by using its name
ResPartner partner = new ResPartner(mContext, null);
OColumn display_name = partner.getColumn("display_name");
Note, if annotations applied and version not compitable with that column, it will returns null
getFunctionalColumns() Syntax:
List<OColumn> getFunctionalColumns()
Returns all functional columns (with annotation @Odoo.Functional)
ResPartner partner = new ResPartner(mContext, null);
for(OColumn column : partner.getFunctionalColumns()){
Log.i(column.getName(), column.getLabel());
}
getManyToManyColumns() Syntax:
List<OColumn> getManyToManyColumns(OModel reationModel)
Returns list of OColumn for many to many table. Takes relation model object as parameter
ResPartner partner = new ResPartner(mContext, null);
for(OColumn col: partner.getManyToManyColumns(new Tags(mContext, null))){
Log.i(col.getName(), col.getLabel());
}
createInstance() Syntax:
OModel createInstance(Class<?> type)
Used to create OModel object related to model class type.
34
Chapter 1. Contents:
authority() Syntax:
String authority()
returns, default authority.
ContentProvider
Used by BaseModelProvider.
uri() Syntax:
Uri uri()
Returns, model Uri object. Works with BaseModelProvider
ResPartner partner = new ResPartner(mContext, null);
Cursor cr = getContentResolver().query(
partner.uri(), // URI
null, // Projection
null, // Selection
null, // Selection arguments
null // sort order
);
buildURI() Syntax:
Uri buildURI(String authority)
Used to create custom uri with different authority and path segments.
35
projection() Syntax:
String[] projection()
String[] projection(boolean onlyServerColumns)
Returns string array of columns used as projection to ContentResolver query() method.
Optional parameter for getting only local column projection or server column projection.
ResPartner partner = new ResPartner(mContext, null);
Cursor cr = getContentResolver().query(
partner.uri(), // URI
partner.projection(), // Projection
null, // Selection
null, // Selection arguments
null // sort order
);
Database Operations
getLabel() Returns label for selection value. Works with OSelection type
CRMLead leads = new CRMLead(mContext, null);
ODataRow row = leads.browse(1);
String stateLabel = leads.getLabel("state", row.getString("state"));
36
Chapter 1. Contents:
// Projection
// Selection
// Selection arguments
getServerIds()
returns list of server ids.
ResPartner partner = new ResPartner(mContext, null);
List<Integer> serverIds = partner.getServerIds();
37
insertOrUpdate() Syntax:
int insertOrUpdate(int serverId, OValues values)
int insertOrUpdate(String selection, String[] selectionArgs, OValues values)
Creates new record if not exists or update if exists
ResPartner partner = new ResPartner(mContext, null);
OValues values = new OValues();
values.put("id",1);
values.put("name", "Dharmang Soni");
int newId = partner.insertOrUpdate(1, values);
38
Chapter 1. Contents:
values.
returns
new
created
id
if
successfull,
otherwise
delete() Delete record from local. Server record will be deleted when synchronization done.
Syntax:
delete(int row_id)
delete(String selection, String[] selectionArgs)
retuns number of record deleted.
ResPartner partner = new ResPartner(mContext, null);
int count = partner.delete(5);
// or
int count = partner.delete(OColumn.ROW_ID +" = ?", new String[]{"5"});
selectServerId() Syntax:
int selectServerId(int row_id)
returns server id for local record.
If record not found, returns OModel.INVALID_ROW_ID i.e., -1
ResPartner partner = new ResPartner(mContext, null);
int serverId = partner.selectServerId(2);
selectManyToManyRecords() Syntax:
List<ODataRow> selectManyToManyRecords(String[] projection, String
column_name, int row_id)
Returns list of many to many relation records for column and row.
ResPartner partner = new ResPartner(mContext, null);
List<ODataRow> tags = partner.selectManyToManyRecords(new String[]{"name"}, "tag_ids", 2);
39
update() Syntax:
int update(String selection, String[] args, OValues values)
int update(int row_id, OValues values)
Update record value.
ResPartner partner = new ResPartner(mContext, null);
OValues values =new OValues();
values.put("name","Parth Gajjar");
int updated = partner.update(5, values);
query() Syntax:
List<ODataRow> query(String sql)
List<ODataRow> query(String sql, String[] args)
Returns list of record generated by query.
ResPartner partner = new ResPartner(mContext, null);
String sql = "SELECT _id, name, city FROM res_partner WHERE country_id = ?";
List<ODataRow> records = partner.query(sql, new String[]{"4"});
executeRawQuery() Syntax:
Cursor executeRawQuery(String sql, String[] args)
Used to execute raw queries.
ResPartner partner = new ResPartner(mContext, null);
executeQuery() Syntax:
void executeQuery(String sql)
Execute queries. DROP TABLE, CREATE TABLE, etc...
getName() Syntax:
String getName(int row_id)
Returns name column value for record. (@See setDefaultNameColumn() and getDefaultNameColumn())
ResPartner partner = new ResPartner(mContext, null);
String name = partner.getName(3);
40
Chapter 1. Contents:
countGroupBy() Syntax:
ODataRow countGroupBy(String column, String group_by, String having, String[]
args)
Returns ODataRow object with total column contains total number of records
ResPartner partner = new ResPartner(mContext, null);
int total = partner.countGroupBy("parent_id", "parent_id", "parent_id != ?", new String[]{"false"});
defaultDomain() Sytanx:
ODomain defaultDomain()
Returns, default domain for model. called when synchronization occured. Default it return only blank object new
ODomain() with no domain filter. You need to override this method for return you default domain filter for
model.
class ResPartner extends OModel {
....
....
....
@Override
public ODomain defaultDomain(){
ODomain domain = new ODomain();
domain.put("customer","=",true);
return domain;
}
}
checkForCreateDate() Syntax:
boolean checkForCreateDate()
Return true if you need to check for create date on synchronization. It will filter create_date with sync limit from
setting.
If return false, all the data are re-synchronized every time.
Default is True
41
checkForWriteDate() Syntax:
boolean checkForWriteDate()
Return true if you need to compare each of record with write_date. It will reduce the trafic for requests. Only
different write_date records are syncronized.
If return false, nothing will checked with write_date
Default True
class ResPartner extends OModel {
...
...
...
@Override
public boolean checkForWriteDate(){
return true;
}
}
allowUpdateRecordOnServer() Syntax:
boolean allowUpdateRecordOnServer()
If true, framework will update record on server if local record dirty and write_date is newer that servers
write_date
If false, framework will never update record on server with locally changed values.
Default True
class ResPartner extends OModel {
...
...
...
@Override
public boolean allowUpdateRecordOnServer(){
return true;
}
}
allowCreateRecordOnServer() Syntax:
boolean allowCreateRecordOnServer()
42
Chapter 1. Contents:
If true, framework will create record on server if it found 0 value to id column. (i.e., locally created records)
If false, framework will never create record on server.
Default True
class ResPartner extends OModel {
...
...
...
@Override
public boolean allowCreateRecordOnServer(){
return true;
}
}
allowDeleteRecordOnServer() Syntax:
boolean allowDeleteRecordOnServer()
If true, framework will delete record from server if it locally inactive (deleted by user locally)
If false, framework will never delete record from server
Default True
class ResPartner extends OModel {
...
...
...
@Override
public boolean allowDeleteRecordOnServer(){
return true;
}
}
allowDeleteRecordInLocal() Syntax:
boolean allowDeleteRecordInLocal()
If true, framework will remove local record if server record not exist.
If false, framework will not remove any local record if server record not exist.
Default True
class ResPartner extends OModel {
...
...
...
@Override
public boolean allowDeleteRecordInLocal(){
return true;
}
}
43
quickSyncRecords() Syntax:
void quickSyncRecords(ODomain domain)
Used when you need to synchronize some of records depends on some domain. You need to run this method in
AsynTask or any background service.
new AsyncTask<Void,Void,Void>{
public Void doInBackground(Void...args){
ResPartner partner = new ResPartner(mContext, null);
ODomain domain = new ODomain();
domain.add("is_company", "=", true);
partner.quickSyncRecords(domain);
return null;
}
}.execute();
quickCreateRecord() Syntax:
void ODataRow quickCreateRecord(ODataRow row)
Return fully synced record data row object. You need to pass datarow object which contain id column with its server
id value. Method will sync full record and return updated object.
new AsyncTask<Void,Void,Void>{
public Void doInBackground(Void...args){
ResPartner partner = new ResPartner(mContext, null);
ODataRow row = new ODataRow();
row.put("id", 49);
44
Chapter 1. Contents:
row = partner.quickCreateRecord(row);
return null;
}
}.execute();
Other
isInstalledOnServer() Syntax:
void isInstalledOnServer(String module_name, IModuleInstallListener callback)
Check for module installed on server or not.
ResPartner partner = new ResPartner(mContex, null);
partner.isInstalledOnServer("notes", new IModuleInstallListener() {
@Override
public void installedOnServer(boolean isInstalled) {
// isInstalled ?
}
});
getServerDataHelper() Syntax:
ServerDataHelper getServerDataHelper()
Used to perform some of server operations (works with live network only).
Contains following methods:
getOdoo() : Returns Odoo object
nameSearch() : Name search on server
read() : Read record from server
searchRecords() : search records with fields, domain and limit
executeWorkFlow() : execute server workflow with signal
callMethod() : call models custom methods
createOnServer() : quick create record on server (not create locally)
updateOnServer() : quick update record on server (not update locally)
BaseModelProvider.java Provide base database operation with ContentResolver,
extends ContentProvider and works with Uri
We required to use BaseModelProvider when creating custom sync service for model.
public class CustomersSyncProvider extends BaseModelProvider {
@Override
public String authority() {
return ResPartner.AUTHORITY;
}
}
45
<provider
android:name="com.odoo.addons.customers.providers.CustomersSyncProvider"
android:authorities="com.odoo.core.provider.content.sync.res_partner"
android:label="@string/sync_label_customers"
android:multiprocess="true" />
46
Chapter 1. Contents:
else {
MailMessage mail = new MailMessage(getContext(), getUser(uri));
return mail.executeRawQuery("select * from mail_message", null);
}
}
}
OSyncService.java Provide support for managing your sync requests and perform operation with your model data..
When uses sync adapter for custom sync service. Use OSyncService We need to extends OSyncService class
which implement two methods:
1. getSyncAdapter()
2. performDataSync()
getSyncAdapter() Syntax:
OSyncAdapter getSyncAdapter(OSyncService serviceObj, Context context)
Used to return intial sync adapter object. (do not use chaining methods in this method)
public class CustomerSyncService extends OSyncService {
@Override
public OSyncAdapter getSyncAdapter(OSyncService service, Context context) {
return new OSyncAdapter(context, ResPartner.class, this, true);
}
@Override
public void performDataSync(OSyncAdapter adapter, Bundle extras, OUser user) {
}
}
performDataSync() Called just before data sync start. You can put some filters (domains), limiting data requiest in this method. Also you can specify the next sync operation after its sync finish.
public class CustomerSyncService extends OSyncService {
public static final String TAG = CustomerSyncService.class.getSimpleName();
@Override
public OSyncAdapter getSyncAdapter(OSyncService service, Context context) {
return new OSyncAdapter(context, ResPartner.class, service, true);
}
@Override
public void performDataSync(OSyncAdapter adapter, Bundle extras, OUser user) {
ODomain domain = new ODomain();
domain.add("active","=",true);
adapter.syncDataLimit(80).setDomain(domain);
}
}
47
Here, You can see we have checked for model name. Each time when you have chaining sync adapters you need to
check for model name in performDataSync. Otherwise, your service will go in infinite loop.
onSyncFinish() will tell service to perform next operation and service will continue to complete all the task in
chain.
Note: You have to check everytime for each of model to pass domain and filters by getting its model name.
If you dont wont to continue with next sync operation but you need to do some operation after sync finish. You can do
it in two ways:
1. Just add sync finish call back and return null. Do your operation before returning null or
2. Just override onSyncFinished() method in your model. Where you can perform your operations.
Drawer Menu
The navigation drawer is a panel that transitions in from the left edge of the screen and displays the apps main
navigation options.
Odoo mobile framework provide feature to add dynamic menu to your application just by providing list of menus.
48
Chapter 1. Contents:
49
By extending BaseFragment class you are allowed to implement drawerMenu() method. Which returns list of
DrawerItem with key, title and your object of fragment or class type for Activity.
Here is simple example for loading drawer items:
class Customers extends BaseFragment {
...
...
@Override
public List<ODrawerItem> drawerMenus(Context context) {
List<ODrawerItem> items = new ArrayList<>();
items.add(new ODrawerItem(KEY).setTitle("Customers")
.setIcon(R.drawable.ic_action_customers)
.setExtra(extra(Type.Customer))
.setInstance(new Customers()));
items.add(new ODrawerItem(KEY).setTitle("Suppliers")
.setIcon(R.drawable.ic_action_suppliers)
.setExtra(extra(Type.Supplier))
.setInstance(new Customers()));
items.add(new ODrawerItem(KEY).setTitle("Companies")
.setIcon(R.drawable.ic_action_company)
.setExtra(extra(Type.Company))
.setInstance(new Customers()));
return items;
}
public Bundle extra(Type type) {
Bundle extra = new Bundle();
extra.putString(EXTRA_KEY_TYPE, type.toString());
return extra;
}
...
...
}
50
Chapter 1. Contents:
ODrawerItem setInstance(Class<?
ODrawerItem setInstance(Class<?
51
Addons
52
Chapter 1. Contents:
Your addon main class extends BaseFragment and implement two methods:
1. drawerMenus()
2. database()
drawerMenus() For your addons navigation menus, BaseFragment provide method to be implement for generating menu under application drawer. Returns list of DrawerItem
53
54
Chapter 1. Contents:
model
under
55
ProjectTask contains project_id column related to ProjectProject class type with ManyToOne relation.
We have passed ProjectTask.class to database() method. So, when framework creating database, it will
take all the relation models in columns and create its master table.
Now, for running app. You need to register your main class to addons registery as below.
Registering addon to Addons registry Each of the modules (addons) are registered under Addons.java class of
com.odoo.config package.
public class Addons extends AddonsHelper {
OAddon customers = new OAddon(Customers.class).setDefault();
OAddon tasks = new OAddon(Tasks.class);
}
Creating Sync service The sync service component in app encapsulates the code for the tasks that transfer data
between the device and a server. Based on the scheduling and triggers provided by application, the sync service
framework runs the code in the sync adapter component and perform database operation with received data from
server. To create sync service for your addon, you need to add the following pieces:
Sync Service class (extends OSyncService class)
Custom database provider class with your AUTHORITY (extends BaseModelProvider class)
Sync adapter XML metadata file.
Declarations in the app manifest.
Sync Service class
model.
A component that allows the sync framework to run the code in your sync adapter class for given
56
Chapter 1. Contents:
import com.odoo.core.service.OSyncAdapter;
import com.odoo.core.service.OSyncService;
import com.odoo.core.support.OUser;
public class ProjectSyncService extends OSyncService {
public static final String TAG = ProjectSyncService.class.getSimpleName();
@Override
public OSyncAdapter getSyncAdapter(OSyncService service, Context context) {
return new OSyncAdapter(getApplicationContext(), ProjectTask.class, this, true);
}
@Override
public void performDataSync(OSyncAdapter adapter, Bundle extras, OUser user) {
adapter.syncDataLimit(80);
}
}
Custom database provider class with your AUTHORITY (extends BaseModelProvider class) The sync adapter
framework is designed to work with device data managed by the flexible and highly secure content provider framework.
For this reason, the sync adapter framework expects that an app that uses the framework has already defined a content
provider for its local data. If the sync adapter framework tries to run your sync adapter, and your app doesnt have a
content provider, your sync adapter crashes.
Here, odoo mobile framework have pre defined methods and mechanism to handle your data with content provider.
The one BaseModelProvider is central ContentProvider for all models with base AUTHORITY shared with
each of the model.
But, in case of creating custom sync service we required different content provider to be registerd in Android Manifest
file. To do so, we just need to extend BaseModelProvider and provide our custom AUTHORITY by overriding
authority() method.
Here is snippet:
Adding custom AUTHORITY to Model
public class ProjectTask extends OModel {
public static final String TAG = ProjectTask.class.getSimpleName();
public static final String AUTHORITY = "com.odoo.addons.projects.project_tasks";
57
import com.odoo.addons.projects.models.ProjectTask;
import com.odoo.core.orm.provider.BaseModelProvider;
public class ProjectTaskProvider extends BaseModelProvider {
public static final String TAG = ProjectTaskProvider.class.getSimpleName();
@Override
public String authority() {
return ProjectTask.AUTHORITY;
}
}
Sync adapter XML metadata file A file containing information about your sync adapter. The framework reads this
file to find out how to load and schedule your data transfer.
To plug your sync adapter component into the framework, you need to provide the framework with metadata that
describes the component and provides additional flags. The metadata specifies the account type youve created for
your sync adapter, declares a content provider authority associated with your app, controls a part of the system user
interface related to sync adapters, and declares other sync-related flags. Declare this metadata in a special XML file
stored in the /res/xml/ directory in your app project. You can give any name to the file, although its usually called
syncadapter.xml.
See
more
at
:
adapter.html#CreateSyncAdapterMetadata
https://developer.android.com/training/sync-adapters/creating-sync-
<sync-adapter xmlns:android="http://schemas.android.com/apk/res/android"
android:accountType="com.odoo.auth"
android:contentAuthority="com.odoo.addons.projects.project_tasks"
android:supportsUploading="true"
android:userVisible="true" />
All Done !
Launch your application by cleaning app data. (need to clean because we have updated database.)
You can see sync option for project tasks under your account:
58
Chapter 1. Contents:
59
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mView = view;
listView = (ListView) mView.findViewById(R.id.listview);
listAdapter = new OCursorListAdapter(getActivity(), null, android.R.layout.simple_list_it
listView.setAdapter(listAdapter);
}
...
...
60
Chapter 1. Contents:
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mView = view;
listView = (ListView) mView.findViewById(R.id.listview);
listAdapter = new OCursorListAdapter(getActivity(), null, android.R.layout.simple_lis
listView.setAdapter(listAdapter);
getLoaderManager().initLoader(0, null, this);
}
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
return new CursorLoader(getActivity(), db().uri(), null, null, null, null);
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
listAdapter.changeCursor(data);
if (data.getCount() > 0) {
OControls.setGone(mView, R.id.loadingProgress);
OControls.setVisible(mView, R.id.swipe_container);
OControls.setGone(mView, R.id.no_items);
} else {
OControls.setGone(mView, R.id.loadingProgress);
OControls.setGone(mView, R.id.swipe_container);
OControls.setVisible(mView, R.id.no_items);
OControls.setText(mView, R.id.title, "No Tasks found");
OControls.setText(mView, R.id.subTitle, "Swipe to check new tasks");
}
if (db().isEmptyTable()) {
// Request for sync
}
}
@Override
public void onLoaderReset(Loader<Cursor> loader) {
listAdapter.changeCursor(null);
}
...
...
}
Registering sync (SwipeRefresh) control and sync observer @See more setHasSwipeRefreshView()
@See more setHasSyncStatusObserver()
Swipe refresh view listener:
public class Tasks extends BaseFragment implements LoaderManager.LoaderCallbacks<Cursor>,
ISyncStatusObserverListener, SwipeRefreshLayout.OnRefreshListener {
...
...
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
listAdapter.changeCursor(data);
if (data.getCount() > 0) {
61
OControls.setGone(mView, R.id.loadingProgress);
OControls.setVisible(mView, R.id.swipe_container);
OControls.setGone(mView, R.id.no_items);
setHasSwipeRefreshView(mView, R.id.swipe_container, this);
} else {
OControls.setGone(mView, R.id.loadingProgress);
OControls.setGone(mView, R.id.swipe_container);
OControls.setVisible(mView, R.id.no_items);
setHasSwipeRefreshView(mView, R.id.no_items, this);
OControls.setText(mView, R.id.title, "No Tasks found");
OControls.setText(mView, R.id.subTitle, "Swipe to check new tasks");
}
if (db().isEmptyTable()) {
// Request for sync
onRefresh();
}
}
@Override
public void onRefresh() {
if (inNetwork()) {
parent().sync().requestSync(ProjectTask.AUTHORITY);
}
}
...
...
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mView = view;
listView = (ListView) mView.findViewById(R.id.listview);
listAdapter = new OCursorListAdapter(getActivity(), null, android.R.layout.simple_lis
listView.setAdapter(listAdapter);
setHasSyncStatusObserver(TAG, this, db());
getLoaderManager().initLoader(0, null, this);
}
@Override
public void onStatusChange(Boolean changed) {
if(changed){
getLoaderManager().restartLoader(0, null, this);
}
}
...
62
Chapter 1. Contents:
...
}
Binding View
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mView = view;
listView = (ListView) mView.findViewById(R.id.listview);
listAdapter = new OCursorListAdapter(getActivity(), null, android.R.layout.simple_list_item_1
listView.setAdapter(listAdapter);
listAdapter.setOnViewBindListener(this);
setHasSyncStatusObserver(TAG, this, db());
getLoaderManager().initLoader(0, null, this);
}
@Override
public void onViewBind(View view, Cursor cursor, ODataRow row) {
OControls.setText(view, android.R.id.text1, row.getString("name"));
}
...
...
}
63
64
Chapter 1. Contents:
To provide faster application development, odoo mobile framework come with some of usefull controls which work
with your model record, integrated with chatter view, different data types, on change methods, validations, live search
and more.
OForm widget OForm widget used when you need to show model record. It helps record to bind view as per its
type. Uses OField as its inner widgets. You need to just add your fields under OForm controls.
It extends LinearLayout so you can easily change its layout property as per LinearLayout does.
Some of other property works with OForm:
prefix:editableMode : boolean
prefix:modelName : string
prefix:autoUIGenerate : boolean
prefix:controlIconTint: color
Here, prefix is your resource attribute reference.
<RelativeLayout xmlns:android=-http://schemas.android.com/apk/res/androidxmlns:prefix=-http://schemas.android.com/apk/res-autoandroid:layout_width=-match_parentandroid:layout_height=-match_parent->
<odoo.controls.OForm
android:id=-@+id/customerFormEditprefix:modelName=-res.partnerandroid:layout_width=-match_parentandroid:orientation=-verticalandroid:layout_height=-wrap_content->
<!-- OFields controls here //-->
</odoo.controls.OForm>
</RelativeLayout>
You can take any of valid name for prefix, ADT default take app as prefix.
What if you want to add other controls in OForm widget ?
Yes, you can also add other controls such as ImageView, TextView or any other controls under OForm.
editableModel Takes boolean value (true|false). default false. Not required property
Make your form work in editable mode or read only mode.
modelName Takes string value (model name). Required property
OForm uses model name to bind your field property. Such as field label, its type and other properties.
65
autoUIGenerate Takes boolean value (true|false). Default true Not required property
Responsible to generate responsive layout for your form fields. (works with OFields only, non of your other controls
are affected by autoUIGenerate property)
Adds icon (if you have provided to OField), label for field, proper spacing and marging and some other UI changes.
controlIconTint Takes color reference value or color code. Not required property
Changes all your OField widget icon tint color.
Initialize form widget OForm form = (OForm) view.findViewById(R.id.myForm);
Methods:
initForm()
Syntax:
setEditable()
Syntax:
loadChatter()
Syntax:
setIconTintColor()
Syntax:
66
Chapter 1. Contents:
getValues()
Syntax:
OValues getValues()
Returns form values, used when you need to create or udpate record. If returns null, may be validation failed.
OForm form = (OForm) view.findViewById(R.id.myForm);
form.initForm(record);
...
...
OValues updatedValues = form.getValues();
if(updatedValues != null){
// Store updated values.
}
67
68
Chapter 1. Contents:
OField widget OField widget works with OForm widget. Each of OField is your models column or just dummy
column.
If OForm autoUIGenerate flag is on, it will create UI with icon (if any), label and column input part. (input box,
checkbox, radio button, datetime picker, many to one widget - spinner, and more^^^)
Some of properties you need to know before using OField control.
fieldName : string Models column name or your dummy column name.
<odoo.controls.OField
app:fieldName=-nameandroid:layout_height=-wrap_contentandroid:layout_width=-match_parent->
</odoo.controls.OField>
iconTint : reference|color Changes icon color. takes color refernece or color code.
<odoo.controls.OField
android:layout_width=-match_parentapp:iconResource=-@drawable/ic_action_messageapp:fieldName=-emailapp:iconTint=-@color/android_greenandroid:layout_height=-wrap_content->
</odoo.controls.OField>
showIcon : boolean, showLabel : boolean Show/Hide icon and label. Takes true or false. Default is true
<odoo.controls.OField
android:layout_width=-match_parentapp:iconResource=-@drawable/ic_action_messageapp:fieldName=-emailapp:showLabel=-falseandroid:layout_height=-wrap_content->
</odoo.controls.OField>
69
Chapter 1. Contents:
widgetImageSize : dimension Changes image size (works with Widget type Image or ImageCircle)
withBottomPadding : boolean Ignore adding bottom padding by auto UI generator if provided false.
withTopPadding : boolean Ignore adding top padding by auto UI generator if provided false.
controlLabel : string|reference
Label for control. takes string or string reference.
defaultValue : reference|string Default value for control. If no data found from record for field it will takes
default value.
defaultImage : reference Default image for Image widget type. If no image found.
valueArray : reference Used for dummy column, value array reference (works with selection type)
fieldTextAppearance : reference Field text appearance reference
fieldTextSize : dimension, fieldLabelSize : dimension Field text and label size in dimension.
fieldTextColor : color , fieldLabelColor : color Field text and label color
fieldLabelTextAppearance : reference Field label text appearance
71
Actionbar Spinner Actionbar spinner provide quick filter and navigations. BaseFragment provide method to
implement spinner to your fragment.
By calling following method your can acitvate spinner control for actionbar from onViewCreated method.
parent().setHasActionBarSpinner(true);
...
...
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mView = view;
parent().setHasActionBarSpinner(true);
}
...
...
72
Chapter 1. Contents:
When you call this method, OdooActivity activate spinner for your fragment and returns Spinner object by calling
parent().getActionBarSpinner(); method after activating spinner for actionbar.
Now, you can easily manage your spinner with adding items by adapter and custom view.
Chatter view
Full history on your record. OForm control integrated with Mail chatter for your record. You just need to activate
chatter for your model and OForm will take care for loading chatter view for your record.
Supported features:
Log internal note with attachments
1.3. Getting Started with Framework
73
1.4 Contributing
If you would like to contribute code you can do so through GitHub by forking the repository and sending a pull request.
When submitting code, please make every effort to follow existing conventions and style in order to keep the code as
readable as possible.
74
Chapter 1. Contents:
CHAPTER 2
genindex
search
75
76
Index
Symbols
_s() _c() _dim(), 23
A
About, 1
actionbar spinner, 71
Addon Registry, 14
Addons, 52
allowCreateRecordOnServer(), 42
allowDeleteRecordInLocal(), 43
allowDeleteRecordOnServer(), 43
allowUpdateRecordOnServer(), 42
Aplication Config, 8
authority(), 35
autoUIGenerate, 66
B
Base Models Intro, 16
BaseFragment.java, 20
BaseModelProvider.java, 45
Blue Layer, 12
browse(), 36
buildURI(), 35
C
Chatter View, 73
checkForCreateDate(), 41
checkForWriteDate(), 42
Clone Framework, 5
controlIconTint, 66
controlLabel, 71
Controls, 65
count(), 39
countGroupBy(), 41
Create Model, 55
createInstance(), 34
D
Datatypes, 29
db(), 20
defaultDomain(), 41
defaultImage, 71
defaultValue, 71
delete(), 39
Device testing, 2
Directory Structure, 12
Download Android Studio, 1
drawer menu, 48
E
editableMode, 65
executeQuery(), 40
executeRawQuery(), 40
F
fieldLabelColor, 71
fieldLabelSize, 71
fieldLabelTextAppearance, 71
fieldName, 69
fieldTextAppearance, 71
fieldTextColor, 71
fieldTextSize, 71
fieldType, 70
First Step, 7
Framework Architecutre, 8
G
getColumn(), 34
getColumns(), 33
getDefaultNameColumn(), 32
getFunctionalColumns(), 34
getLabel() Selection type, 36
getLastSyncDateTime(), 41
getManyToManyColumns(), 34
getName(), 40
getOdooVersion(), 33
getRelationColumns(), 34
getServerDataHelper(), 45
getServerIds(), 37
getSyncAdapter(), 47
77
getTableName(), 32
getUser(), 33
getValues(), 67
Git Repositories, 3
Green Layer, 8
I
iconResource, 69
iconTint, 69
Import to Android Studio, 5
initForm(), 66
inNetwork(), 21
insert(), 38
insertOrUpdate(), 38
isEmptyTable(), 37
isInstalledOnServer(), 45
L
loadChatter(), 66
M
Mail Chatter (Widget), 18
modelName, 65
O
OColumn.addDomain(), 26
OColumn.addSelection(), 27
OColumn.java, 24
OColumn.setDefaultValue(), 26
OColumn.setLabel(), 25
OColumn.setLocalColumn(), 26
OColumn.setName(), 25
OColumn.setRecordSyncLimit(), 25
OColumn.setRelatedColumn(), 25
OColumn.setRequired(), 26
OColumn.setSize(), 25
OColumn.setType(), 26
Odoo Mobile Framework, 3
ODrawerItem.java, 50
OField, 69
OForm, 65
OModel.get(), 35
OModel.java, 29
onSyncStarted() onSyncFinished(), 44
Orange Layer, 12
OSyncService.java, 47
OVarchar, 29
P
parent(), 20
parsePattern, 69
performDataSync(), 47
projection(), 36
78
Q
query(), 40
quickCreateRecord(), 44
quickSyncRecords(), 44
R
Red Layer, 12
Register Addon, 56
S
select(), 37
selectManyToManyRecords(), 39
selectServerId(), 39
setCounter(), 51
setDefaultNameColumn(), 31
setEditable(), 66
setExtra(), 51
setGroupTitle(), 51
setHasFloatingButton(), 21
setHasMailChatter(), 32
setHasSearchView(), 22
setHasSwipeRefreshView(), 22
setHasSyncStatusObserver(), 23
setIcon(), 52
setIconTintColor(), 66
setInstance(), 51
setModelName(), 32
setSwipeRefreshing() hideRefreshingProgress(), 23
setTitle(), 20, 50
showFab() hideFab(), 22
showIcon, 69
showLabel, 69
startFragment(), 21
Submit Issue, 7
T
Type: OBlob, 30
Type: OBoolean, 29
Type: ODate, 29
Type: ODateTime, 30
Type: OFloat, 29
Type: OHtml, 29
Type: OInteger, 29
Type: OSelection, 30
Type: OText, 29
Type: OTimestamp, 30
Type:: ManyToMany, 30
Type:: ManyToOne, 30
Type:: OneToMany, 30
U
update(), 40
uri(), 35
Index
user(), 20
V
v8, 27
valueArray, 71
W
widgetImageSize, 71
widgetType, 70
withBottomPadding, 71
withOutSidePadding, 70
withTopPadding, 71
Index
79