From 0701f73c65acd0ef0acff9bffa5c6c2126b3e2c2 Mon Sep 17 00:00:00 2001
From: Maxime Graulich <maxime.graulich@gmail.com>
Date: Tue, 14 May 2013 09:28:07 +0000
Subject: [PATCH] Add Android project

---
 contrib/mobile/Android/AndroidManifest.xml    |  32 +
 .../res/drawable-hdpi/ic_action_search.png    | Bin 0 -> 555 bytes
 .../Android/res/drawable-hdpi/ic_launcher.png | Bin 0 -> 865 bytes
 .../Android/res/drawable-hdpi/ic_list.png     | Bin 0 -> 464 bytes
 .../Android/res/drawable-hdpi/ic_mesh.png     | Bin 0 -> 760 bytes
 .../Android/res/drawable-hdpi/ic_settings.png | Bin 0 -> 1412 bytes
 .../Android/res/drawable-ldpi/ic_launcher.png | Bin 0 -> 384 bytes
 .../res/drawable-mdpi/ic_action_search.png    | Bin 0 -> 3030 bytes
 .../Android/res/drawable-mdpi/ic_launcher.png | Bin 0 -> 614 bytes
 .../Android/res/drawable-mdpi/model.png       | Bin 0 -> 1116 bytes
 .../Android/res/drawable-mdpi/param.png       | Bin 0 -> 3371 bytes
 .../mobile/Android/res/layout/list_header.xml |  13 +
 contrib/mobile/Android/res/layout/model.xml   |  35 +
 contrib/mobile/Android/res/raw/bh_pro         |  59 ++
 .../Android/res/raw/machine_magstadyn_a_pro   | 938 ++++++++++++++++++
 .../mobile/Android/res/raw/magnet_data_pro    |  16 +
 contrib/mobile/Android/res/raw/magnet_geo     |  93 ++
 contrib/mobile/Android/res/raw/magnet_pro     |  69 ++
 .../mobile/Android/res/raw/magnetostatics_pro | 209 ++++
 .../Android/res/raw/pmsm_8p_circuit_pro       | 123 +++
 contrib/mobile/Android/res/raw/pmsm_data_geo  | 104 ++
 contrib/mobile/Android/res/raw/pmsm_geo       |  95 ++
 contrib/mobile/Android/res/raw/pmsm_geo_pro   | 211 ++++
 contrib/mobile/Android/res/raw/pmsm_pro       | 211 ++++
 contrib/mobile/Android/res/raw/pmsm_rotor_geo | 163 +++
 .../mobile/Android/res/raw/pmsm_stator_geo    | 215 ++++
 contrib/mobile/Android/res/raw/test_geo       |  64 ++
 .../mobile/Android/res/values-v11/styles.xml  |   5 +
 .../mobile/Android/res/values-v14/styles.xml  |   5 +
 contrib/mobile/Android/res/values/strings.xml |  25 +
 contrib/mobile/Android/res/values/styles.xml  |   5 +
 contrib/mobile/Android/res/xml/models.xml     |  21 +
 .../src/org/geuz/onelab/GLESRender.java       |  45 +
 .../Android/src/org/geuz/onelab/Gmsh.java     |  90 ++
 .../src/org/geuz/onelab/MainActivity.java     | 806 +++++++++++++++
 .../org/geuz/onelab/ModeleArrayAdapter.java   |  54 +
 .../Android/src/org/geuz/onelab/Models.java   |  40 +
 .../src/org/geuz/onelab/Parameter.java        |  85 ++
 .../src/org/geuz/onelab/ParameterNumber.java  | 270 +++++
 .../src/org/geuz/onelab/ParameterString.java  | 152 +++
 .../org/geuz/onelab/SeparatedListView.java    | 144 +++
 .../src/org/geuz/onelab/mGLSurfaceView.java   | 133 +++
 42 files changed, 4530 insertions(+)
 create mode 100644 contrib/mobile/Android/AndroidManifest.xml
 create mode 100644 contrib/mobile/Android/res/drawable-hdpi/ic_action_search.png
 create mode 100644 contrib/mobile/Android/res/drawable-hdpi/ic_launcher.png
 create mode 100644 contrib/mobile/Android/res/drawable-hdpi/ic_list.png
 create mode 100644 contrib/mobile/Android/res/drawable-hdpi/ic_mesh.png
 create mode 100644 contrib/mobile/Android/res/drawable-hdpi/ic_settings.png
 create mode 100644 contrib/mobile/Android/res/drawable-ldpi/ic_launcher.png
 create mode 100644 contrib/mobile/Android/res/drawable-mdpi/ic_action_search.png
 create mode 100644 contrib/mobile/Android/res/drawable-mdpi/ic_launcher.png
 create mode 100644 contrib/mobile/Android/res/drawable-mdpi/model.png
 create mode 100644 contrib/mobile/Android/res/drawable-mdpi/param.png
 create mode 100644 contrib/mobile/Android/res/layout/list_header.xml
 create mode 100644 contrib/mobile/Android/res/layout/model.xml
 create mode 100644 contrib/mobile/Android/res/raw/bh_pro
 create mode 100644 contrib/mobile/Android/res/raw/machine_magstadyn_a_pro
 create mode 100644 contrib/mobile/Android/res/raw/magnet_data_pro
 create mode 100644 contrib/mobile/Android/res/raw/magnet_geo
 create mode 100644 contrib/mobile/Android/res/raw/magnet_pro
 create mode 100644 contrib/mobile/Android/res/raw/magnetostatics_pro
 create mode 100644 contrib/mobile/Android/res/raw/pmsm_8p_circuit_pro
 create mode 100644 contrib/mobile/Android/res/raw/pmsm_data_geo
 create mode 100644 contrib/mobile/Android/res/raw/pmsm_geo
 create mode 100644 contrib/mobile/Android/res/raw/pmsm_geo_pro
 create mode 100644 contrib/mobile/Android/res/raw/pmsm_pro
 create mode 100644 contrib/mobile/Android/res/raw/pmsm_rotor_geo
 create mode 100644 contrib/mobile/Android/res/raw/pmsm_stator_geo
 create mode 100644 contrib/mobile/Android/res/raw/test_geo
 create mode 100644 contrib/mobile/Android/res/values-v11/styles.xml
 create mode 100644 contrib/mobile/Android/res/values-v14/styles.xml
 create mode 100644 contrib/mobile/Android/res/values/strings.xml
 create mode 100644 contrib/mobile/Android/res/values/styles.xml
 create mode 100644 contrib/mobile/Android/res/xml/models.xml
 create mode 100644 contrib/mobile/Android/src/org/geuz/onelab/GLESRender.java
 create mode 100644 contrib/mobile/Android/src/org/geuz/onelab/Gmsh.java
 create mode 100644 contrib/mobile/Android/src/org/geuz/onelab/MainActivity.java
 create mode 100644 contrib/mobile/Android/src/org/geuz/onelab/ModeleArrayAdapter.java
 create mode 100644 contrib/mobile/Android/src/org/geuz/onelab/Models.java
 create mode 100644 contrib/mobile/Android/src/org/geuz/onelab/Parameter.java
 create mode 100644 contrib/mobile/Android/src/org/geuz/onelab/ParameterNumber.java
 create mode 100644 contrib/mobile/Android/src/org/geuz/onelab/ParameterString.java
 create mode 100644 contrib/mobile/Android/src/org/geuz/onelab/SeparatedListView.java
 create mode 100644 contrib/mobile/Android/src/org/geuz/onelab/mGLSurfaceView.java

diff --git a/contrib/mobile/Android/AndroidManifest.xml b/contrib/mobile/Android/AndroidManifest.xml
new file mode 100644
index 0000000000..ce2626134e
--- /dev/null
+++ b/contrib/mobile/Android/AndroidManifest.xml
@@ -0,0 +1,32 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="org.geuz.onelab"
+    android:versionCode="1"
+    android:versionName="1.0" >
+
+    <uses-feature android:glEsVersion="0x00010000" android:required="true"></uses-feature>
+    <uses-sdk
+        android:minSdkVersion="14"
+        android:targetSdkVersion="15" />
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
+
+    <application
+        android:icon="@drawable/ic_launcher"
+        android:label="@string/app_name"
+        android:theme="@style/AppTheme" android:logo="@drawable/ic_launcher">
+        <activity
+            android:name=".MainActivity"
+            android:label="@string/title_activity_main" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+            <intent-filter >
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.DEFAULT" />
+        		<category android:name="android.intent.category.BROWSABLE" />
+            	<data android:scheme="*"  android:host="*" android:pathPattern=".*\\.geo" android:mimeType="text/plain"  />    
+            </intent-filter>
+        </activity>
+    </application>
+
+</manifest>
\ No newline at end of file
diff --git a/contrib/mobile/Android/res/drawable-hdpi/ic_action_search.png b/contrib/mobile/Android/res/drawable-hdpi/ic_action_search.png
new file mode 100644
index 0000000000000000000000000000000000000000..8a7da97f768c8a5bbd9da5db77b18ae5ac546ad6
GIT binary patch
literal 555
zcmeAS@N?(olHy`uVBq!ia0y~yU@!n-4kiW$h8qca7Z?~A*pj^6T^Rm@;DWu&Co?cG
zKJavL42fucdu`*ZO$j2$KQ4~+j}%j75p;BFj!t~r>g*gHeb-yS(fq=tT9d7;u?``@
z0u!4}M5Y8NdY<?!KX1eI^1{~^KVoC-Up#D=St`;b($D*2zrd652M$ctF?!RV7G*|?
zaVgC{Yc~6AjU7LO%+fDad;5+j-`*Bzq7x{>-rT5j+J<4x_3Rj4h8x@V-ppyZ8(=i^
z$kh!J&Fl?siv#th7n*i0y7Ia-!JLI*-D^3%_UE5F7kMrXn(C!0)LG+rP_w{Vr0LHu
zovoR(x{opyt}Kn!pX&8M_iKhpkqo=*VWk$H_QUUk9%nHeD4g>?X!+&L7+&v5DhUd{
zmqS92UR|+jRi;$MVGm7H9_H7F1)W4(A6oDoTKY|&<>%MPSH~Y4&Ogt4xFGiXcaA`j
z)mO7tUwvfpj(L{f^5c&`eivDPH}8Ah{@ZWO_!*|9KFo?(eU<A5uc}aIhDq1kMjth1
z9+CdzzyI!2;OLNwoVNR}-XH6p@4sbVe`jXsI;vEy{4nUZXw#oxdS7$Qtmpb^c>8j!
zyqdLZUH!CKK~^(;d@ld7J(|7$zIET_mn9VpJMQM~kh)g3o3+e&l8T_y2HOdzpEfim
zZH!odo%>GE{<!s@fA%aAWLX%X@xg}wVbE{!raxScb*y|}*dG}j+O=`ro8Jr!3=E#G
KelF{r5}E+QSot>q

literal 0
HcmV?d00001

diff --git a/contrib/mobile/Android/res/drawable-hdpi/ic_launcher.png b/contrib/mobile/Android/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000000000000000000000000000000000000..13ba1383cfb684d42ad5e12bd49bfc09ae51e3b6
GIT binary patch
literal 865
zcmeAS@N?(olHy`uVBq!ia0y~yU}ykg4rT@hhA$5${$yZa_!;06;`$#97#JAt-@o6`
z(4e58@a@~%w{LGhe}4Y*<=uDg?6`1Y!HE+y{`~p*^XKR9-`_uaboAW0IR_3jeE$6W
z!Gi-=uB<q5V#2FeSFc@LbM$D}p+hade}Dh__4WJr_wU`?bLPy9XV1>wxUu2<`FY2V
z^?dm7@ZrP5|Ni~`@#EvmmzS?zUG@0!@xzDPX3S`aiE;7pFfcPyk(L(Pu%ThbjEo5r
z5^{1prcFx;54Vz#5D*gL;pAjnv7(@*B_bigK}AJk*RGn48_VkILhS9e=FG`ROLH+W
zP>_=o;o;#}x2|OJ<fMv<0B>(2U0u1TD4WK{FefJ+QBgi-W~Pu3i|yO1LLa`G$H2hA
zSQ6wH%;50sMjD8d<n8Xl(7`I}!N9=4S>O>_%)lU&2f~bJ*p9?8Ffg!}c>21sU*hIw
z;8u8@88MxKf$^cIi(^Q|oVQoqi<le)SRC6P{Lc^LNNJGWzfA87yH<Yf&KfiGorh|7
zZeo&BxX%#e!2E>q0gH)49pjV+wiEUZf)^Mn*#wxR6xKI<W|C5P-*A~pN<sO-ng+HG
zHVe%KjEk7hab`3`Gz2qADVROzX<+MMw@_Tb_=x!%cgBJ0dWJV*7aA7YGi~EKwvXwC
z<^o2qc;+|47Z}#AXDZ{&Xt;Hqv6{ui;k|T&ER$5i7u^F@jJz9usU>V}V4G1Zy&=qj
z`OQA&2+akIe)pNz2wz}W|DGv~Go#`5cgAcMlLPPB8$_9;1imOA*wet~@>jq>djVsj
zJ=+=142L`Z3~4MT3K!2a{9=-t@NzjrEF-VS*W!kG4Qx+-c{;c|Fi-lcvp{bF<IOs$
z0MQE#CHDL)I5Qmf#WRGkm@K%kp5YUdRKUyW43Uhy8eg*;rYyLo&t$|T74RmUabp8p
z$nR7Kl?9AX>tr8rXE^M=&rrc6b>T%h!?p&tl3%(FstXv`*6}ak&Tv?NpCzNo?{C?C
zDTnQK*-C1R=DEQQH!JR5V6OP6wCLjbE8HDY3k1$9efsNWlX`;j*H;0-@5>)E9%9w$
zw&vKp-zHBo<iNUJZ4$p`KURJuS)lPR>&NT)YwZ=^F)aD#ED`r}^W)!4<pGufo8}wq
RF)%PNc)I$ztaD0e0sv9vcOC!$

literal 0
HcmV?d00001

diff --git a/contrib/mobile/Android/res/drawable-hdpi/ic_list.png b/contrib/mobile/Android/res/drawable-hdpi/ic_list.png
new file mode 100644
index 0000000000000000000000000000000000000000..0845ffb33f34db2c2e4501f38c5dad6088d53f95
GIT binary patch
literal 464
zcmeAS@N?(olHy`uVBq!ia0y~yU@&K3V9@1YV_;z5n)Z1&0|Ns~v6E*A2L}g74M$1`
z0|NtRfk$L91B1Xn5N0&7n(M&8z#v)T8c`CQpH@<ySd_|8US6)3nU`IhoLG>mmtT}V
z`<;yx0|TS4r;B4qM&sLC_SqtiGHegh%^5fDFbdu0nB%gVWgVvzlO>;yl3CK^XFJv_
zA6cI;nc2B(%5<gaP6iXaf}$h3B3_+O+FY<?!>!aAsq?aySKm+i_r@U9<p7JZ%%W-A
zwdXtv78TV0s9Lzd&L`_k@bVWY_Z*viMYHPDmadN2nB{(#nzx&VRis<6zBdVeyQV5a
zH(EJIrSnSff%9b_cHCL;WZ&|?;hNJ|2kC_`jalclGiGYh&Ra3R?;W4`hyPsoj~@F_
zm!5*=xl1<g`YKy(dQUpc@W!z<$6jCYtTI}=(PQo+_3pBBYd`3e&f>fK`0B6uKO%}X
zXaCOHc|>(ljPa9IQ%;8>o1JSXm4EX8gFlO9w><ST@i&cI;&EkT{*Mm+P?sLl=~~X8
z(?0l{)-CnBIQf34i_P)tS3Ii>))sa%&v~4G%VuuGBMI^U47(P1UtIf4>=Oe61B0il
KpUXO@geCwyYRRbp

literal 0
HcmV?d00001

diff --git a/contrib/mobile/Android/res/drawable-hdpi/ic_mesh.png b/contrib/mobile/Android/res/drawable-hdpi/ic_mesh.png
new file mode 100644
index 0000000000000000000000000000000000000000..2c927569920e18ae051265d2fb7187c682cd8cf5
GIT binary patch
literal 760
zcmeAS@N?(olHy`uVBq!ia0y~yU@&B0U@+idV_;y|abVI;1_lO}VkgfK4h{~E8jh3>
z1_lPs0*}aI1_ptDAk1iDHP?ZGfkCpwHKHUqKdq!Zu_%?Hyu4g5GcUV1Ik6yBFTW^#
z_B$IX1_q{5PZ!6KjK;UOPG<!>${hc=-ZQ}bU94D$$a?AUppSVQul?rUAsjd{Xpd6R
zmbDRISz|i4zhdr?7H`_u{Eo%(!YYlmQTl7+#b-M7c%D<4G<mayy+zBJGxg_cPCSxH
zGxAq8YCd3^V75)6bxOm|peGL$6L>V3Y7flzTdQTnn!s{{Psho3m*2|!R~b*g>|F8k
zNoYX+O8KjG%3SAI4!rxY_jX59RrKEl>$tNsqYCsGeyzT>t5ah|`IYaC4nmKd7~ZVP
zd@r_W#Xa7Jt)Xvu1;wvQZe8yeZ!X~ab)MDAbt_-4?v~(dn9Hl?BOMr`&XiC(_g}rh
zbfyIN$)1;8M6R;GvMvp6Hmp~4yORIvTTAC<rzuz3UqzRuPA;@vrJ5jP!6(BskC|Io
z&V*a(*dKqd1G)>uZ!qog(3-K_ZGZWa8TSulO=7e?u=-T?@uCEyq)+|_tR9r^Ufq4d
z=z*l*eg{?2BO)IxH!YjG@ombkt4&VoVH3-WT*4+PZ<-`Caq5$fH7f2Ys+LOHCj}!t
z`%ZX4rEW}K^s1!lb57llo}I^;GWb7k>YY_)By7Dw^oZdD@dA;GE3dkuP6R#Re0q0p
zS|tA+b~UZpN4ka0D*RX2Uv1XRQCq*E=D_8gGi;?^dlw2dTSzjn2QeH`sJfc@wQ8v@
zr{Ri!0pFLicsS+oG<<yZEv;iA!;R@m3nY^!|8m_Mb^AI;p%ufoWjq-zH`dgJuD`N+
zWxItmL-j6(740{q7?OLlvIL(qCoJ%8h&p0+`gp<OvstSIr*3}zPb~kI=8-;z9dkm0
zE#K|plws>*@VEXh(|t<lfuVu>&v;w$$y}SN(#*Mgm<}5@|7WnV-<Di^D6Eiyfq}u(
L)z4*}Q$iB}jXXoX

literal 0
HcmV?d00001

diff --git a/contrib/mobile/Android/res/drawable-hdpi/ic_settings.png b/contrib/mobile/Android/res/drawable-hdpi/ic_settings.png
new file mode 100644
index 0000000000000000000000000000000000000000..aced98ab0d9c88e34b584f2b91441190f7cbf521
GIT binary patch
literal 1412
zcmeAS@N?(olHy`uVBq!ia0y~yU@&B0V9@7aV_;zLa!~rtz`(##?Bp53!NI{%!;#X#
zz`(#+;1OBOz#w1&!i;&^0*VX_43Z_T5hcO-X(i=}MX3zs<>h*rdD+Fui3O>8`9<lo
z-`PkpFt9Rux;TbpG;W<4-4PZla=hL+?!ZK)Gq+P_X=*+cndy@1rj#kJefC5<$6_AG
z7C9zPCi$+WDuG=Wyg6@qrv$jQq^_vsG`V2l<63*d`&CNvts526>2<bmJ|Dbp{(Rg1
z{6B{u9k^G$w)EfgHG99`$~Is5MVO6oaYI-_$)_CFZ%py7H+Hf{Fl}K}7Ov#~Vc@+`
zbJ7uu2QR0H=d$Lp%nB;G#>nk;E1s){foDxtHoF>=xY5=tN|F<8)K|Fo9u_Q(;gnzT
z**Hf>`;x9v&HP&n*9G;v3;j6ku!o27O0%X}-^ylbMZ@s7T{R!M{8mm@;^;ZQ;d7?s
z-)B7<)q+2yGBhPmUwy$K$HwRS;?Bg2`<C|<Np&)|Tun^yiWfY`w7Ic%VpY1)t>aTJ
z?6rO^el}pYvhxf1uk$(tR!u9EG%FW<;TyugwA9Dc=b6Nu@a5M%8A=!2nw<1~)i1xK
z-8<dV7go91&fDf+!)_xb$Thv;c!RE>Ri*{wohg^=rEc)?DCcwtPx{8ZwXoj$L%@>H
z#RoQe%r)6E**{6;gOAtmho_FzHEoc3%hu*%CC~eZ#i#Si>SIC)S#x(q2gV0gD?fLT
zvRad$Wd3SD@7B$X%v)cCq({v=pmbTiByx?}&5i3_G`_Bq7q!@zapP?_hfR3Ga*pUL
ziCVs|*b@9YZ~T_7;EiC_@tYU<f=!HZe)<=E7CYsfHJLXU&#0c+uGzVTsh+W3NNiGm
zV;sX3#aG8<j{Ux3*|v4hFYkR(AC^{KQT_IpnfuIrkNU9n{ui}<7@{ZLpWJr6m}gI*
zgG*`U)gP75+TZ7WZIfWSsuIw?>UMU|H>t3G8|C-Y6+TT%oELLWa`SPOW73L^RdaVK
z8{SI&@zvFB))iCLj+nDAZ?EQC-`;TY$hx^9x-H2sZl(xLJ;?BY`;@%%>OzJYo*vq-
zoZd)U^EY#9AA7?w*O`TBxm4ku`6>);O!f?yy?g%3R!o@i!?b11<k-D0l-9gY^(%dT
zVs(Pcg8iNj7QMXshIv|wwenY29R8<f$a%x##Lv?Y{0>Pb#wh#!o_u8O0X3&p0?oHM
zR{nWXCHq~xbK`-u2hV!`ExMYlvw?TVYPsis9T!b?NT_l9UwLTZ^3?~<c|34GwKnI!
z``+CtO3GLNT3UbH-*$@gRnF(jeO$YEIMeTDy7%w|*PpGN+5Kvb)LhnQ%jHF5w#A&9
zJhRNfLwTOckslffECrJSL~gsEcx}#b*{JS=XoB2_TCe-u2eK|{zqtB>F^=t;NRRhl
z;kB>M3B_x3hhJIFweOy`YVKFH<i&?GW0_gjtvWAe>6_x(a#z$)CC$WPfqU&fmBy|$
zJsb9K(&;pRt#V<tUY|<9#8AOHyN&sloB2D}mQK>p`t!_l^DeVP*P}`U<T@vZHuJBZ
zeMSH3W!AQSbBCrUORu>LMCNN0ESY4ne%tNsc~{ohE!dY`wRXkrDfeYGov-8yx@?;j
z;<~EWL{g9IxQNAX)x#Ot%_<&oS>-GfV_$uEbtlu{gT+zxwQnWgR*Jse^nyiBanA13
z2~r=*Ogm2>_$SmA`TU`@x0Rj~`@=bPOOD*IJ@Bb&(~WIC-;CrJ==cff>EA9sCZp)$
zm!5Nm&+Lxw^+yTzXWC6Njbk#eE^?k5BPpI;5_ybec73nMf_vE!rrJ9e+>5tWI~LLX
zaME6>yRR-~dn{1ee8s!%&KmzB$>Q+6GXj!sdak(km#v0JX07(C#~WrA$Qp3{Shnr6
a{r<^J$AW!7?qFbGVDNPHb6Mw<&;$T-7kZ%p

literal 0
HcmV?d00001

diff --git a/contrib/mobile/Android/res/drawable-ldpi/ic_launcher.png b/contrib/mobile/Android/res/drawable-ldpi/ic_launcher.png
new file mode 100644
index 0000000000000000000000000000000000000000..09e5479ac7176a8f71b9337c950a52db986e0179
GIT binary patch
literal 384
zcmeAS@N?(olHy`uVBq!ia0y~yU@!n-4mJh`hH$2z?F<YIY)RhkE)4%caKYZ?lNlHo
zI14-?iy0V%3PG6h^PQ?b1_lQ95>H=O_DkH{3<AP``#(uDFfj6Zx;TbZ%y~Q0TIjF>
z538%%cQ?D8L3?XDd|5nhFm7ASm{}fUDPa89*!=uyRX4@7k2QyL89P6k?szP;j<xE+
zrUUJ@4?+?}J#KF0m(g0o^giV+^JA{n3;{RU+eE_{7dibtu;P$bK&re%$c)_%lWQ+T
zB;I3E`{wA}YRNt07W-7uXW9>v<U>MctZrCc8xWB=k16&|a}!sw$crp_4eg%z2O_^6
z0u$dbEx*NXuhkR%K<Jy}vO_ai^-|?!LL}B7P<`7xmn&Ix$Cla&Av>b)@6V0?B$s}E
zEz6&k`5Wi+tzDWa`OG0CazWXH_mURX*91BuQ}1VG=&nkgaX7K@9`o{y*DQj9i$1gK
hv2xqmKdOJqn5@^|xafn-76t|e22WQ%mvv4FO#m(cll=ey

literal 0
HcmV?d00001

diff --git a/contrib/mobile/Android/res/drawable-mdpi/ic_action_search.png b/contrib/mobile/Android/res/drawable-mdpi/ic_action_search.png
new file mode 100644
index 0000000000000000000000000000000000000000..134d5490bd3310559cc944d44d24857eef29f2a1
GIT binary patch
literal 3030
zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I7G?$phQ^Te;|vT8oCO|{#S9GGLLkg|>2BR0
z1_mzwOlRkSfQ<Z-{NjxK0tHWJXN7{I{ItxRR0f8MTXTccLxNw5*?zzG#mT#)VTyNt
zkSK>jkW+Vq$V4?QMNR>)4#kBxMFS5Cy1KGRpIFer+}GF8BO0i~)5Udz{fXkDzUIXp
zU8jCOtX`abZO`{-Xa8-zZufl6=ee8DvmfB#ndV^}XxhND(n(J6LG$q=#~wb>b7<sJ
zDPR!b*qowR{8yQg;YXc~jkeMO_I(VD6_>d=7!LT(K42iz{-6Jq)65vgh8D&HB@->Y
zIT}P59IE=9mN7WEF*eMdp%%=rfQ2F9baK*Th5%iL1oir7ml+!7{+L<K$Phh6QIv7P
zL<R-n)D9Ph3~Pop=fk>O86pfAMAE#ESTfwuWiapzPxD~du$|$+IRWlX3>-WR27w)|
znhY$}3<)Qcl`9xpW-^GleG0evsJ%|$xfTOM#mr4MJ5?-Q8>2aN3)#cN_2e|pd5UX`
zm?bhL&T`N@R5?@9sL_P~!RIp!3=1ZT3O;E5{I}v9-@0?>%=)(R#p}M>&-Py_De3XQ
zr{`A}I503gEUCNrPe*^VRD(5JL+-yts_$4b;<y)-e(z4(#P6_`VZqB=;hzgYVdJ`R
z!p@sFpFVkV!|RAsbmFP-+JEVX;tz!X&G}hp^XL252m2nWG#bS=y0iRvaOlhzpQSSA
zCvmnU-FepU{%1S)|39*qm5z8O?TpY8c^oKI*yl2<=d;mLrB0_wnnzVH{ZDyxU*|Wo
z-F;Jr4Ow=K)f07B#3nO;^Hvv#C^_)xI|IX~-T4QvXmBt$WHdiKU;h8S{a^P5stgTj
zo|6h07~))1^g>Q;wm;6nz~Hi=QEP*v^p}GYItSQf4zk`k$o(h5ti?&?$RQ^IC$5wR
znW6;EHBC+$ZD%*gY9;7jaga4R5SY<6xqwgaQ0NXm+XDVyi5&9|YV2v`WN|#fA)Kgq
ztAjDAD?+)CLwsiI55<EXEJEEX3MV^60+qZcntB)pb%iK|ddPmVEn>24k8#^I(fR~~
zQPZEcJ?@568aD;nUg6p5ymN)QREygp?h7d;hO_#`7R<g-v_;Cc$86#A3#&8uZ}r<b
zA2&GgLW14+NRENtvBORqEp#|1C!gM^w1#K(F{uq<YnXR;eoa2Vv7AMy(e(hQ8B4j7
zLZY0bM}$v=-wlry3Nk7tg10!$Ihk7m52-6nUg5n(ZI|HBBN9nQhV2m^I?C6C`i1oc
zsym#In5zhNIvc6)oWSI{aY@J}p-XO;@`99K>a3h?;vuCx`Q)vX>`m;JQ*;!xPqaRn
z`{eKw<0sNj6hB3C%}sJBT=FCMkw(y|EHBBY0#8kzvZc;2atvKOE9mZug&~5b{ZUS9
z7j6q$AK1P^*rarp<=JL2Pw%B`7frn^l_8$-J#+nwl3jv#r^@+FzYu=u^h@^_(_b)u
zDd*vB6Ky`;k**;*TY_C8U9wza{S2RFl9#(BkB1nT8@`_Ld?x?Q{Ll!kZCW*=6HjqX
z^_r?SRa#3wWaX-5tM0Ah4*eW@I;4MPTyX6=w@~BY$16FnOj{kgYHq;mVCmrWmDVfT
zSEaAW53yfT7x}l7E%LC>VSnc(feSXqKi+dpfje1pbA^s#Ht*`T(nixGY8%hqtSQsl
zJ>#$J?rz&vD;HWi8+#dtZw~rACC#4w@r=SBb4vU;pKC0i{<*H}p2&O6N1D>hOni14
zrp9Einl^n}#A=V#fveqL?=@TZcKO_8dtG-&{%+)RJnp3)qwb#Ge~xwT^WdAocb9W5
z7xT5X`npbURrXTpg}YtK_vbBtH)GzuxQ2N?`OEKB?tT7CrdI!N$lu&w%fGtwM6hk<
zQDM8yb56qMsA*xojjaCh+aCj+V-GtxFHM}9IQ?PE#GMyy7GHJib>r{JJQnj<<#Fz@
z++&N?*whr&ynSE!zMB=~yK|Z5GHV}epW|oGoLzMG+Dy~gwuaY@p3i<h`}*wr+Y_QH
zqI9;c*tR3pbJLTkWs&c;?a6D6vW#3B5gHY{*=_CIwW`;4uid>|aQRNZ$$qQnT}wZ_
z;p4WG+g5Iu-0<`U+wFDRa<|ncrYDJ~Z$G;3@Vm)-C)e((?fq-Z&f9*IZ?$ZcY+dn|
zA`z=Ft9!G~&3R{Ed-Th+m-^`u=LOE+Fn+vE__XGc%(=m{FT1CUr|&Fo{@l^s>D_c%
zZ@Qh{Z0TcnPwai-Rr0kk_F>hfuXAT_o_*-;ireeonZ3(=*M4XI8I$>%^CFFlFC0GM
z{2=h@MSJe~Qw_53uc`BQ_HRtz`dnE*S$|^q+Upy(FD+m7J@LJ`-8Z|U`H$@$+nC=o
zx)&LL#{9tc6WdSwAI_f_-+JG<Uip8@|Em8N8J0JwGNv<kHaa#&GyVQiRin7S&)({G
z>bFfd-#Ydz*y$+h*x$6a>FL3>iWw)~OjxV<{rQY@6VGMxwFcC^xORa(@mXT`;W{4m
z*7nx$Hv7JUjtHrXhSN>UFWzx3zVGtOWtz*q+3AM<mg{xBOttJ*>1Em6GT&vg%l?>N
zTI89l5pyFvbG&6N^|aQR<>l<V|L5)J_D6FcaX+pWpP_#uwxDw1xkF!Cmy4~`6VkDo
z=HS!eXEEi2qkz^5u^!b=!sV)cT$P7p52Y*VUo^Yeal<)AOV00;hn8>Eq&E}ym{zJB
zHD0RobZ3kD$_aaXczy29wwfn4t4tx+$kuAFVe_Pk6AGPHDf&*{mi{XJSz6iYHL0ze
z{vFNh-mWh<mHlM)<_T+9BXzm9IW2n;5~Xoni+xjiYIxfIvz@0br>&l+efI5{&8Kcp
zFrV{&{{Oc^hlCzZ+P1XKJ6u;b;@RFcS(ck@3M+4OJr-rvZVO{uW3!`cn^x{s|J859
zr?0Eqt5)Tk-57W9RMWw&jM=ZbL%E)|*1o=T{cWs&gns1xt%<+d=1SX%c6O~3xh+0j
zwEl+1or<T@?fIwn&%85b%gWV9cBY(9yOj3w**)EP(R|ZZO@B6>FOT=;tu4Iw!?wKr
z`pxyW{`9jNw|6&hbKbdlzs-(4smo8EJ8NwpvLxh7$gdEycbD#NO}zdi@8Ub@>OJ2~
z-dw#Mz32O1yOaBFhcbrxUQN52`rGsO=I{3FI#<2?G3|G5>{`Fv!nennFERgRSLWMx
zedm>{vX^W_g8Hv%zjo(4F2C>J-1p_Wyk@+iy>pH|QZ8_*eDd-;=l$<;yjHi$daBnv
zWWOw5CYvs+pXD^`(=4~y!LxoxCq?h_KVx_C+N*n2f81}&^UpD{iLCVc9C9-A*2|{L
zlhZ$)@0mMwZf%|3&pQdX7j3J4o_y|p7JvTxT>>Q!FS-8jer~<T`drMX9VMSO-F_+@
zz9W3rdaL-{S0%4({!PB@e|-0x-Luy1jLF{lu4?br>a_1KrRSNSyZdEt<wvpq*RIa9
zw7t9cb5;KLqu;;Y7rR?mr2hBZ>D@QW)!(h%<G&~Vi^E&To6dLJui8idyL03Ho%*Z;
z<qJMvyyO0zt+o05zlmS_`JGw&XZD|N<86CA&%(~q@{xVf-<N-uJD*QEuQpHo-=cq~
z*NKbi*ZsKq`ue$xGcGQi{%QK;{kb(u|Gql#T5|pEV~38(?K@dvY#8???DyM)<#)<u
z-!Hz;@BgGmp<d&E#?OskgD))qJy~+{<o_(pGd}-GHrBljYJ4Vp1o<*BRH-sBG&D0X
z{QS?r(D0Ihq11qZ;Z*_ygVhWM2J!q!@kiYl7#Iu!d_r9RlL-9Q?{HvXU=Sz?@(X6*
zl~OZy@J%aj=$*A}^MNxLXRVE6U|?A3>EaloaXvX=fmDFQ)2uuH>th)@&wu-O{@#E8
zi7cP$wG1-;`Zs)@dEm_-_X5Us?-M?$$2j~`jJRvRqv1c3LFqjPy#R(~->eU?sx9Dr
z5zi3({$bjO8s^>a#1Ad}?_js_cT>U3U+N0a<6SsB{@TYC{`)U4+~V=>|Nr{K|NhT!
z5HQp>PFV5(zp!b*tH3D?jrZzJRL{Ks|G(TpaO3a)_ZfUSXRYLU#>r#C#Gtam_UixU
Snym~B3=E#GelF{r5}E+zcf7>_

literal 0
HcmV?d00001

diff --git a/contrib/mobile/Android/res/drawable-mdpi/ic_launcher.png b/contrib/mobile/Android/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000000000000000000000000000000000000..286d27e00068fb04f4dd541a4daa9b5a28cebd99
GIT binary patch
literal 614
zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4rT@hhPm4t-!L#Ru%tWsIx;Y9?C1WI$jZRL
z@H4<C#PvTIFfcIOzkk1>p+P}G;oG;jZ{Oa2{`~yq%e(K~*>T~*f)giZ{Q2|q=g-gI
zzrTO<=;*m~a}FG6`26|#g9it$Tv>7A#DrI`u3o#g=IGI`Lx);^|Nj2<>+ARL@87$(
z=ggTI&z_yVabv^z^Ye}!>-q5E;lqcA|NZ;><HyIBFE3xcy6W-c<A)Eo&6v>;6XW9H
zVPIyaA}uYnVMD`=85t8MB;@3HOq-Sx9&RNeAs{5g!^z3EVnsnqOGH9~gNlm8u3a@7
zH<s1ah1lC`&6$&tmgZt$pdcqF!o$O{Ze7Xb$w?Iz0p8w5y1H^vQ8tZ@VNOmuqN04v
z%uFF67TdR1g+6>WkAZ=Ku_VYZn8D%MjWiG^$=lt9p@UV{gMop8v%n*=n1Mkk7lauT
z_dhjeU|?V`@$_|Nzr@YWAjWhswKSiBf#I5`i(^Q|oTHaLg$@}AIA1(*^zV5e!BY))
zgQ^1<-u}P+(qf;@6nkcek1XN`m<w3M4+!57k6{qKAsWMwpWt7>Si@x9#Jzy^8mqVi
z{~9j6297nHdJJr9IP@6!&T#87u%6-4W8gi*sn@_WLokNH(m*U`!Fy%{p%{fPf+twT
zJ8T(^4zhZjXVBfj@LF>Li}(Ut_8kwH_J}hGx~y-|*wOGx^#Zq^LN)IcZ^pao4m$-V
ze0_T-!sF2{5s9Nx3mN)%3jW@r=D~dCi0!9W;g8rX8|UtldU$pJeOW0}-j_T6cRprd
PU|{fc^>bP0l+XkKUV{iJ

literal 0
HcmV?d00001

diff --git a/contrib/mobile/Android/res/drawable-mdpi/model.png b/contrib/mobile/Android/res/drawable-mdpi/model.png
new file mode 100644
index 0000000000000000000000000000000000000000..3a71677c81cae0c5bad62b5baa29b1c6001982e9
GIT binary patch
literal 1116
zcmeAS@N?(olHy`uVBq!ia0y~yU<d$V4mJh`hCabhYZ(|A*pj^6T^Rm@;DWu&Co?cG
za29w(7Beu2ECpf4A62<33=9nHC7!;n>~}Z?Mdej5=*_ofU|@df>EaktaqI1^v-#4l
z5^Nuy&%9Y<k=r%dNk~JJl|{?d$;(G$@0Tmi-A7oTFrQ*PDgQfP;U7=V^G6;WCxyZt
z9yLv<Vo2iN%B0G^>R48kl4;)^vzs*)aePaHZsr{|>z#X}w*L6WJ<0Y}-|tFRGc27F
z<fVyBSY4_Ju{-hRP0s%Z4<1NgyA|%5GABjofT7^a`@iShR@u(L!f?$cW$KeG0hX^t
zJ8RzW<TaRndah!n+<|D7w{`0jm9&*MxqOP+7!gyg$8;ve=<&5%r&Z3&TrqWZ@zC2A
zwRUxJaq(Bb8vgeNhfY8LEI(-v%K^Cz(+MmE*P^P$4otTdPq3PsW;F9p$CKawD;CHy
zlroqzT$x+Uzis<=bD>U`4Lf&c3U?lHSbfzhv8S^0i8jMMmV!?P(E;wvK5CPvFFqtZ
zF?Z7boZQ@4-RY-i`&aB{-oX68u0fPx|NE~O3?~_@+-JUUe>4BY7(Mgco}U&<d!kkL
zYl?7vpTBYWx9IHi%sV_TX^U{l?rhCfSNm97-|{5=;ZK*8iBGP#Iw@9Mv&`BWwK{68
zp1;3;JhMU6+OYNCeORA;{%LZuc;Sb4Y>pqU{`vFA&s=}WUcQj~5)B0vd<VAQm6Kzb
zQRc6p6zG4)zWeASFa4aSx1<uR=BhQ6D?9z&8vgB2E^k3a#Sf8_3j->8gI1OVGxro1
zCi}Vb=zqVo-Y}PU!V{M($KsiL@=X?L<!3j1)Gn~F*|vN4?uCrU;t%oIZChBX_hKo-
zUbFCo_#+?oF@351-@UxnU;W!*wpSka5B29>wK*?+h2in-t{08Aq6xd}eKMFN_`V)h
zWGLs~HUI5$_cCYJb*^ie)xU`Kz4tqELzCBF-_wqzXP2-^T>kazm#!e^e@~NHXVd(%
z8w^9VL=`J-7xACVXfU*VUe_&Q_x$(27B&gzl_6206YZU9FEISL^1ardxo5ljKf(Y1
zH2<v-cYQLs#OiHk!~gvpc^xPC1rP3<?4xFX{%O(iU8WAVS9Y$t`s!_nmZ?Y_`y?Ai
zg{fXke=S?K?A?{Dt#_C2%u|~zIe+HNolFTje{LN*bjbhizNx?a-4=iRd*Va~>jbV=
z3x)@a44*Z<|9x7i=&)tD_(b-3&vSKjby+7*o_z1X0f+s??{;kcrqVE-agT4&8w2eR
z0q59%?W=cm(R*v_!#Ahn5ATEBNgFFRt247S)Y#ecJ>WWdozGy0+R6FSy~muE22Gr|
z_JDip=9|}h4doN&yVtlbVNJMb8J=r4yS`LwhqCYkXMX;f(#dL`ecdOx8Tux_5f)@#
zu(kZeAGwCMjx|=#U!6@W-WjyA<gcVOaxM$<+IrP~&()OEhUN9=85kHCJYD@<);T3K
F0RSep{C@xd

literal 0
HcmV?d00001

diff --git a/contrib/mobile/Android/res/drawable-mdpi/param.png b/contrib/mobile/Android/res/drawable-mdpi/param.png
new file mode 100644
index 0000000000000000000000000000000000000000..0103c21fe2a6bbcd3e59fa6f3ca9503cfc367e60
GIT binary patch
literal 3371
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

literal 0
HcmV?d00001

diff --git a/contrib/mobile/Android/res/layout/list_header.xml b/contrib/mobile/Android/res/layout/list_header.xml
new file mode 100644
index 0000000000..bf26b6dcbd
--- /dev/null
+++ b/contrib/mobile/Android/res/layout/list_header.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+	android:id="@+id/list_header_title"
+	android:layout_width="fill_parent"
+	android:layout_height="wrap_content"
+	android:paddingTop="2dip"
+	android:paddingBottom="2dip"
+	android:paddingLeft="5dip"
+	style="?android:attr/listSeparatorTextViewStyle"
+	>
+    
+
+</TextView>
\ No newline at end of file
diff --git a/contrib/mobile/Android/res/layout/model.xml b/contrib/mobile/Android/res/layout/model.xml
new file mode 100644
index 0000000000..9301369f01
--- /dev/null
+++ b/contrib/mobile/Android/res/layout/model.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="horizontal" >
+
+    <ImageView
+        android:id="@+id/icone"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:contentDescription="icone"
+        android:src="@drawable/ic_launcher" />
+
+    <LinearLayout
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent"
+        android:orientation="vertical" >
+
+        <TextView
+            android:id="@+id/titre"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textAppearance="?android:attr/textAppearanceLarge"
+            android:textColor="#ffffff" />
+
+        <TextView
+            android:id="@+id/description"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:textColor="#ffffff" />
+
+    </LinearLayout>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/contrib/mobile/Android/res/raw/bh_pro b/contrib/mobile/Android/res/raw/bh_pro
new file mode 100644
index 0000000000..1458d87c83
--- /dev/null
+++ b/contrib/mobile/Android/res/raw/bh_pro
@@ -0,0 +1,59 @@
+Function{
+  // nu = 100. + 10. * exp ( 1.8 * b * b )
+  // analytical
+  nu_1a[] = 100. + 10. * Exp[1.8*SquNorm[$1]] ;
+  dnudb2_1a[] = 18. * Exp[1.8*SquNorm[$1]] ;
+  h_1a[] = nu_1a[$1]*$1 ;
+  dhdb_1a[] = TensorDiag[1,1,1] * nu_1a[$1#1] + 2*dnudb2_1a[#1] * SquDyadicProduct[#1]  ;
+  dhdb_1a_NL[] = 2*dnudb2_1a[$1] * SquDyadicProduct[$1]  ;
+
+  // interpolated
+  Mat1_h = {
+    0.0000e+00, 5.5023e+00, 1.1018e+01, 1.6562e+01, 2.2149e+01, 2.7798e+01, 3.3528e+01,
+    3.9363e+01, 4.5335e+01, 5.1479e+01, 5.7842e+01, 6.4481e+01, 7.1470e+01, 7.8906e+01,
+    8.6910e+01, 9.5644e+01, 1.0532e+02, 1.1620e+02, 1.2868e+02, 1.4322e+02, 1.6050e+02,
+    1.8139e+02, 2.0711e+02, 2.3932e+02, 2.8028e+02, 3.3314e+02, 4.0231e+02, 4.9395e+02,
+    6.1678e+02, 7.8320e+02, 1.0110e+03, 1.3257e+03, 1.7645e+03, 2.3819e+03, 3.2578e+03,
+    4.5110e+03, 6.3187e+03, 8.9478e+03, 1.2802e+04, 1.8500e+04, 2.6989e+04, 3.9739e+04,
+    5.9047e+04, 8.8520e+04, 1.3388e+05, 2.0425e+05, 3.1434e+05, 4.8796e+05, 7.6403e+05
+  } ;
+  Mat1_b = {
+    0.0000e+00, 5.0000e-02, 1.0000e-01, 1.5000e-01, 2.0000e-01, 2.5000e-01, 3.0000e-01,
+    3.5000e-01, 4.0000e-01, 4.5000e-01, 5.0000e-01, 5.5000e-01, 6.0000e-01, 6.5000e-01,
+    7.0000e-01, 7.5000e-01, 8.0000e-01, 8.5000e-01, 9.0000e-01, 9.5000e-01, 1.0000e+00,
+    1.0500e+00, 1.1000e+00, 1.1500e+00, 1.2000e+00, 1.2500e+00, 1.3000e+00, 1.3500e+00,
+    1.4000e+00, 1.4500e+00, 1.5000e+00, 1.5500e+00, 1.6000e+00, 1.6500e+00, 1.7000e+00,
+    1.7500e+00, 1.8000e+00, 1.8500e+00, 1.9000e+00, 1.9500e+00, 2.0000e+00, 2.0500e+00,
+    2.1000e+00, 2.1500e+00, 2.2000e+00, 2.2500e+00, 2.3000e+00, 2.3500e+00, 2.4000e+00
+  } ;
+  Mat1_b2 = {
+    0.0000e+00, 2.5000e-03, 1.0000e-02, 2.2500e-02, 4.0000e-02, 6.2500e-02, 9.0000e-02,
+    1.2250e-01, 1.6000e-01, 2.0250e-01, 2.5000e-01, 3.0250e-01, 3.6000e-01, 4.2250e-01,
+    4.9000e-01, 5.6250e-01, 6.4000e-01, 7.2250e-01, 8.1000e-01, 9.0250e-01, 1.0000e+00,
+    1.1025e+00, 1.2100e+00, 1.3225e+00, 1.4400e+00, 1.5625e+00, 1.6900e+00, 1.8225e+00,
+    1.9600e+00, 2.1025e+00, 2.2500e+00, 2.4025e+00, 2.5600e+00, 2.7225e+00, 2.8900e+00,
+    3.0625e+00, 3.2400e+00, 3.4225e+00, 3.6100e+00, 3.8025e+00, 4.0000e+00, 4.2025e+00,
+    4.4100e+00, 4.6225e+00, 4.8400e+00, 5.0625e+00, 5.2900e+00, 5.5225e+00, 5.7600e+00
+  } ;
+  Mat1_nu = {
+    1.1005e+02, 1.1005e+02, 1.1018e+02, 1.1041e+02, 1.1075e+02, 1.1119e+02, 1.1176e+02,
+    1.1247e+02, 1.1334e+02, 1.1440e+02, 1.1568e+02, 1.1724e+02, 1.1912e+02, 1.2139e+02,
+    1.2416e+02, 1.2752e+02, 1.3165e+02, 1.3671e+02, 1.4297e+02, 1.5076e+02, 1.6050e+02,
+    1.7275e+02, 1.8829e+02, 2.0810e+02, 2.3356e+02, 2.6651e+02, 3.0947e+02, 3.6589e+02,
+    4.4056e+02, 5.4014e+02, 6.7397e+02, 8.5528e+02, 1.1028e+03, 1.4436e+03, 1.9164e+03,
+    2.5777e+03, 3.5104e+03, 4.8366e+03, 6.7381e+03, 9.4870e+03, 1.3494e+04, 1.9385e+04,
+    2.8118e+04, 4.1172e+04, 6.0854e+04, 9.0779e+04, 1.3667e+05, 2.0764e+05, 3.1835e+05
+  } ;
+
+  Mat1_nu_b2  = ListAlt[Mat1_b2, Mat1_nu] ;
+  nu_1[] = InterpolationLinear[$1]{List[Mat1_nu_b2]} ;
+  dnudb2_1[] = dInterpolationLinear[$1]{List[Mat1_nu_b2]} ;
+  h_1[] = nu_1[(SquNorm[$1])] * $1 ;
+  dhdb_1[] = TensorDiag[1,1,1] * nu_1[SquNorm[$1]#1] + 2*dnudb2_1[#1] * SquDyadicProduct[$1]  ;
+}
+
+
+
+
+
+
diff --git a/contrib/mobile/Android/res/raw/machine_magstadyn_a_pro b/contrib/mobile/Android/res/raw/machine_magstadyn_a_pro
new file mode 100644
index 0000000000..f58a22b84a
--- /dev/null
+++ b/contrib/mobile/Android/res/raw/machine_magstadyn_a_pro
@@ -0,0 +1,938 @@
+Group {
+  DefineGroup[ DomainM, DomainB, DomainS ];
+  DefineGroup[ DomainL, DomainNL, Dummy ];
+  DefineGroup[ Rotor_Inds, Rotor_IndsP, Rotor_IndsN, Rotor_Magnets, Rotor_Bars ];
+  DefineGroup[ Surf_bn0, Rotor_Bnd_MBaux] ;
+  DefineGroup[ Resistance_Cir, Inductance_Cir, Capacitance_Cir, DomainZt_Cir, DomainSource_Cir ];
+}
+
+Function{
+
+  DefineConstant[ Flag_Cir, Flag_NL, Flag_ParkTransformation ];
+  DefineConstant[ Term_vxb ];
+  DefineConstant[ AxialLength        = {1, Visible 0},
+                  FillFactor_Winding = {1, Visible 0},
+                  Factor_R_3DEffects = {1, Visible 0},
+                  SymmetryFactor     = {1, Visible 0} ];
+
+  Flag_Symmetry = (SymmetryFactor==1) ? 0 : 1 ;
+
+  DefineConstant[ Nb_max_iter        = {20, Visible 0},
+                  relaxation_factor  = {1, Visible 0},
+                  stop_criterion     = {1e-5, Visible 0},
+                  reltol             = {1e-7, Visible 0},
+                  abstol             = {1e-5, Visible 0} ];
+
+  DefineConstant[ II, VV, pA, pB, pC, Ie, ID, IQ, I0 ];
+  DefineFunction[ br, js, Resistance, Inductance, Capacitance ];
+  DefineFunction[ Theta_Park, Theta_Park_deg, RotorPosition, RotorPosition_deg ] ;
+
+
+  DefineConstant[ Flag_SrcType_Rotor = {0, Visible 0} ];
+
+  DefineConstant[ Clean_Results = { 1, Choices {0,1},
+    Label "Remove previous result files",
+    Path "Input/1", Visible 1 } ] ;
+
+  DefineConstant[ Flag_SaveAllSteps = {0, Label "Save all time steps",
+      Path "Input/0", Choices {0,1}} ];
+
+  DefineConstant[ my_output={"Output/40T_rotor", Visible 0}];
+
+}
+
+Include "bh.pro"; // nonlinear BH caracteristic of magnetic material
+
+Group {
+
+  Inds = Region[ {Stator_Inds, Rotor_Inds} ] ;
+
+  DomainB = Region[ {Inds} ] ;
+  DomainM = Region[ {Rotor_Magnets} ] ;
+
+  Stator  = Region[{ StatorC, StatorCC }] ;
+  Rotor   = Region[{ RotorC,  RotorCC }] ;
+
+  Rotor_Moving = Region[{ Rotor, Rotor_Air, Rotor_Airgap, Rotor_Inds, Rotor_Bnd_MBaux} ] ; // Use in ChangeOfCoordinates
+
+  MB  = MovingBand2D[ MovingBand_PhysicalNb, Stator_Bnd_MB, Rotor_Bnd_MB, SymmetryFactor] ;
+  Air = Region[{ Rotor_Air, Rotor_Airgap, Stator_Air, Stator_Airgap, MB } ] ;
+  Inds = Region[{ Rotor_Inds, Stator_Inds } ] ;
+
+  DomainV = Region[{}]; // Speed considered either with term v/\b
+  If(Term_vxb) // or not dynamics in time domain + mechanics
+    DomainV = Region[{ RotorC }];
+  EndIf
+
+  DomainCC = Region[{ Air, Inds, StatorCC, RotorCC }];
+  DomainC  = Region[{ StatorC, RotorC }];
+  Domain  = Region[{ DomainCC, DomainC }] ;
+
+  If(Flag_NL)
+    DomainNL = Region[ {Stator_Fe, Rotor_Fe } ];
+    DomainL  = Region[ {Domain,-DomainNL} ];
+  EndIf
+
+  DomainKin = #1234 ; // Dummy region number for mechanical equation
+  DomainDummy = #12345 ; // Dummy region number for mechanical equation
+}
+
+Function {
+  mu0 = 4.e-7 * Pi ;
+
+  sigma_al = 3.72e7 ; // conductivity of aluminum [S/m]
+  sigma_cu = 5.9e7  ; // conductivity of copper [S/m]
+
+  nu [#{Air, Inds, Stator_Al, Rotor_Al, Stator_Cu, Rotor_Cu, Rotor_Magnets, Rotor_Bars}]  = 1. / mu0 ;
+
+  If(!Flag_NL)
+    nu [#{Stator_Fe, Rotor_Fe }]  = 1 / (mur_fe * mu0) ;
+  EndIf
+  If(Flag_NL)
+   nu [#{Stator_Fe, Rotor_Fe }] = nu_1a[$1] ;
+  EndIf
+  dhdb_NL [ DomainNL ] = dhdb_1a_NL[$1];
+
+  sigma[#{Rotor_Fe}] = sigma_fe ;
+  sigma[#{Rotor_Al, Stator_Al}] = sigma_al ;
+  sigma[#{Rotor_Cu, Stator_Cu}] = sigma_cu ;
+  sigma[#{Inds}] = sigma_cu ;
+
+  rho[] = 1/sigma[] ;
+
+  Rb[] = Factor_R_3DEffects*AxialLength*FillFactor_Winding*NbWires[]^2/SurfCoil[]/sigma[] ;
+  Resistance[#{Stator_Inds, Rotor_Inds}] = Rb[] ;
+
+  T = 1/Freq ; // Fundamental period in s
+
+  Idir[#{Stator_IndsP, Rotor_IndsP}] =  1 ;
+  Idir[#{Stator_IndsN, Rotor_IndsN}] = -1 ;
+
+  // Functions for Park transformation
+  Idq0[] = Vector[ ID, IQ, I0 ] ;
+  Pinv[] = Tensor[ Sin[Theta_Park[]],        Cos[Theta_Park[]],        1,
+                   Sin[Theta_Park[]-2*Pi/3], Cos[Theta_Park[]-2*Pi/3], 1,
+                   Sin[Theta_Park[]+2*Pi/3], Cos[Theta_Park[]+2*Pi/3], 1 ];
+
+  P[] = 2/3 * Tensor[ Sin[Theta_Park[]], Sin[Theta_Park[]-2*Pi/3], Sin[Theta_Park[]+2*Pi/3],
+                      Cos[Theta_Park[]], Cos[Theta_Park[]-2*Pi/3], Cos[Theta_Park[]+2*Pi/3],
+                      1/2, 1/2, 1/2 ] ;
+
+  Iabc[]     = Pinv[] * Idq0[] ;
+  Flux_dq0[] = P[] * Vector[#11, #22, #33] ;
+
+  If(Flag_ParkTransformation)
+    II = 1 ;
+    IA[] = CompX[ Iabc[] ] ;
+    IB[] = CompY[ Iabc[] ] ;
+    IC[] = CompZ[ Iabc[] ] ;
+  EndIf
+  If(!Flag_ParkTransformation)
+    IA[] = F_Sin_wt_p[]{2*Pi*Freq, pA} ;
+    IB[] = F_Sin_wt_p[]{2*Pi*Freq, pB} ;
+    IC[] = F_Sin_wt_p[]{2*Pi*Freq, pC} ;
+
+    js[PhaseA] = II * NbWires[]/SurfCoil[] * IA[] * Idir[] * Vector[0, 0, 1] ;
+    js[PhaseB] = II * NbWires[]/SurfCoil[] * IB[] * Idir[] * Vector[0, 0, 1] ;
+    js[PhaseC] = II * NbWires[]/SurfCoil[] * IC[] * Idir[] * Vector[0, 0, 1] ;
+  EndIf
+
+  Velocity[] = wr*XYZ[]/\Vector[0,0,1] ;
+
+  // Maxwell stress tensor
+  T_max[] = ( SquDyadicProduct[$1] - SquNorm[$1] * TensorDiag[0.5, 0.5, 0.5] ) / mu0 ;
+  T_max_cplx[] = ( TensorV[CompX[$1]*Conj[$1],CompY[$1]*Conj[$1],CompZ[$1]*Conj[$1]] - $1*Conj[$1] * TensorDiag[0.5, 0.5, 0.5] ) / mu0 ; // Check if valid
+
+
+  AngularPosition[] = (Atan2[$Y,$X]#7 >= 0.)? #7 : #7+2*Pi ;
+
+  RotatePZ[] = Rotate[ Vector[$X,$Y,$Z], 0, 0, $1 ] ;//Watch out: Do not use XYZ[]!
+
+  // Kinematics
+  Inertia = 8.3e-3 ; //87
+  Friction[] = 0 ;
+
+  Fmag[] = #55 ; // Computed in postprocessing
+}
+
+//-------------------------------------------------------------------------------------
+
+Jacobian {
+  { Name Vol; Case { { Region All ; Jacobian Vol; } } }
+}
+
+Integration {
+  { Name I1 ; Case {
+      { Type Gauss ;
+        Case {
+          { GeoElement Triangle   ; NumberOfPoints  6 ; }
+	  { GeoElement Quadrangle ; NumberOfPoints  4 ; }
+	  { GeoElement Line       ; NumberOfPoints  13 ; }
+        }
+      }
+    }
+  }
+}
+
+//-------------------------------------------------------------------------------------
+
+Constraint {
+
+  { Name MVP_2D ;
+    Case {
+      { Region Surf_Inf ; Type Assign; Value 0. ; }
+      { Region Surf_bn0 ; Type Assign; Value 0. ; }
+
+      If(Flag_Symmetry)
+        { Region Surf_cutA1; SubRegion Region[{Surf_Inf,Surf_bn0}]; Type Link;
+          RegionRef Surf_cutA0; SubRegionRef Region[{Surf_Inf,Surf_bn0}];
+          Coefficient (NbrPoles%2)?-1:1 ; Function RotatePZ[-NbrPoles*2*Pi/NbrPolesTot]; }
+        { Region Surf_cutA1; Type Link; RegionRef Surf_cutA0;
+          Coefficient (NbrPoles%2)?-1:1 ; Function RotatePZ[-NbrPoles*2*Pi/NbrPolesTot]; }
+
+        //For the moving band
+        For k In {1:SymmetryFactor-1}
+        { Region Rotor_Bnd_MB~{k+1} ; SubRegion Rotor_Bnd_MB~{(k!=SymmetryFactor-1)?k+2:1}; Type Link;
+          RegionRef Rotor_Bnd_MB_1; SubRegionRef Rotor_Bnd_MB_2;
+          Coefficient ((NbrPoles%2)?-1:1)^(k); Function RotatePZ[-k*NbrPoles*2*Pi/NbrPolesTot]; }
+        EndFor
+
+      EndIf
+    }
+  }
+
+  { Name Current_2D ;
+    Case {
+      If(Flag_SrcType_Stator==1)
+        { Region PhaseA     ; Value II*Idir[] ; TimeFunction IA[]; }
+        { Region PhaseB     ; Value II*Idir[] ; TimeFunction IB[]; }
+        { Region PhaseC     ; Value II*Idir[] ; TimeFunction IC[]; }
+      EndIf
+      If(Flag_SrcType_Rotor==1)
+        { Region Rotor_Inds ; Value Ie*Idir[] ; }
+      EndIf
+    }
+  }
+
+  { Name Voltage_2D ;
+    Case {
+      { Region RotorC  ; Value 0. ; } // Not needed if Global equation not in formulation
+      { Region StatorC ; Value 0. ; } // Not needed if Global equation not in formulation
+    }
+  }
+
+  { Name Current_Cir ;
+    Case {
+      If(Flag_Cir && Flag_SrcType_Stator==1)
+        { Region Input1  ; Value II  ; TimeFunction IA[]; }
+        { Region Input2  ; Value II  ; TimeFunction IB[]; }
+        { Region Input3  ; Value II  ; TimeFunction IC[]; }
+      EndIf
+    }
+  }
+
+  { Name Voltage_Cir ; // Example induction machine
+    Case {
+      If(Flag_Cir && Flag_SrcType_Stator==2 && !Flag_NL)
+        { Region Input1  ; Value VV  ; TimeFunction IA[]; }
+        { Region Input2  ; Value VV  ; TimeFunction IB[]; }
+        { Region Input3  ; Value VV  ; TimeFunction IC[]; }
+      EndIf
+      If(Flag_Cir && Flag_SrcType_Stator==2 && Flag_NL)
+        { Region Input1  ; Value VV  ; TimeFunction IA[]*Frelax[]; }
+        { Region Input2  ; Value VV  ; TimeFunction IB[]*Frelax[]; }
+        { Region Input3  ; Value VV  ; TimeFunction IC[]*Frelax[]; }
+      EndIf
+    }
+  }
+
+
+  //Kinetics
+  { Name CurrentPosition ;
+    Case {
+      { Region DomainKin ; Type Init ; Value 0.#66 ; }
+    }
+  }
+
+  { Name CurrentVelocity ;
+    Case {
+      { Region DomainKin ; Type Init ; Value wr ; } // wr in [0,1200] rad/s
+    }
+  }
+
+}
+
+//-----------------------------------------------------------------------------------------------
+
+FunctionSpace {
+
+  { Name Hcurl_a_2D ; Type Form1P ;
+    BasisFunction {
+      { Name se1 ; NameOfCoef ae1 ; Function BF_PerpendicularEdge ;
+        Support Region[{ Domain, Rotor_Bnd_MBaux }] ; Entity NodesOf [ All ] ; }
+   }
+    Constraint {
+      { NameOfCoef ae1 ; EntityType NodesOf ; NameOfConstraint MVP_2D ; }
+    }
+  }
+
+  // Gradient of Electric scalar potential (2D)
+  { Name Hregion_u_Mag_2D ; Type Form1P ;
+    BasisFunction {
+      { Name sr ; NameOfCoef ur ; Function BF_RegionZ ;
+        Support DomainC ; Entity DomainC ; }
+    }
+    GlobalQuantity {
+      { Name U ; Type AliasOf        ; NameOfCoef ur ; }
+      { Name I ; Type AssociatedWith ; NameOfCoef ur ; }
+    }
+    Constraint {
+      { NameOfCoef U ; EntityType GroupsOfNodesOf ; NameOfConstraint Voltage_2D ; }
+      { NameOfCoef I ; EntityType GroupsOfNodesOf ; NameOfConstraint Current_2D ; }
+    }
+  }
+
+  { Name Hregion_i_Mag_2D ; Type Vector ;
+    BasisFunction {
+      { Name sr ; NameOfCoef ir ; Function BF_RegionZ ;
+        Support DomainB ; Entity DomainB ; }
+    }
+    GlobalQuantity {
+      { Name Ib ; Type AliasOf        ; NameOfCoef ir ; }
+      { Name Ub ; Type AssociatedWith ; NameOfCoef ir ; }
+    }
+    Constraint {
+      { NameOfCoef Ub ; EntityType Region ; NameOfConstraint Voltage_2D ; }
+      { NameOfCoef Ib ; EntityType Region ; NameOfConstraint Current_2D ; }
+    }
+  }
+
+  { Name Hregion_Z ; Type Scalar ; // Circuit equations
+    BasisFunction {
+      { Name sr ; NameOfCoef ir ; Function BF_Region ;
+        Support DomainZt_Cir ; Entity DomainZt_Cir ; }
+    }
+    GlobalQuantity {
+      { Name Iz ; Type AliasOf        ; NameOfCoef ir ; }
+      { Name Uz ; Type AssociatedWith ; NameOfCoef ir ; }
+    }
+    Constraint {
+      { NameOfCoef Uz ; EntityType Region ; NameOfConstraint Voltage_Cir ; }
+      { NameOfCoef Iz ; EntityType Region ; NameOfConstraint Current_Cir ; }
+    }
+  }
+
+  // For use in Mechanical equation
+  { Name Position ; Type Scalar ;
+    BasisFunction {
+      { Name sr ; NameOfCoef ir ; Function BF_Region ;
+        Support DomainKin ; Entity DomainKin ; }
+    }
+    GlobalQuantity {
+      { Name P ; Type AliasOf  ; NameOfCoef ir ; }
+    }
+    Constraint {
+      { NameOfCoef P ; EntityType Region ; NameOfConstraint CurrentPosition ; }
+    }
+  }
+
+
+  { Name Velocity ; Type Scalar ;
+    BasisFunction {
+      { Name sr ; NameOfCoef ir ; Function BF_Region ;
+        Support DomainKin ; Entity DomainKin ; } }
+    GlobalQuantity {
+      { Name V ; Type AliasOf ; NameOfCoef ir ; }
+    }
+    Constraint {
+      { NameOfCoef V ; EntityType Region ; NameOfConstraint CurrentVelocity ; }
+    }
+  }
+
+}
+
+//-----------------------------------------------------------------------------------------------
+
+Formulation {
+
+  { Name MagSta_a_2D ; Type FemEquation ;
+    Quantity {
+      { Name a  ; Type Local  ; NameOfSpace Hcurl_a_2D ; }
+
+      { Name ir ; Type Local  ; NameOfSpace Hregion_i_Mag_2D ; }
+      { Name Ub ; Type Global ; NameOfSpace Hregion_i_Mag_2D [Ub] ; }
+      { Name Ib ; Type Global ; NameOfSpace Hregion_i_Mag_2D [Ib] ; }
+
+      { Name Uz ; Type Global ; NameOfSpace Hregion_Z [Uz] ; }
+      { Name Iz ; Type Global ; NameOfSpace Hregion_Z [Iz] ; }
+    }
+
+    Equation {
+      Galerkin { [ nu[{d a}] * Dof{d a}  , {d a} ] ;
+        In Domain ; Jacobian Vol ; Integration I1 ; }
+      Galerkin { JacNL [ dhdb_NL[{d a}] * Dof{d a} , {d a} ] ;
+        In DomainNL ; Jacobian Vol ; Integration I1 ; }
+
+      Galerkin {  [  0*Dof{d a} , {d a} ]  ; // DO NOT REMOVE!!! - Keeping track of Dofs in auxiliary line of MB if Symmetry=1
+        In Rotor_Bnd_MBaux; Jacobian Vol; Integration I1; }
+
+      Galerkin { [ -nu[] * br[] , {d a} ] ;
+        In DomainM ; Jacobian Vol ; Integration I1 ; }
+
+      Galerkin { [ -js[] , {a} ] ;
+        In DomainS ; Jacobian Vol ; Integration I1 ; }
+
+      Galerkin { [ -NbWires[]/SurfCoil[] * Dof{ir} , {a} ] ;
+        In DomainB ; Jacobian Vol ; Integration I1 ; }
+      Galerkin { DtDof [ AxialLength * NbWires[]/SurfCoil[] * Dof{a} , {ir} ] ;
+        In DomainB ; Jacobian Vol ; Integration I1 ; }
+      GlobalTerm { [ Dof{Ub}/SymmetryFactor, {Ib} ] ; In DomainB ; }
+      Galerkin { [ Rb[]/SurfCoil[]* Dof{ir} , {ir} ] ;
+        In DomainB ; Jacobian Vol ; Integration I1 ; }
+
+      // GlobalTerm { [ Resistance[]  * Dof{Ib} , {Ib} ] ; In DomainB ; }
+      // The above term can replace:
+      // Galerkin{ [ NbWires[]/SurfCoil[] / sigma[] * NbWires[]/SurfCoil[] * Dof{ir}, {ir} ]
+      // if we have an estimation of the resistance of DomainB, via e.g. measurements
+
+      If(Flag_Cir)
+	GlobalTerm { NeverDt[ Dof{Uz}                , {Iz} ] ; In Resistance_Cir ; }
+        GlobalTerm { NeverDt[ Resistance[] * Dof{Iz} , {Iz} ] ; In Resistance_Cir ; }
+
+	GlobalTerm { [ 0. * Dof{Iz} , {Iz} ] ; In DomainSource_Cir ; }
+        GlobalTerm { [ 0. * Dof{Uz} , {Iz} ] ; In DomainZt_Cir ; }
+
+        GlobalEquation {
+          Type Network ; NameOfConstraint ElectricalCircuit ;
+          { Node {Iz}; Loop {Uz}; Equation {Uz}; In DomainZt_Cir ; }
+          { Node {Ib}; Loop {Ub}; Equation {Ub}; In DomainB ; }
+         }
+      EndIf
+    }
+  }
+
+  { Name MagDyn_a_2D ; Type FemEquation ;
+    Quantity {
+      { Name a  ; Type Local  ; NameOfSpace Hcurl_a_2D ; }
+      { Name ur ; Type Local  ; NameOfSpace Hregion_u_Mag_2D ; }
+      { Name I  ; Type Global ; NameOfSpace Hregion_u_Mag_2D [I] ; }
+      { Name U  ; Type Global ; NameOfSpace Hregion_u_Mag_2D [U] ; }
+
+      { Name ir ; Type Local  ; NameOfSpace Hregion_i_Mag_2D ; }
+      { Name Ub ; Type Global ; NameOfSpace Hregion_i_Mag_2D [Ub] ; }
+      { Name Ib ; Type Global ; NameOfSpace Hregion_i_Mag_2D [Ib] ; }
+
+      { Name Uz ; Type Global ; NameOfSpace Hregion_Z [Uz] ; }
+      { Name Iz ; Type Global ; NameOfSpace Hregion_Z [Iz] ; }
+    }
+    Equation {
+      Galerkin { [ nu[{d a}] * Dof{d a}  , {d a} ] ;
+        In Domain ; Jacobian Vol ; Integration I1 ; }
+      Galerkin { JacNL [ dhdb_NL[{d a}] * Dof{d a} , {d a} ] ;
+        In DomainNL ; Jacobian Vol ; Integration I1 ; }
+
+      Galerkin {  [  0*Dof{d a} , {d a} ]  ; // DO NOT REMOVE!!! - Keeping track of Dofs in auxiliary line of MB if Symmetry=1
+        In Rotor_Bnd_MBaux; Jacobian Vol; Integration I1; }
+
+      Galerkin { [ -nu[] * br[] , {d a} ] ;
+        In DomainM ; Jacobian Vol ; Integration I1 ; }
+
+      Galerkin { DtDof[ sigma[] * Dof{a} , {a} ] ;
+        In DomainC ; Jacobian Vol ; Integration I1 ; }
+      Galerkin { [ sigma[] * Dof{ur}, {a} ] ;
+        In DomainC ; Jacobian Vol ; Integration I1 ; }
+
+      Galerkin { [ -sigma[] * (Velocity[] *^ Dof{d a}) , {a} ] ;
+        In DomainV ; Jacobian Vol ; Integration I1 ; }
+
+      Galerkin { [ -js[] , {a} ] ;
+        In DomainS ; Jacobian Vol ; Integration I1 ; }
+
+      Galerkin { DtDof[ sigma[] * Dof{a} , {ur} ] ;
+        In DomainC ; Jacobian Vol ; Integration I1 ; }
+      Galerkin { [ sigma[] * Dof{ur} , {ur} ] ;
+        In DomainC ; Jacobian Vol ; Integration I1 ; }
+      GlobalTerm { [ Dof{I} , {U} ] ; In DomainC ; }
+
+      Galerkin { [ -NbWires[]/SurfCoil[] * Dof{ir} , {a} ] ;
+        In DomainB ; Jacobian Vol ; Integration I1 ; }
+      Galerkin { DtDof [ AxialLength * NbWires[]/SurfCoil[] * Dof{a} , {ir} ] ;
+        In DomainB ; Jacobian Vol ; Integration I1 ; }
+      GlobalTerm { [ Dof{Ub}/SymmetryFactor , {Ib} ] ; In DomainB ; }
+      Galerkin { [ Rb[]/SurfCoil[]* Dof{ir} , {ir} ] ;
+        In DomainB ; Jacobian Vol ; Integration I1 ; } // Resistance term
+
+      // GlobalTerm { [ Resistance[]  * Dof{Ib} , {Ib} ] ; In DomainB ; }
+      // The above term can replace the resistance term:
+      // if we have an estimation of the resistance of DomainB, via e.g. measurements
+      // which is better to account for the end windings...
+
+      If(Flag_Cir)
+	GlobalTerm { NeverDt[ Dof{Uz}                , {Iz} ] ; In Resistance_Cir ; }
+        GlobalTerm { NeverDt[ Resistance[] * Dof{Iz} , {Iz} ] ; In Resistance_Cir ; }
+
+	GlobalTerm { [ Dof{Uz}                      , {Iz} ] ; In Inductance_Cir ; }
+	GlobalTerm { DtDof [ Inductance[] * Dof{Iz} , {Iz} ] ; In Inductance_Cir ; }
+
+	GlobalTerm { NeverDt[ Dof{Iz}        , {Iz} ] ; In Capacitance_Cir ; }
+	GlobalTerm { DtDof [ Capacitance[] * Dof{Uz} , {Iz} ] ; In Capacitance_Cir ; }
+
+	GlobalTerm { [ 0. * Dof{Iz} , {Iz} ] ; In DomainZt_Cir ; }
+        GlobalTerm { [ 0. * Dof{Uz} , {Iz} ] ; In DomainZt_Cir ; }
+
+        GlobalEquation {
+          Type Network ; NameOfConstraint ElectricalCircuit ;
+          { Node {I};  Loop {U};  Equation {I};  In DomainC ; }
+          { Node {Ib}; Loop {Ub}; Equation {Ub}; In DomainB ; }
+          { Node {Iz}; Loop {Uz}; Equation {Uz}; In DomainZt_Cir ; }
+         }
+      EndIf
+    }
+  }
+
+
+ //--------------------------------------------------------------------------
+  // Mechanics
+  //--------------------------------------------------------------------------
+  { Name Mechanical ; Type FemEquation ;
+    Quantity {
+      { Name V ; Type Global ; NameOfSpace Velocity [V] ; } // velocity
+      { Name P ; Type Global ; NameOfSpace Position [P] ; } // position
+    }
+    Equation {
+      GlobalTerm { DtDof [ Inertia * Dof{V} , {V} ] ; In DomainKin ; }
+      GlobalTerm { [ Friction[] * Dof{V} , {V} ] ; In DomainKin ; }
+      GlobalTerm { [             -Fmag[] , {V} ] ; In DomainKin ; }
+
+      GlobalTerm { DtDof [ Dof{P} , {P} ] ; In DomainKin ; }
+      GlobalTerm {       [-Dof{V} , {P} ] ; In DomainKin ; }
+    }
+  }
+
+}
+
+//-----------------------------------------------------------------------------------------------
+
+Resolution {
+
+  { Name TimeDomain ;
+    System {
+      { Name A ; NameOfFormulation MagDyn_a_2D ; }
+    }
+    Operation {
+      CreateDir["res/"];
+      If[ Clean_Results==1 ]{
+        DeleteFile["res/temp.dat"];
+        DeleteFile["res/Tr.dat"]; DeleteFile["res/Ts.dat"]; DeleteFile["res/Tmb.dat"];
+        DeleteFile["res/Ua.dat"]; DeleteFile["res/Ub.dat"]; DeleteFile["res/Uc.dat"];
+        DeleteFile["res/Ia.dat"]; DeleteFile["res/Ib.dat"]; DeleteFile["res/Ic.dat"];
+        DeleteFile["res/Flux_a.dat"]; DeleteFile["res/Flux_b.dat"]; DeleteFile["res/Flux_c.dat"];
+        DeleteFile["res/Flux_d.dat"]; DeleteFile["res/Flux_q.dat"]; DeleteFile["res/Flux_0.dat"];
+      }
+      InitMovingBand2D[MB] ;
+      MeshMovingBand2D[MB] ;
+      InitSolution[A] ;
+      If[Flag_ParkTransformation && Flag_SrcType_Stator==1]{ PostOperation[ThetaPark_IABC] ; }
+      If[!Flag_NL]{
+        Generate[A] ; Solve[A] ;
+      }
+      Else{
+        //IterativeLoop[Nb_max_iter, stop_criterion, relaxation_factor]
+        // { GenerateJac[A] ; SolveJac[A] ; }
+        IterativeLoopN[ Nb_max_iter, relaxation_factor,
+                        System { {A, reltol, abstol, Solution MeanL2Norm}} ]
+          { GenerateJac[A] ; SolveJac[A] ; }
+      }
+      SaveSolution[A] ;
+      PostOperation[Get_LocalFields] ;
+      PostOperation[Get_GlobalQuantities] ;
+    }
+  }
+
+  { Name TimeDomain_Loop ;
+    System {
+      { Name A ; NameOfFormulation MagDyn_a_2D ; }
+    }
+    Operation {
+      CreateDir["res/"];
+      If[ Clean_Results==1 ]{
+        DeleteFile["res/temp.dat"];
+        DeleteFile["res/Tr.dat"]; DeleteFile["res/Ts.dat"]; DeleteFile["res/Tmb.dat"];
+        DeleteFile["res/Ua.dat"]; DeleteFile["res/Ub.dat"]; DeleteFile["res/Uc.dat"];
+        DeleteFile["res/Ia.dat"]; DeleteFile["res/Ib.dat"]; DeleteFile["res/Ic.dat"];
+        DeleteFile["res/Flux_a.dat"]; DeleteFile["res/Flux_b.dat"]; DeleteFile["res/Flux_c.dat"];
+        DeleteFile["res/Flux_d.dat"]; DeleteFile["res/Flux_q.dat"]; DeleteFile["res/Flux_0.dat"];
+      }
+      InitMovingBand2D[MB] ;
+      MeshMovingBand2D[MB] ;
+      InitSolution[A] ;
+      TimeLoopTheta[time0, timemax, delta_time, 1.]{ // Euler implicit (1) -- Crank-Nicolson (0.5)
+        If[Flag_ParkTransformation && Flag_SrcType_Stator==1]{ PostOperation[ThetaPark_IABC] ; }
+        If[!Flag_NL]{
+	  Generate[A]; Solve[A];
+        }
+        Else{
+          // IterativeLoop[Nb_max_iter, stop_criterion, relaxation_factor] {
+            //  GenerateJac[A] ; SolveJac[A] ; }
+          IterativeLoopN[
+            Nb_max_iter, relaxation_factor, System { {A, reltol, abstol, Solution MeanL2Norm}} ]{
+            GenerateJac[A] ; SolveJac[A] ; }
+        }
+        SaveSolution[A];
+
+        PostOperation[Get_LocalFields] ;
+        If[ $TimeStep > 1 ]{
+          PostOperation[Get_GlobalQuantities] ;
+        }
+        ChangeOfCoordinates[ NodesOf[Rotor_Moving], RotatePZ[delta_theta]] ;
+        MeshMovingBand2D[MB] ;
+      }
+    }
+  }
+
+  { Name FrequencyDomain ;
+    System {
+      { Name A ; NameOfFormulation MagDyn_a_2D ; Type ComplexValue ; Frequency Freq ; }
+    }
+    Operation {
+      If[ Clean_Results==1 && wr == 0.]{
+        DeleteFile["res/Tr.dat"]; DeleteFile["res/Ts.dat"]; DeleteFile["res/Tmb.dat"];
+        DeleteFile["res/Ua.dat"]; DeleteFile["res/Ub.dat"]; DeleteFile["res/Uc.dat"];
+        DeleteFile["res/Ia.dat"]; DeleteFile["res/Ib.dat"]; DeleteFile["res/Ic.dat"];
+      }
+      SetTime[wr];
+      InitMovingBand2D[MB] ;
+      MeshMovingBand2D[MB] ;
+      Generate[A] ; Solve[A] ; SaveSolution[A];
+      PostOperation[Map_LocalFields] ;
+      PostOperation[Torque_Emf_Flux] ;
+    }
+  }
+
+  /*
+  { Name  MagDyn_Kin ;
+    System {
+      { Name A ; NameOfFormulation MagDyn_a_2D ; }
+      { Name M ; NameOfFormulation Mechanical ; }
+    }
+    Operation {
+      ChangeOfCoordinates [ NodesOf[Rotor_Moving], RotatePZ[theta0] ] ; // Initial position (supposing initial mesh with angleR=0)
+      InitMovingBand2D[MB] ; MeshMovingBand2D[MB] ;
+
+      InitSolution[A] ; SaveSolution[A] ;
+      InitSolution[M] ; SaveSolution[M] ;
+
+      TimeLoopTheta[time0, timemax, delta_time, 1.]{
+	Generate[A] ; Solve[A] ;  SaveSolution[A] ;
+        PostOperation[MagDyn_a_2D] ;
+
+        Generate[M] ; Solve[M] ; SaveSolution[M] ;
+        PostOperation[Mechanical] ;
+
+        ChangeOfCoordinates [ NodesOf[Rotor_Moving], RotatePZ[#77-#66] ] ;
+        Evaluate[ #77#66 ] ; //Keep track of previous angular position
+        MeshMovingBand2D[MB] ;
+      }
+    }
+  }
+  */
+
+}
+
+//-----------------------------------------------------------------------------------------------
+
+PostProcessing {
+
+ { Name MagSta_a_2D ; NameOfFormulation MagSta_a_2D ;
+   PostQuantity {
+     { Name a ; Value { Term { [  {a} ]   ; In Domain ; Jacobian Vol ; } } }
+     { Name az ; Value { Term { [  CompZ[{a}] ]   ; In Domain ; Jacobian Vol ; } } }
+     { Name b  ; Value { Term { [ {d a} ] ; In Domain ; Jacobian Vol ; } } }
+     { Name boundary  ; Value { Term { [ {d a} ] ; In Dummy ; Jacobian Vol ; } } }
+     { Name br  ; Value { Term { [ br[] ] ; In DomainM ; Jacobian Vol ; } } }
+
+     { Name Flux ; Value { Integral { [ SymmetryFactor*AxialLength*Idir[]*NbWires[]/SurfCoil[]* CompZ[{a}] ] ;
+           In Inds  ; Jacobian Vol ; Integration I1 ; } } }
+     { Name Force_vw ; Value {
+         Integral { Type Global ; [ 0.5 * nu[] * VirtualWork [{d a}] * AxialLength ];
+           In ElementsOf[Rotor_Airgap, OnOneSideOf Rotor_Bnd_MB];
+           Jacobian Vol ; Integration I1 ; } } }
+
+     { Name Torque_Maxwell ;  Value {
+         Integral {
+           [ CompZ [ XYZ[] /\ (T_max[{d a}] * XYZ[]) ]*2*Pi*AxialLength/SurfaceArea[]  ] ;
+           In Domain ; Jacobian Vol  ; Integration I1; } } }
+
+     { Name Torque_vw ; Value {
+         Integral { Type Global ;
+           [ CompZ[ 0.5 * nu[] * XYZ[] /\ VirtualWork[{d a}] ] * AxialLength ];
+           In ElementsOf[Rotor_Airgap, OnOneSideOf Rotor_Bnd_MB];
+           Jacobian Vol ; Integration I1 ; } } }
+
+     { Name U ; Value {
+         Term { [ {Ub} ]  ; In DomainB ; }
+         Term { [ {Uz} ]  ; In DomainZt_Cir ; }
+     } }
+
+     { Name I ; Value {
+         Term { [ {Ib} ]  ; In DomainB ; }
+         Term { [ {Iz} ]  ; In DomainZt_Cir ; }
+     } }
+
+   }
+ }
+
+ { Name MagDyn_a_2D ; NameOfFormulation MagDyn_a_2D ;
+   PostQuantity {
+     { Name a  ; Value { Term { [ {a} ] ; In Domain ; Jacobian Vol ; } } }
+     { Name az ; Value { Term { [ CompZ[{a}] ] ; In Domain ; Jacobian Vol ; } } }
+
+     { Name b  ; Value { Term { [ {d a} ] ; In Domain ; Jacobian Vol ; } } }
+     { Name boundary  ; Value { Term { [ 1 ] ; In Dummy ; Jacobian Vol ; } } } // Dummy quantity
+     { Name b_radial  ; Value { Term { [ {d a}* Vector[  Cos[AngularPosition[]#4], Sin[#4], 0.] ] ; In Domain ; Jacobian Vol ; } } }
+     { Name b_tangent ; Value { Term { [ {d a}* Vector[ -Sin[AngularPosition[]#4], Cos[#4], 0.] ] ; In Domain ; Jacobian Vol ; } } }
+
+     { Name js ; Value { Term { [ js[] ] ; In DomainS ; Jacobian Vol ; } } }
+     { Name br ; Value { Term { [ br[] ] ; In DomainM ; Jacobian Vol ; } } }
+
+     { Name j  ; Value {
+         Term { [ -sigma[]*(Dt[{a}]+{ur}) ]        ; In DomainC ; Jacobian Vol ; }
+         Term { [  sigma[]*(Velocity[] *^ {d a}) ] ; In DomainV ; Jacobian Vol ; }
+       }
+     }
+     { Name ir ; Value { Term { [ {ir} ] ; In Inds ; Jacobian Vol ; } } }
+
+     { Name jz ; Value {
+         Term { [ CompZ[-sigma[]*(Dt[{a}]+{ur})] ]       ; In DomainC ; Jacobian Vol ; }
+         Term { [ CompZ[ sigma[]*(Velocity[]*^{d a}) ] ] ; In DomainV ; Jacobian Vol ; }
+       }
+     }
+
+     { Name rhoj2 ;
+       Value {
+         Term { [ sigma[]*SquNorm[ Dt[{a}]+{ur}] ] ; In Region[{DomainC,-DomainV}] ; Jacobian Vol ; }
+         Term { [ sigma[]*SquNorm[ Dt[{a}]+{ur}-Velocity[]*^{d a} ] ] ; In DomainV ; Jacobian Vol ; }
+         Term { [ 1./sigma[]*SquNorm[ IA[]*{ir} ] ] ; In PhaseA  ; Jacobian Vol ; }
+         Term { [ 1./sigma[]*SquNorm[ IB[]*{ir} ] ] ; In PhaseB  ; Jacobian Vol ; }
+         Term { [ 1./sigma[]*SquNorm[ IC[]*{ir} ] ] ; In PhaseC  ; Jacobian Vol ; }
+       }
+     }
+
+     { Name JouleLosses ;
+       Value {
+         Integral { [ sigma[] * SquNorm[ Dt[{a}]+{ur}-Velocity[]*^{d a} ] ]   ; In Region[{DomainC,-DomainV}] ; Jacobian Vol ; Integration I1 ; }
+         Integral { [ sigma[] * SquNorm[ Dt[{a}]+{ur}-Velocity[]*^{d a} ] ]   ; In DomainV ; Jacobian Vol ; Integration I1 ; }
+         Integral { [ 1./sigma[]*SquNorm[ IA[]*{ir} ] ] ; In PhaseA  ; Jacobian Vol ; Integration I1 ; }
+         Integral { [ 1./sigma[]*SquNorm[ IB[]*{ir} ] ] ; In PhaseB  ; Jacobian Vol ; Integration I1 ; }
+         Integral { [ 1./sigma[]*SquNorm[ IC[]*{ir} ] ] ; In PhaseC  ; Jacobian Vol ; Integration I1 ; }
+       }
+     }
+
+     { Name Flux ; Value { Integral { [ SymmetryFactor*AxialLength*Idir[]*NbWires[]/SurfCoil[]* CompZ[{a}] ] ;
+           In Inds  ; Jacobian Vol ; Integration I1 ; } } }
+
+     { Name Force_vw ; // Force computation by Virtual Works
+       Value {
+         Integral {
+           Type Global ; [ 0.5 * nu[] * VirtualWork [{d a}] * AxialLength ];
+           In ElementsOf[Rotor_Airgap, OnOneSideOf Rotor_Bnd_MB]; Jacobian Vol ; Integration I1 ; }
+       }
+     }
+
+     { Name Torque_vw ; Value { // Torque computation via Virtual Works
+         Integral { Type Global ;
+           [ CompZ[ 0.5 * nu[] * XYZ[] /\ VirtualWork[{d a}] ] * AxialLength ];
+           In ElementsOf[Rotor_Airgap, OnOneSideOf Rotor_Bnd_MB]; Jacobian Vol ; Integration I1 ; }
+       }
+     }
+
+
+     { Name Torque_Maxwell ; // Torque computation via Maxwell stress tensor
+       Value {
+         Integral {
+           [ CompZ [ XYZ[] /\ (T_max[{d a}] * XYZ[]) ] * 2*Pi*AxialLength/SurfaceArea[] ] ;
+           In Domain ; Jacobian Vol  ; Integration I1; }
+       }
+     }
+
+     { Name Torque_Maxwell_cplx ; // Torque computation via Maxwell stress tensor
+       Value {
+         Integral {
+           [ CompZ [ XYZ[] /\ (T_max_cplx[{d a}] * XYZ[]) ] * 2*Pi*AxialLength/SurfaceArea[] ] ;
+           In Domain ; Jacobian Vol  ; Integration I1; }
+       }
+     }
+
+     { Name ComplexPower ; // S = P + i*Q
+       Value {
+         Integral { [ Complex[ sigma[]*SquNorm[Dt[{a}]+{ur}], nu[]*SquNorm[{d a}] ] ] ;
+           In Region[{DomainC,-DomainV}] ; Jacobian Vol ; Integration I1 ; }
+         Integral { [ Complex[ sigma[]*SquNorm[Dt[{a}]+{ur}-Velocity[]*^{d a}], nu[]*SquNorm[{d a}] ] ] ;
+           In DomainV ; Jacobian Vol ; Integration I1 ; }
+       }
+     }
+
+     { Name U ; Value {
+         Term { [ {U} ]   ; In DomainC ; }
+         Term { [ {Ub} ]  ; In DomainB ; }
+         Term { [ {Uz} ]  ; In DomainZt_Cir ; }
+     } }
+
+     { Name I ; Value {
+         Term { [ {I} ]   ; In DomainC ; }
+         Term { [ {Ib} ]  ; In DomainB ; }
+         Term { [ {Iz} ]  ; In DomainZt_Cir ; }
+     } }
+
+     { Name S ; Value {
+         Term { [ {U}*Conj[{I}] ]    ; In DomainC ; }
+         Term { [ {Ub}*Conj[{Ib}] ]  ; In DomainB ; }
+         Term { [ {Uz}*Conj[{Iz}] ]  ; In DomainZt_Cir ; }
+     } }
+
+     { Name Velocity  ; Value {
+         Term { [ Velocity[] ] ; In Domain ; Jacobian Vol ; }
+       }
+     }
+
+     // For getting the value of some functions:
+     { Name RotorPosition_deg ; Value { Term { Type Global; [ RotorPosition_deg[] ] ; In DomainDummy ; } } }
+     { Name Theta_Park_deg    ; Value { Term { Type Global; [ Theta_Park_deg[] ] ; In DomainDummy ; } } }
+     { Name IA  ; Value { Term { Type Global; [ IA[] ] ; In DomainDummy ; } } }
+     { Name IB  ; Value { Term { Type Global; [ IB[] ] ; In DomainDummy ; } } }
+     { Name IC  ; Value { Term { Type Global; [ IC[] ] ; In DomainDummy ; } } }
+
+     { Name Flux_d  ; Value { Term { Type Global; [ CompX[Flux_dq0[]] ] ; In DomainDummy ; } } }
+     { Name Flux_q  ; Value { Term { Type Global; [ CompY[Flux_dq0[]] ] ; In DomainDummy ; } } }
+     { Name Flux_0  ; Value { Term { Type Global; [ CompZ[Flux_dq0[]] ] ; In DomainDummy ; } } }
+   }
+ }
+
+ { Name Mechanical ; NameOfFormulation Mechanical ;
+   PostQuantity {
+     { Name P ; Value { Term { [ {P} ]  ; In DomainKin ; } } } //Position
+     { Name V ; Value { Term { [ {V} ]  ; In DomainKin ; } } } //Velocity
+     { Name Vrpm ; Value { Term { [ {V}*30/Pi ]  ; In DomainKin ; } } } //Velocity in rpm
+   }
+ }
+
+}
+
+//-----------------------------------------------------------------------------------------------
+//-----------------------------------------------------------------------------------------------
+
+If (Flag_ParkTransformation)
+PostOperation ThetaPark_IABC UsingPost MagDyn_a_2D {
+  Print[ RotorPosition_deg, OnRegion DomainDummy, Format Table, LastTimeStepOnly, File StrCat[Dir, StrCat["temp",ExtGnuplot]],
+         SendToServer "Output/1RotorPosition", Color "LightYellow" ];
+  Print[ Theta_Park_deg, OnRegion DomainDummy, Format Table, LastTimeStepOnly, File StrCat[Dir, StrCat["temp",ExtGnuplot]],
+         SendToServer "Output/1Theta_Park", Color "LightYellow" ];
+  Print[ IA, OnRegion DomainDummy, Format Table, LastTimeStepOnly, File StrCat[Dir, StrCat["temp",ExtGnuplot]], SendToServer "Output/2IA", Color "Pink" ];
+  Print[ IB, OnRegion DomainDummy, Format Table, LastTimeStepOnly, File StrCat[Dir, StrCat["temp",ExtGnuplot]], SendToServer "Output/2IB", Color "Yellow" ];
+  Print[ IC, OnRegion DomainDummy, Format Table, LastTimeStepOnly, File StrCat[Dir, StrCat["temp",ExtGnuplot]], SendToServer "Output/2IC", Color "LightGreen"  ];
+}
+EndIf
+PostOperation Get_LocalFields UsingPost MagDyn_a_2D {
+  Print[ ir, OnElementsOf Stator_Inds, File StrCat[Dir, StrCat["ir_stator",ExtGmsh]], LastTimeStepOnly, AppendTimeStepToFileName Flag_SaveAllSteps] ;
+  Print[ ir, OnElementsOf Rotor_Inds,  File StrCat[Dir, StrCat["ir_rotor",ExtGmsh]], LastTimeStepOnly, AppendTimeStepToFileName Flag_SaveAllSteps] ;
+  //Print[ br,  OnElementsOf #{DomainM}, File StrCat[Dir, StrCat["b",ExtGmsh]], LastTimeStepOnly, AppendTimeStepToFileName Flag_SaveAllSteps] ;
+  Print[ b,  OnElementsOf Domain, File StrCat[Dir, StrCat["b",ExtGmsh]], LastTimeStepOnly, AppendTimeStepToFileName Flag_SaveAllSteps] ;
+  Print[ boundary, OnElementsOf Dummy,  File StrCat[Dir, StrCat["bnd",ExtGmsh]], LastTimeStepOnly, AppendTimeStepToFileName Flag_SaveAllSteps] ;
+  Print[ az, OnElementsOf Domain, File StrCat[Dir, StrCat["a",ExtGmsh]], LastTimeStepOnly, AppendTimeStepToFileName Flag_SaveAllSteps ] ;
+}
+
+PostOperation Get_GlobalQuantities UsingPost MagDyn_a_2D {
+  If(!Flag_Cir)
+  If(!Flag_ParkTransformation)
+    Print[ I, OnRegion PhaseA_pos, Format Table,
+           File > StrCat[Dir, StrCat["Ia",ExtGnuplot]], LastTimeStepOnly, SendToServer "Output/2IA", Color "Pink" ];
+    Print[ I, OnRegion PhaseB_pos, Format Table,
+           File > StrCat[Dir, StrCat["Ib",ExtGnuplot]], LastTimeStepOnly, SendToServer "Output/2IB", Color "Yellow" ];
+    Print[ I, OnRegion PhaseC_pos, Format Table,
+           File > StrCat[Dir, StrCat["Ic",ExtGnuplot]], LastTimeStepOnly, SendToServer "Output/2IC", Color "LightGreen" ];
+  EndIf
+
+  Print[ U, OnRegion PhaseA_pos, Format Table,
+         File > StrCat[Dir, StrCat["Ua",ExtGnuplot]], LastTimeStepOnly, SendToServer "Output/30UA", Color "Pink" ];
+  Print[ U, OnRegion PhaseB_pos, Format Table,
+         File > StrCat[Dir, StrCat["Ub",ExtGnuplot]], LastTimeStepOnly, SendToServer "Output/31UB", Color "Yellow" ];
+  Print[ U, OnRegion PhaseC_pos, Format Table,
+         File > StrCat[Dir, StrCat["Uc",ExtGnuplot]], LastTimeStepOnly, SendToServer "Output/32UC", Color "LightGreen" ];
+  EndIf
+  If(Flag_Cir && Flag_SrcType_Stator==2)
+    Print[ I, OnRegion Input1, Format Table,
+           File > StrCat[Dir, StrCat["Ia",ExtGnuplot]], LastTimeStepOnly, SendToServer "Output/2IA", Color "Pink" ];
+    Print[ I, OnRegion Input2, Format Table,
+           File > StrCat[Dir, StrCat["Ib",ExtGnuplot]], LastTimeStepOnly, SendToServer "Output/2IB", Color "Yellow" ];
+    Print[ I, OnRegion Input3, Format Table,
+           File > StrCat[Dir, StrCat["Ic",ExtGnuplot]], LastTimeStepOnly, SendToServer "Output/2IC", Color "LightGreen" ];
+    Print[ U, OnRegion Input1, Format Table,
+           File > StrCat[Dir, StrCat["Ua",ExtGnuplot]], LastTimeStepOnly, SendToServer "Output/30UA", Color "Pink" ];
+    Print[ U, OnRegion Input2, Format Table,
+           File > StrCat[Dir, StrCat["Ub",ExtGnuplot]], LastTimeStepOnly, SendToServer "Output/31UB", Color "Yellow" ];
+    Print[ U, OnRegion Input3, Format Table,
+           File > StrCat[Dir, StrCat["Uc",ExtGnuplot]], LastTimeStepOnly, SendToServer "Output/32UC", Color "LightGreen" ];
+  EndIf
+  If(Flag_Cir && Flag_SrcType_Stator==0)
+    Print[ I, OnRegion R1, Format Table,
+           File > StrCat[Dir, StrCat["Ia",ExtGnuplot]], LastTimeStepOnly, SendToServer "Output/2IA", Color "Pink" ];
+    Print[ I, OnRegion R2, Format Table,
+           File > StrCat[Dir, StrCat["Ib",ExtGnuplot]], LastTimeStepOnly, SendToServer "Output/2IB", Color "Yellow" ];
+    Print[ I, OnRegion R3, Format Table,
+           File > StrCat[Dir, StrCat["Ic",ExtGnuplot]], LastTimeStepOnly, SendToServer "Output/2IC", Color "LightGreen" ];
+    Print[ U, OnRegion R1, Format Table,
+           File > StrCat[Dir, StrCat["Ua",ExtGnuplot]], LastTimeStepOnly, SendToServer "Output/30UA", Color "Pink" ];
+    Print[ U, OnRegion R2, Format Table,
+           File > StrCat[Dir, StrCat["Ub",ExtGnuplot]], LastTimeStepOnly, SendToServer "Output/31UB", Color "Yellow" ];
+    Print[ U, OnRegion R3, Format Table,
+           File > StrCat[Dir, StrCat["Uc",ExtGnuplot]], LastTimeStepOnly, SendToServer "Output/32UC", Color "LightGreen" ];
+  EndIf
+
+
+  Print[ I, OnRegion RotorC, Format Table,
+         File > StrCat[Dir, StrCat["Irotor",ExtGnuplot]], LastTimeStepOnly, SendToServer "Output/2Ir", Color "LightYellow" ];
+
+  Print[ Torque_Maxwell[Rotor_Airgap], OnGlobal, Format TimeTable,
+         File > StrCat[Dir, StrCat["Tr",ExtGnuplot]], LastTimeStepOnly, Store 54, SendToServer my_output, Color "LightYellow" ];
+  Print[ Torque_Maxwell[Stator_Airgap], OnGlobal, Format TimeTable,
+         File > StrCat[Dir, StrCat["Ts",ExtGnuplot]], LastTimeStepOnly, Store 55, SendToServer "Output/41T_stator", Color "LightYellow" ];
+  Print[ Torque_Maxwell[MB], OnGlobal, Format TimeTable,
+         File > StrCat[Dir, StrCat["Tmb",ExtGnuplot]], LastTimeStepOnly, Store 56, SendToServer "Output/42T_mb", Color "LightYellow" ];
+  //Print[ Torque_vw, OnRegion NodesOf[Rotor_Bnd_MB], Format RegionValue,
+  //       File > StrCat[Dir, StrCat["Tr_vw",ExtGnuplot]], LastTimeStepOnly, Store 54, SendToServer "Output/1T_rotor_vw" ];
+
+  If(Flag_SrcType_Stator)
+  Print[ Flux[PhaseA], OnGlobal, Format TimeTable,
+         File > StrCat[Dir, StrCat["Flux_a",ExtGnuplot]], LastTimeStepOnly, Store 11, SendToServer "Output/50Flux_a",  Color "Pink" ];
+  Print[ Flux[PhaseB], OnGlobal, Format TimeTable,
+         File > StrCat[Dir, StrCat["Flux_b",ExtGnuplot]], LastTimeStepOnly, Store 22, SendToServer "Output/51Flux_b",  Color "Yellow" ];
+  Print[ Flux[PhaseC], OnGlobal, Format TimeTable,
+         File > StrCat[Dir, StrCat["Flux_c",ExtGnuplot]], LastTimeStepOnly, Store 33, SendToServer "Output/52Flux_c", Color "LightGreen"];
+
+  If(Flag_ParkTransformation && Flag_SrcType_Stator)
+    Print[ Flux_d, OnRegion DomainDummy, Format TimeTable,
+           File > StrCat[Dir, StrCat["Flux_d",ExtGnuplot]], LastTimeStepOnly, SendToServer "Output/60Flux_d", Color "LightYellow" ];
+    Print[ Flux_q, OnRegion DomainDummy, Format TimeTable,
+           File > StrCat[Dir, StrCat["Flux_q",ExtGnuplot]], LastTimeStepOnly, SendToServer "Output/61Flux_q", Color "LightYellow" ];
+    Print[ Flux_0, OnRegion DomainDummy, Format TimeTable,
+           File > StrCat[Dir, StrCat["Flux_0",ExtGnuplot]], LastTimeStepOnly, SendToServer "Output/62Flux_0", Color "LightYellow" ];
+  EndIf
+  EndIf
+}
+
+
+PostOperation Joule_Losses UsingPost MagDyn_a_2D {
+  Print[ JouleLosses[Rotor], OnGlobal, Format TimeTable,
+         File > StrCat[Dir, StrCat["P",ExtGnuplot]], LastTimeStepOnly, SendToServer "Output/3P_rotor" ];
+  Print[ JouleLosses[Rotor_Fe], OnGlobal, Format TimeTable,
+         File > StrCat[Dir, StrCat["P_Fe",ExtGnuplot]], LastTimeStepOnly, SendToServer "Output/3P_rotor_fe" ];
+}
+
+/*
+PostOperation Mechanical UsingPost Mechanical {
+  Print[ P, OnRegion DomainKin, File > StrCat[Dir, StrCat["P", ExtGnuplot]],
+         Format Table, Store 77, LastTimeStepOnly, SendToServer "Output/3Position"] ;
+  Print[ V, OnRegion DomainKin, File > StrCat[Dir, StrCat["V", ExtGnuplot]],
+         Format Table, LastTimeStepOnly, SendToServer "Output/4Velocity"] ;
+}
+*/
diff --git a/contrib/mobile/Android/res/raw/magnet_data_pro b/contrib/mobile/Android/res/raw/magnet_data_pro
new file mode 100644
index 0000000000..3e0a76ce52
--- /dev/null
+++ b/contrib/mobile/Android/res/raw/magnet_data_pro
@@ -0,0 +1,16 @@
+
+DefineConstant[ Val_Rint = {0.15, Min 0.2, Max 1, Step 0.1,
+                            Path "Parameters/Geometry/1",
+                            Label "Internal shell radius (m)"} ];
+
+DefineConstant[ Val_Rext = {0.25, Min Val_Rint, Max 0.5, Step 0.1,
+                            Path "Parameters/Geometry/2",
+                            Label "External shell radius (m)"}];
+
+AIR = 100;
+AIR_INF = 101;
+AIR_GAP = 102;
+MAGNET = 103;
+CORE = 104;
+LINE_INF = 105;
+LINE_X = 106;
diff --git a/contrib/mobile/Android/res/raw/magnet_geo b/contrib/mobile/Android/res/raw/magnet_geo
new file mode 100644
index 0000000000..c0c7815711
--- /dev/null
+++ b/contrib/mobile/Android/res/raw/magnet_geo
@@ -0,0 +1,93 @@
+Include "magnet_data.pro";
+
+DefineConstant[ h = {0.14, Min 0.1, Max 0.2, Step 0.01,
+                     Path "Parameters/Geometry",
+                     Label "Core height (m)"} ] ;
+
+DefineConstant[ l = {0.14, Min 0.05, Max 0.2, Step 0.01,
+                     Path "Parameters/Geometry",
+                     Label "Core width (m)"} ] ;
+
+DefineConstant[ d = {0.03, Min 0.01, Max 0.05, Step 0.002,
+                     Path "Parameters/Geometry",
+                     Label "Core tickness (m)"} ] ;
+
+DefineConstant[ e = {5e-3, Min 5e-4, Max d, Step 1e-3,
+                     Path "Parameters/Geometry",
+                     Label "Air gap (m)", Highlight "LightYellow"} ] ;
+
+DefineConstant[ ha = {0.03, Min 0.01, Max 0.1, Step 0.01,
+                     Path "Parameters/Geometry",
+                     Label "Magnet height (m)"} ] ;
+
+lc0 = d / 5 ;
+lc1 = e / 2 ;
+lc2 = (Val_Rext - Val_Rint) / 8. ;
+
+Point(1) = {0, 0, 0, lc0};
+Point(2) = {-l/2, 0, 0, lc0};
+Point(3) = {-l/2, h/2, 0, lc0};
+Point(4) = {l/2, 0, 0, lc1};
+Point(5) = {l/2, h/2, 0, lc0};
+Point(6) = {-l/2, ha/2, 0, lc0};
+Point(7) = {-l/2+d, ha/2, 0, lc0};
+Point(8) = {-l/2+d, 0, 0, lc0};
+Point(9) = {l/2-d, 0, 0, lc1};
+Point(10) = {l/2-d, h/2-d, 0, lc0};
+Point(11) = {-l/2+d, h/2-d, 0, lc0};
+Point(12) = {l/2, e/2, 0, lc1};
+Point(13) = {l/2-d, e/2, 0, lc1};
+
+Point(30) = {Val_Rint, 0, 0, lc2};
+Point(31) = {Val_Rext, 0, 0, lc2};
+Point(32) = {0, Val_Rint, 0, lc2};
+Point(33) = {0, Val_Rext, 0, lc2};
+Point(34) = {-Val_Rext, 0, 0, lc2};
+Point(35) = {-Val_Rint, 0, 0, lc2};
+
+Line(1) = {34, 35};
+Line(2) = {35, 2};
+Line(3) = {2, 8};
+Line(4) = {8, 1};
+Line(5) = {1, 9};
+Line(6) = {9, 4};
+Line(7) = {4, 30};
+Line(8) = {30, 31};
+Line(9) = {2, 6};
+Line(10) = {6, 3};
+Line(11) = {3, 5};
+Line(12) = {5, 12};
+Line(13) = {12, 4};
+Line(14) = {9, 13};
+Line(15) = {13, 10};
+Line(16) = {10, 11};
+Line(17) = {11, 7};
+Line(18) = {7, 8};
+Line(19) = {7, 6};
+Line(20) = {13, 12};
+Circle(21) = {35, 1, 32};
+Circle(22) = {32, 1, 30};
+Circle(23) = {34, 1, 33};
+Circle(24) = {33, 1, 31};
+
+Line Loop(25) = {21, 22, 8, -24, -23, 1};
+Plane Surface(26) = {25};
+Line Loop(27) = - {22, -7, -13, -12, -11, -10, -9, -2, 21};
+Plane Surface(28) = {27};
+Line Loop(29) = - {11, 12, -20, 15, 16, 17, 19, 10};
+Plane Surface(30) = {29};
+Line Loop(31) = {19, -9, 3, -18};
+Plane Surface(32) = {31};
+Line Loop(33) = - {20, 13, -6, 14};
+Plane Surface(34) = {33};
+Line Loop(35) = {15, 16, 17, 18, 4, 5, 14};
+Plane Surface(36) = {35};
+
+// physical entities (for which elements will be saved)
+Physical Surface(AIR) = {28, 36};
+Physical Surface(AIR_INF) = {26};
+Physical Surface(AIR_GAP) = {34};
+Physical Surface(MAGNET) = {32};
+Physical Surface(CORE) = {30};
+Physical Line(LINE_INF) = {23, 24};
+Physical Line(LINE_X) = {1:8};
diff --git a/contrib/mobile/Android/res/raw/magnet_pro b/contrib/mobile/Android/res/raw/magnet_pro
new file mode 100644
index 0000000000..a18c7cdf4f
--- /dev/null
+++ b/contrib/mobile/Android/res/raw/magnet_pro
@@ -0,0 +1,69 @@
+/*
+   To solve the problem
+   with scalar potential, type 'getdp test -solve MagSta_phi -pos phi'
+   with vector potential, type 'getdp test -solve MagSta_a -pos a'
+*/
+
+Include "magnet_data.pro";
+
+Group {
+  // AIR, AIR_INF, etc. are variables defined in core.txt, and correspond to the
+  // tags of physical regions in the mesh
+  Air     = Region[ AIR ];
+  AirInf  = Region[ AIR_INF ];
+  Core    = Region[ CORE ];
+  AirGap  = Region[ AIR_GAP ];
+  Magnet  = Region[ MAGNET ];
+
+  // These are the generic group names that are used in "Magnetostatics.pro"
+  Domain_S = Region[ {} ] ;
+  Domain_Inf = Region[ AirInf ] ;
+  Domain_M   = Region[ Magnet ] ;
+  Domain_Mag = Region[ {Air, Core, AirGap} ] ;
+  Dirichlet_a_0   = Region[ LINE_INF ] ;
+  Dirichlet_phi_0 = Region[ {LINE_X, LINE_INF} ] ;
+}
+
+Function {
+  mu0 = 4.e-7 * Pi ;
+
+  // DefineConstant is used to define a default value for murCore; this value
+  // can be changed interactively by the ONELAB server
+  DefineConstant[ murCore = {200., Min 1, Max 1000, Step 10,
+                             Label "Core relative permeability",
+                             Path "Parameters/Materials"} ];
+
+  nu [ Region[{Air, AirInf, AirGap, Magnet}] ] = 1. / mu0 ;
+  nu [ Core ]  = 1. / (murCore * mu0) ;
+
+  mu [ Region[{Air, AirInf, AirGap, Magnet}] ] = mu0 ;
+  mu [ Core ]  = murCore * mu0;
+
+  DefineConstant[ Hc = {920000, Label "Magnet coercive field (A/m)",
+                        Path "Parameters/Materials"} ];
+  hc [ Magnet ] = Vector[0., Hc, 0.] ;
+}
+
+Include "magnetostatics.pro"
+
+eps = 1.e-5 ;
+
+Printf[ "murCore: %f",murCore ] ;
+
+PostOperation {
+  { Name phi ; NameOfPostProcessing MagSta_phi;
+    Operation {
+      Print[ phi, OnElementsOf Domain, File "phi.pos" ] ;
+      Print[ b, OnElementsOf Domain, File "b_phi.pos" ] ;
+      Print[ b, OnLine {{-0.07,eps,0}{0.09,eps,0}} {500}, File "b_phi.txt", Format Table ] ;
+    }
+  }
+  { Name a ; NameOfPostProcessing MagSta_a;
+    Operation {
+      Print[ a, OnElementsOf Domain, File "a.pos"] ;
+      Print[ b, OnElementsOf Domain, File "b_a.pos" ] ;
+      Print[ h, OnElementsOf Domain, File "h_a.pos" ] ;
+      Print[ b, OnLine {{-0.07,eps,0}{0.09,eps,0}} {500}, File "b_a.txt" , Format Table ] ;
+    }
+  }
+}
diff --git a/contrib/mobile/Android/res/raw/magnetostatics_pro b/contrib/mobile/Android/res/raw/magnetostatics_pro
new file mode 100644
index 0000000000..4c9c07d5c5
--- /dev/null
+++ b/contrib/mobile/Android/res/raw/magnetostatics_pro
@@ -0,0 +1,209 @@
+Group {
+  // Input groups:
+  DefineGroup[ Domain_M = {{}, Label "Permanent magnets",
+                           Path "Regions/0Sources"},
+               Domain_S = {{}, Label "Inductor (imposed j_s)",
+                           Path "Regions/0Sources"},
+               Domain_Inf = {{}, Label "Infinite domain (spherical shell)",
+                             Path "Regions/0Special regions", Closed "1"},
+               Domain_Mag = {{}, Label "Passive magnetic regions",
+                             Path "Regions/Other regions"},
+               Dirichlet_phi_0 = {{}, Label "h_t = 0", Closed "1",
+                                  Path "Regions/0Boundary conditions"},
+               Dirichlet_a_0 = {{}, Label "b_n = 0",
+                                Path "Regions/0Boundary conditions"} ];
+
+  DefineGroup[ Domain = {{Domain_Mag, Domain_M, Domain_S, Domain_Inf},
+                         Label "Computational domain", Path "Regions", Visible 0} ];
+}
+
+Function{
+  // Input constants:
+  DefineConstant[ Val_Rint, Val_Rext // interior/exterior radius of Domain_Inf
+                  ];
+
+  // Input functions:
+  DefineFunction[ mu, // magnetic permeability
+                  nu, // magnetic reluctivity
+                  hc, // coercive magnetic field
+                  js // source current density
+                  ];
+
+  // remove this: only for demo
+  //DefineConstant[ hcx = {0, Label "Coercive field h_x", Path "Sources"}];
+  //DefineConstant[ hcy = {1000, Label "Coercive field h_y", Path "Sources"}];
+  //hc[] = Vector[hcx,hcy,0];
+  //mu[] = 4*Pi*10^-7;
+  //nu[] = 1/mu[];
+}
+
+Jacobian {
+  { Name JVol ;
+    Case {
+      { Region Domain_Inf ; Jacobian VolSphShell{Val_Rint, Val_Rext} ; }
+      { Region All ; Jacobian Vol ; }
+    }
+  }
+}
+
+Integration {
+  { Name I1 ;
+    Case {
+      { Type Gauss ;
+        Case {
+	  { GeoElement Triangle ; NumberOfPoints 4 ; }
+	  { GeoElement Quadrangle  ; NumberOfPoints 4 ; }
+	}
+      }
+    }
+  }
+}
+
+
+/* --------------------------------------------------------------------------
+   MagSta_phi : Magnetic scalar potential phi formulation
+   -------------------------------------------------------------------------- */
+
+Constraint {
+  { Name phi ;
+    Case {
+      { Region Dirichlet_phi_0 ; Value 0. ; }
+    }
+  }
+}
+
+FunctionSpace {
+  { Name Hgrad_phi ; Type Form0 ;
+    BasisFunction {
+      { Name sn ; NameOfCoef phin ; Function BF_Node ;
+        Support Domain ; Entity NodesOf[ All ] ; }
+    }
+    Constraint {
+      { NameOfCoef phin ; EntityType NodesOf ; NameOfConstraint phi ; }
+    }
+  }
+}
+
+Formulation {
+  { Name MagSta_phi ; Type FemEquation ;
+    Quantity {
+      { Name phi ; Type Local ; NameOfSpace Hgrad_phi ; }
+    }
+    Equation {
+      Galerkin { [ - mu[] * Dof{d phi} , {d phi} ] ;
+                 In Domain ; Jacobian JVol ; Integration I1 ; }
+
+      Galerkin { [ - mu[] * hc[] , {d phi} ] ;
+                 In Domain_M ; Jacobian JVol ; Integration I1 ; }
+    }
+  }
+}
+
+Resolution {
+  { Name MagSta_phi ;
+    System {
+      { Name A ; NameOfFormulation MagSta_phi ; }
+    }
+    Operation {
+      Generate[A] ; Solve[A] ; SaveSolution[A] ;
+    }
+  }
+}
+
+PostProcessing {
+  { Name MagSta_phi ; NameOfFormulation MagSta_phi ;
+    Quantity {
+      { Name b   ; Value { Local { [ - mu[] * {d phi} ] ; In Domain ; Jacobian JVol ; }
+                           Local { [ - mu[] * hc[] ]    ; In Domain_M ; Jacobian JVol ; } } }
+      { Name h   ; Value { Local { [ - {d phi} ]        ; In Domain ; Jacobian JVol ; } } }
+      { Name phi ; Value { Local { [ {phi} ]            ; In Domain ; Jacobian JVol ; } } }
+    }
+  }
+}
+
+PostOperation {
+  { Name MagSta_phi ; NameOfPostProcessing MagSta_phi;
+    Operation {
+      Print[ b, OnElementsOf Domain, File "MagSta_phi_b.pos" ] ;
+      Print[ h, OnElementsOf Domain, File "MagSta_phi_h.pos" ] ;
+      Print[ phi, OnElementsOf Domain, File "MagSta_phi_phi.pos" ] ;
+    }
+  }
+}
+
+/* --------------------------------------------------------------------------
+   MagSta_a : Magnetic vector potential a formulation (2D)
+   -------------------------------------------------------------------------- */
+
+Constraint {
+  { Name a ;
+    Case {
+      { Region Dirichlet_a_0 ; Value 0. ; }
+    }
+  }
+}
+
+FunctionSpace {
+
+  { Name Hcurl_a ; Type Form1P ;
+    BasisFunction {
+      { Name se ; NameOfCoef ae ; Function BF_PerpendicularEdge ;
+        Support Domain ; Entity NodesOf[ All ] ; }
+    }
+    Constraint {
+      { NameOfCoef ae ; EntityType NodesOf ; NameOfConstraint a ; }
+    }
+  }
+
+}
+
+Formulation {
+  { Name MagSta_a ; Type FemEquation ;
+    Quantity {
+      { Name a  ; Type Local ; NameOfSpace Hcurl_a ; }
+    }
+    Equation {
+      Galerkin { [ nu[] * Dof{d a} , {d a} ] ;
+                 In Domain ; Jacobian JVol ; Integration I1 ; }
+
+      Galerkin { [ hc[] , {d a} ] ;
+                 In Domain_M ; Jacobian JVol ; Integration I1 ; }
+
+      Galerkin { [ -js[] , {a} ] ;
+                 In Domain_S ; Jacobian JVol ; Integration I1 ; }
+    }
+  }
+}
+
+Resolution {
+  { Name MagSta_a ;
+    System {
+      { Name A ; NameOfFormulation MagSta_a ; }
+    }
+    Operation {
+      Generate[A] ; Solve[A] ; SaveSolution[A];
+    }
+  }
+}
+
+PostProcessing {
+  { Name MagSta_a ; NameOfFormulation MagSta_a ;
+    Quantity {
+      { Name a ; Value { Local { [ CompZ[{a}] ]   ; In Domain ; Jacobian JVol ; } } }
+      { Name b ; Value { Local { [ {d a} ]        ; In Domain ; Jacobian JVol ; } } }
+      { Name a ; Value { Local { [ {a} ]          ; In Domain ; Jacobian JVol ; } } }
+      { Name h ; Value { Local { [ nu[] * {d a} ] ; In Domain ; Jacobian JVol ; }
+                         Local { [ hc[] ]         ; In Domain_M ; Jacobian JVol ; } } }
+    }
+  }
+}
+
+PostOperation {
+  { Name MagSta_a ; NameOfPostProcessing MagSta_a;
+    Operation {
+      Print[ b, OnElementsOf Domain, File "MagSta_a_b.pos" ] ;
+      Print[ h, OnElementsOf Domain, File "MagSta_a_h.pos" ] ;
+      Print[ a, OnElementsOf Domain, File "MagSta_a_a.pos" ] ;
+    }
+  }
+}
diff --git a/contrib/mobile/Android/res/raw/pmsm_8p_circuit_pro b/contrib/mobile/Android/res/raw/pmsm_8p_circuit_pro
new file mode 100644
index 0000000000..37e1ac3756
--- /dev/null
+++ b/contrib/mobile/Android/res/raw/pmsm_8p_circuit_pro
@@ -0,0 +1,123 @@
+//
+// Circuit for Permanent Magnet Synchronous Generator - cbmag
+//
+
+Group{
+  // Dummy numbers for circuit definition
+  R1 = #55551 ;
+  R2 = #55552 ;
+  R3 = #55553 ;
+
+  Input1 = #10001 ;
+  Input2 = #10002 ;
+  Input3 = #10003 ;
+  Input4 = #10004 ;
+
+  Resistance_Cir  = Region[{R1, R2, R3}];
+  DomainZ_Cir = Region[ {Resistance_Cir} ];
+
+  DomainSource_Cir = Region[ {} ] ;
+  If(Flag_SrcType_Stator>1)
+    DomainSource_Cir += Region[ {Input1, Input2, Input3} ] ;
+  EndIf
+
+  DomainZt_Cir    = Region[ {DomainZ_Cir, DomainSource_Cir} ];
+}
+
+// --------------------------------------------------------------------------
+// --------------------------------------------------------------------------
+
+Function {
+  // Open circuit - load - short circuit
+  DefineConstant[ ZR = {200,
+      Choices{1e-8, 200, 1e8}, Label "Load resistance",  Path "Input/", Highlight "AliceBlue"} ];
+  Resistance[#{R1, R2, R3}]  = ZR ;
+}
+
+// --------------------------------------------------------------------------
+
+Constraint {
+
+  If (SymmetryFactor<8)
+    If(Flag_SrcType_Stator==0)
+      { Name ElectricalCircuit ; Type Network ;
+        Case Circuit1 {
+          { Region Stator_Ind_Ap ; Branch {100,102} ; }
+          { Region Stator_Ind_Am ; Branch {103,102} ; }
+          { Region R1            ; Branch {103,100} ; }
+        }
+        Case Circuit2 {
+          { Region Stator_Ind_Bp ; Branch {200,202} ; }
+          { Region Stator_Ind_Bm ; Branch {203,202} ; }
+          { Region R2            ; Branch {203,200} ; }
+        }
+        Case Circuit3 {
+          { Region Stator_Ind_Cp ; Branch {300,302} ; }
+          { Region Stator_Ind_Cm ; Branch {303,302} ; }
+          { Region R3            ; Branch {303,300} ; }
+        }
+      }
+    EndIf
+    If (Flag_SrcType_Stator==2)
+      { Name ElectricalCircuit ; Type Network ;
+        Case Circuit1 {
+          { Region Input1        ; Branch {100,101} ; }
+          { Region Stator_Ind_Ap ; Branch {101,102} ; }
+          { Region Stator_Ind_Am ; Branch {103,102} ; }
+          { Region R1            ; Branch {103,100} ; }
+        }
+        Case Circuit2 {
+          { Region Input2        ; Branch {200,201} ; }
+          { Region Stator_Ind_Bp ; Branch {201,202} ; }
+          { Region Stator_Ind_Bm ; Branch {203,202} ; }
+          { Region R2            ; Branch {203,200} ; }
+        }
+        Case Circuit3 {
+          { Region Input3        ; Branch {300,301} ; }
+          { Region Stator_Ind_Cp ; Branch {301,302} ; }
+          { Region Stator_Ind_Cm ; Branch {303,302} ; }
+          { Region R3            ; Branch {303,300} ; }
+        }
+      }
+    EndIf
+  EndIf
+
+  If(SymmetryFactor==8)
+    If(Flag_SrcType_Stator==0) // Only one physical region in geo allow per branch
+      { Name ElectricalCircuit ; Type Network ;
+        Case Circuit1 {
+          { Region PhaseA        ; Branch {100,102} ; }
+          { Region R1            ; Branch {102,100} ; }
+        }
+        Case Circuit2 {
+          { Region PhaseB        ; Branch {200,202} ; }
+          { Region R2            ; Branch {202,200} ; }
+        }
+        Case Circuit3 {
+          { Region PhaseC        ; Branch {300,302} ; }
+          { Region R3            ; Branch {302,300} ; }
+        }
+      }
+    EndIf
+    If(Flag_SrcType_Stator==2) // Only one physical region in geo allow per branch
+      { Name ElectricalCircuit ; Type Network ;
+        Case Circuit1 {
+          { Region Input1        ; Branch {100,101} ; }
+          { Region PhaseA        ; Branch {101,102} ; }
+          { Region R1            ; Branch {102,100} ; }
+        }
+        Case Circuit2 {
+          { Region Input2        ; Branch {200,201} ; }
+          { Region PhaseB        ; Branch {201,202} ; }
+          { Region R2            ; Branch {202,200} ; }
+        }
+        Case Circuit3 {
+          { Region Input3        ; Branch {300,301} ; }
+          { Region PhaseC        ; Branch {302,301} ; }
+          { Region R3            ; Branch {302,300} ; }
+        }
+      }
+    EndIf
+  EndIf
+}
+
diff --git a/contrib/mobile/Android/res/raw/pmsm_data_geo b/contrib/mobile/Android/res/raw/pmsm_data_geo
new file mode 100644
index 0000000000..c2760986cf
--- /dev/null
+++ b/contrib/mobile/Android/res/raw/pmsm_data_geo
@@ -0,0 +1,104 @@
+// Permanent magnet synchronous machine
+// Example of Prof. Dr. Mauricio Valencia Ferreira da Luz (Florianopolis, August 23, 2010)
+
+// Modified and customised for Onelab by Ruth V. Sabariego (February, 2013)
+
+mm = 1e-3 ;
+deg2rad = Pi/180 ;
+
+DefineConstant[ NbrPoles = { 1, Choices {1="1",
+                                         2="2",
+                                         4="4",
+                                         8="8"},
+                             Label "Number of poles in FE model",
+                             Path "Input/1", Highlight "Blue", Visible 1} ] ;
+
+DefineConstant[ InitialRotorAngle_deg = {7.5, Label "Start rotor angle", Path "Input/20", Highlight "AliceBlue"} ];
+
+//--------------------------------------------------------------------------------
+
+InitialRotorAngle = InitialRotorAngle_deg*deg2rad ; // initial rotor angle, 0 if aligned
+
+AxialLength = 35*mm ;
+
+//------------------------------------------------
+//------------------------------------------------
+NbrPolesTot = 8 ; // number of poles in complete cross-section
+
+SymmetryFactor = NbrPolesTot/NbrPoles ;
+Flag_Symmetry = (SymmetryFactor==1)?0:1 ;
+
+NbrSectTot = NbrPolesTot ; // number of "rotor teeth"
+NbrSect = NbrSectTot*NbrPoles/NbrPolesTot ; // number of "rotor teeth" in FE model
+//--------------------------------------------------------------------------------
+
+//------------------------------------------------
+// Stator
+//------------------------------------------------
+NbrSectTotStator  = 24; // number of stator teeth
+NbrSectStator   = NbrSectTotStator*NbrPoles/NbrPolesTot; // number of stator teeth in FE model
+//--------------------------------------------------------------------------------
+
+lm = 2.352*mm ; // magnet height
+Th_magnet = 32.67 *deg2rad ;  // angle in degrees 0 < Th_magnet < 45
+
+//--------------------------------------------------------------------------------
+
+rRext = 25.6*mm;
+rR1 = 10.5*mm;
+rR2 = (rRext-lm); //23.243e-03;
+rR3 = (rRext-0.7389*lm); //23.862e-03;
+rR4 = (rRext-0.72278*lm); //23.9e-03;
+rR5 = rRext; //25.6e-03;
+
+rS1 = 26.02*mm;
+rS2 = 26.62*mm;
+rS3 = 26.96*mm;
+rS4 = 38.16*mm;
+rS5 = 38.27*mm;
+rS6 = 40.02*mm;
+rS7 = 46.00*mm;
+
+Gap = rS1-rR5;
+
+rB1  = rR5+Gap/3;
+rB1b = rB1;
+rB2  = rR5+Gap*2/3;
+
+
+A0 =  45 * deg2rad ; // with this choice, axis A of stator is at 30 degrees with regard to horizontal axis
+A1 =   0 * deg2rad ; // Rotor initial aligned position, current position in angRot
+
+// ----------------------------------------------------
+// Numbers for physical regions in .geo and .pro files
+// ----------------------------------------------------
+// Rotor
+ROTOR_FE     = 1000 ;
+ROTOR_AIR    = 1001 ;
+ROTOR_AIRGAP = 1002 ;
+ROTOR_MAGNET = 1010 ; // Index for first Magnet (1/8 model->1; full model->8)
+
+ROTOR_BND_MOVING_BAND = 1100 ; // Index for first line (1/8 model->1; full model->8)
+ROTOR_BND_A0 = 1200 ;
+ROTOR_BND_A1 = 1201 ;
+SURF_INT     = 1202 ;
+
+// Stator
+STATOR_FE     = 2000 ;
+STATOR_AIR    = 2001 ;
+STATOR_AIRGAP = 2002 ;
+
+STATOR_BND_MOVING_BAND = 2100 ;// Index for first line (1/8 model->1; full model->8)
+STATOR_BND_A0          = 2200 ;
+STATOR_BND_A1          = 2201 ;
+
+STATOR_IND = 2300 ; //Index for first Ind (1/8 model->3; full model->24)
+STATOR_IND_AP = STATOR_IND + 1 ; STATOR_IND_BM = STATOR_IND + 2 ;STATOR_IND_CP = STATOR_IND + 3 ;
+STATOR_IND_AM = STATOR_IND + 4 ; STATOR_IND_BP = STATOR_IND + 5 ;STATOR_IND_CM = STATOR_IND + 6 ;
+
+SURF_EXT = 3000 ; // outer boundary
+
+
+MOVING_BAND = 9999 ;
+
+NICEPOS = 111111 ;
diff --git a/contrib/mobile/Android/res/raw/pmsm_geo b/contrib/mobile/Android/res/raw/pmsm_geo
new file mode 100644
index 0000000000..efade112ec
--- /dev/null
+++ b/contrib/mobile/Android/res/raw/pmsm_geo
@@ -0,0 +1,95 @@
+Include "pmsm_data.geo";
+
+Mesh.Algorithm = 1;
+Geometry.CopyMeshingMethod = 1;
+
+Mesh.CharacteristicLengthFactor = 1.5 ;
+
+
+// Mesh characteristic lengths
+s = 0.4 ;
+pR1=(rR2-rR1)/6.*s;
+pR2=(rR2-rR1)/6.*s;
+
+pS1=(rS7-rS1)/7.*s;
+pS2=(rS7-rS1)/12.*s;
+pS3=(rS6-rS3)/10.*s;
+
+NbrDivMB = 2*Ceil[2*Pi*rRext/8/pR1]; //1/8 Moving band
+
+//--------------------------------------------------------------------------------
+//--------------------------------------------------------------------------------
+
+cen = newp ; Point(cen)={0,0,0,pR1};
+nicepos_rotor[] = {};
+nicepos_stator[] = {};
+
+Include "pmsm_rotor.geo";
+Include "pmsm_stator.geo";
+
+
+// For nice visualisation...
+Mesh.Light = 0 ;
+//Mesh.SurfaceFaces = 1; Mesh.SurfaceEdges=0;
+
+Hide { Point{ Point '*' }; }
+Hide { Line{ Line '*' }; }
+Show { Line{ nicepos_rotor[], nicepos_stator[] }; }
+
+Physical Line(NICEPOS) = { nicepos_rotor[], nicepos_stator[] };
+
+//For post-processing...
+View[0].Light = 0;
+View[0].NbIso = 25; // Number of intervals
+View[0].IntervalsType = 1;
+
+DefineConstant[ Flag_AddInfo = {0, Choices{0,1},
+                               Label "Add info about phases and axis",
+                               Path "Input/1"} ];
+
+For i In {PostProcessing.NbViews-1 : 0 : -1}
+  If(StrFind(View[i].Attributes, "tmp"))
+    Delete View[i];
+  EndIf
+EndFor
+
+If(Flag_AddInfo)
+  rr = 1.25 * rS3 ;
+  For k In {0:NbrPoles-1}
+    xa[] += rr*Cos(1*Pi/24+k*Pi/4) ; ya[] += rr*Sin(1*Pi/24+k*Pi/4) ;
+    xb[] += rr*Cos(3*Pi/24+k*Pi/4) ; yb[] += rr*Sin(3*Pi/24+k*Pi/4) ;
+    xc[] += rr*Cos(5*Pi/24+k*Pi/4) ; yc[] += rr*Sin(5*Pi/24+k*Pi/4) ;
+  EndFor
+
+  // Adding some axes
+  rr0 = 0.3 * rS7 ;
+  rr1 = 1.3 * rS7 ;
+  th_d = InitialRotorAngle ;
+  th_q = th_d + 22.5 * deg2rad ;
+
+  th_a = 30 * deg2rad ;
+  th_b = (30 + 120/4) * deg2rad ;
+  th_c = (30 + 240/4) * deg2rad ;
+
+  ff = 0.9;
+
+  xd[0] = rr0*Cos(th_d) ;    yd[0] = rr0*Sin(th_d) ;
+  xd[1] = ff*rr1*Cos(th_d) ; yd[1] = ff*rr1*Sin(th_d) ;
+  xq[0] = rr0*Cos(th_q) ;    yq[0] = rr0*Sin(th_q) ;
+  xq[1] = ff*rr1*Cos(th_q) ; yq[1] = ff*rr1*Sin(th_q) ;
+
+  xaa[0] = rr0*Cos(th_a) ; yaa[0] = rr0*Sin(th_a) ;
+  xaa[1] = rr1*Cos(th_a) ; yaa[1] = rr1*Sin(th_a) ;
+  xbb[0] = rr0*Cos(th_b) ; ybb[0] = rr0*Sin(th_b) ;
+  xbb[1] = rr1*Cos(th_b) ; ybb[1] = rr1*Sin(th_b) ;
+  xcc[0] = rr0*Cos(th_c) ; ycc[0] = rr0*Sin(th_c) ;
+  xcc[1] = rr1*Cos(th_c) ; ycc[1] = rr1*Sin(th_c) ;
+
+
+  Include "info_view.geo";
+
+EndIf
+
+
+
+
diff --git a/contrib/mobile/Android/res/raw/pmsm_geo_pro b/contrib/mobile/Android/res/raw/pmsm_geo_pro
new file mode 100644
index 0000000000..225b29dd4f
--- /dev/null
+++ b/contrib/mobile/Android/res/raw/pmsm_geo_pro
@@ -0,0 +1,211 @@
+//
+// Permanent Magnet Synchronous Generator
+//
+
+Include "pmsm_data.geo";
+
+DefineConstant[ Flag_NL = {0,
+    Choices{ 0="Linear",
+             1="Nonlinear BH curve"},
+    Label "Fe magnetic law",
+    Path "Input/3", Highlight "Blue"} ] ;
+
+DefineConstant[ Flag_SrcType_Stator = {0,
+    Choices{ 0="None",
+      1="Current" },
+    Label "Source Type in Stator",
+    Path "Input/4", Highlight "Blue", Visible 1} ] ;
+
+DefineConstant[ Flag_SrcType_Rotor = {0,
+    Choices{ 0="None",
+      1="Current" },
+    Label "Source Type in Rotor",
+    Path "Input/5", Highlight "Blue", Visible 0} ] ;
+
+DefineConstant[ Flag_Cir = {!Flag_SrcType_Stator, Choices{0,1},
+    Label "Use circuit in Stator", ReadOnly 1, Visible 0} ] ;
+
+Group {
+  Stator_Fe     = #STATOR_FE ;
+  Stator_Al     = #{};
+  Stator_Cu     = #{};
+  Stator_Air    = #STATOR_AIR ;
+  Stator_Airgap = #STATOR_AIRGAP ;
+
+  Stator_Bnd_A0 = #STATOR_BND_A0 ;
+  Stator_Bnd_A1 = #STATOR_BND_A1 ;
+
+  Rotor_Fe     = #ROTOR_FE ;
+  Rotor_Al     = #{};
+  Rotor_Cu     = #{};
+  Stator_Air    = #STATOR_AIR ;
+  Stator_Airgap = #STATOR_AIRGAP ;
+  Stator_Bnd_MB = #STATOR_BND_MOVING_BAND ;
+  Stator_Bnd_A0 = #STATOR_BND_A0 ;
+  Stator_Bnd_A1 = #STATOR_BND_A1 ;
+
+  Rotor_Fe     = #ROTOR_FE ;
+  Rotor_Air    = #ROTOR_AIR ;
+  Rotor_Airgap = #ROTOR_AIRGAP ;
+
+  Rotor_Bnd_A0 = #ROTOR_BND_A0 ;
+  Rotor_Bnd_A1 = #ROTOR_BND_A1 ;
+
+  MovingBand_PhysicalNb = #MOVING_BAND ;  // Fictitious number for moving band, not in the geo file
+  Surf_Inf = #SURF_EXT ;
+  Surf_bn0 = #SURF_INT ;
+  Surf_cutA0 = #{STATOR_BND_A0, ROTOR_BND_A0};
+  Surf_cutA1 = #{STATOR_BND_A1, ROTOR_BND_A1};
+
+  Dummy = #NICEPOS;
+
+  nbMagnets = NbrPolesTot/SymmetryFactor ;
+  For k In {1:nbMagnets}
+    Rotor_Magnet~{k} = Region[ (ROTOR_MAGNET+k-1) ];
+    Rotor_Magnets += Region[ Rotor_Magnet~{k} ];
+  EndFor
+
+  nbInds = (Flag_Symmetry) ? NbrPoles*NbrSectTotStator/NbrPolesTot : NbrSectTotStator ;
+  Printf("NbrPoles=%g, nbInds=%g SymmetryFactor=%g", NbrPoles, nbInds, SymmetryFactor);
+
+  Stator_Ind_Ap = #{};              Stator_Ind_Am = #{STATOR_IND_AM};
+  Stator_Ind_Bp = #{};              Stator_Ind_Bm = #{STATOR_IND_BM};
+  Stator_Ind_Cp = #{STATOR_IND_CP}; Stator_Ind_Cm = #{};
+  If(NbrPoles > 1)
+    Stator_Ind_Ap += #STATOR_IND_AP;
+    Stator_Ind_Bp += #STATOR_IND_BP;
+    Stator_Ind_Cm += #STATOR_IND_CM;
+  EndIf
+
+  PhaseA = Region[{ Stator_Ind_Ap, Stator_Ind_Am }];
+  PhaseB = Region[{ Stator_Ind_Bp, Stator_Ind_Bm }];
+  PhaseC = Region[{ Stator_Ind_Cp, Stator_Ind_Cm }];
+
+  // Provisional: Just one physical region for nice graph in Onelab
+  PhaseA_pos = Region[{ Stator_Ind_Am }];
+  PhaseB_pos = Region[{ Stator_Ind_Bm }];
+  PhaseC_pos = Region[{ Stator_Ind_Cp }];
+
+  Stator_IndsP = Region[{ Stator_Ind_Ap, Stator_Ind_Bp, Stator_Ind_Cp }];
+  Stator_IndsN = Region[{ Stator_Ind_Am, Stator_Ind_Bm, Stator_Ind_Cm }];
+
+  Stator_Inds = Region[ {PhaseA, PhaseB, PhaseC} ] ;
+  Rotor_Inds  = Region[ {} ] ;
+
+  StatorC  = Region[{ }] ;
+  StatorCC = Region[{ Stator_Fe }] ;
+  RotorC   = Region[{ }] ;
+  RotorCC  = Region[{ Rotor_Fe, Rotor_Magnets }] ;
+
+  // Moving band:  with or without symmetry, these BND lines must be complete
+  Stator_Bnd_MB = #STATOR_BND_MOVING_BAND;
+  For k In {1:SymmetryFactor}
+    Rotor_Bnd_MB~{k} = Region[ (ROTOR_BND_MOVING_BAND+k-1) ];
+    Rotor_Bnd_MB += Region[ Rotor_Bnd_MB~{k} ];
+  EndFor
+  Rotor_Bnd_MBaux = Region[ {Rotor_Bnd_MB, -Rotor_Bnd_MB~{1}}];
+
+}
+
+// --------------------------------------------------------------------------
+// --------------------------------------------------------------------------
+
+Function {
+
+  mur_fe = 1000 ;
+  sigma_fe = 0 ;
+
+  NbrPhases = 3 ;
+  NbrPolePairs = NbrPolesTot/2 ;
+
+  DefineConstant[ b_remanent = { 1.2, Label "Remanent induction", Path "Input/3", Highlight "AliceBlue"} ] ;
+  // For a radial remanent b
+  For k In {1:nbMagnets}
+    br[ Rotor_Magnet~{k} ] = (-1)^(k-1) * b_remanent * Vector[ Cos[Atan2[Y[],X[]]], Sin[Atan2[Y[],X[]]], 0 ];
+  EndFor
+
+  Inominal = 3.9 ; // Nominal current
+  Tnominal = 2.5 ; // Nominal torque
+
+  //Data for modeling a stranded inductor
+  NbWires[]  = 104 ; // Number of wires per slot
+  // STATOR_IND_AM comprises all the slots in that phase, we need thus to divide by the number of slots
+  nbSlots[] = Ceil[nbInds/NbrPhases/2] ;
+  SurfCoil[] = SurfaceArea[]{STATOR_IND_AM}/nbSlots[] ;//All inductors have the same surface
+
+  FillFactor_Winding = 0.5 ; // percentage of Cu in the surface coil side, smaller than 1
+  Factor_R_3DEffects = 1.5 ; // bigger than Adding 50% of resistance
+
+  DefineConstant[ rpm = { 500,
+                          Label "speed in rpm",
+                          Path "Input/7", Highlight "AliceBlue"} ]; // speed in rpm
+  wr = rpm/60*2*Pi ; // speed in rad_mec/s
+
+  // supply at fixed position
+  DefineConstant[ Freq = {wr*NbrPolePairs/(2*Pi), ReadOnly 1,
+                          Path "Output/1", Highlight "LightYellow" } ];
+  Omega = 2*Pi*Freq ;
+  T = 1/Freq ;
+
+  DefineConstant[ thetaMax_deg = { 180, Label "End rotor angle (loop)",
+      Path "Input/21", Highlight "AliceBlue" } ];
+
+  theta0   = InitialRotorAngle + 0. ;
+  thetaMax = thetaMax_deg * deg2rad ; // end rotor angle (used in doing a loop)
+
+  DefineConstant[ NbTurns  = { (thetaMax-theta0)/(2*Pi), Label "Number of revolutions",
+      Path "Input/24", Highlight "LightGrey", ReadOnly 1} ];
+
+  DefineConstant[ delta_theta_deg = { 1., Label "step in degrees",
+      Path "Input/22", Highlight "AliceBlue"} ];
+
+  delta_theta = delta_theta_deg * deg2rad ;
+
+  time0 = 0 ; // at initial rotor position
+  delta_time = delta_theta/wr;
+  timemax = thetaMax/wr;
+
+  DefineConstant[ NbSteps = { Ceil[(timemax-time0)/delta_time], Label "Number of steps",
+      Path "Input/23", Highlight "LightGrey", ReadOnly 1} ];
+
+  RotorPosition[] = InitialRotorAngle + $Time * wr ;
+  RotorPosition_deg[] = RotorPosition[]*180/Pi;
+
+  Flag_ParkTransformation = 1 ;
+  Theta_Park[] = ((RotorPosition[] + Pi/8) - Pi/6) * NbrPolePairs; // electrical degrees
+  Theta_Park_deg[] = Theta_Park[]*180/Pi;
+
+  DefineConstant[ ID = { 0, Path "Input/60", Label "Id stator current", Highlight "AliceBlue"},
+    IQ = { Inominal, Path "Input/61", Label "Iq stator current", Highlight "AliceBlue"},
+    I0 = { 0, Visible 0} ] ;
+
+  If(Flag_SrcType_Stator==0)
+    UndefineConstant["Input/60ID"];
+    UndefineConstant["Input/61IQ"];
+  EndIf
+}
+
+// --------------------------------------------------------------------------
+// --------------------------------------------------------------------------
+// --------------------------------------------------------------------------
+
+Dir="res/";
+ExtGmsh     = ".pos";
+ExtGnuplot  = ".dat";
+
+// --------------------------------------------------------------------------
+// --------------------------------------------------------------------------
+// --------------------------------------------------------------------------
+
+If(Flag_SrcType_Stator==1)
+    UndefineConstant["Input/ZR"];
+EndIf
+
+If(Flag_Cir)
+  Include "pmsm_8p_circuit.pro" ;
+EndIf
+Include "machine_magstadyn_a.pro" ;
+
+DefineConstant[ ResolutionChoices    = {"TimeDomain_Loop", Path "GetDP/1"} ];
+DefineConstant[ PostOperationChoices = {"Map_LocalFields", Path "GetDP/2"} ];
+DefineConstant[ ComputeCommand       = {"-solve -v 1 -v2", Path "GetDP/9"} ];
diff --git a/contrib/mobile/Android/res/raw/pmsm_pro b/contrib/mobile/Android/res/raw/pmsm_pro
new file mode 100644
index 0000000000..b9ee5ce16a
--- /dev/null
+++ b/contrib/mobile/Android/res/raw/pmsm_pro
@@ -0,0 +1,211 @@
+//
+// Permanent Magnet Synchronous Generator
+//
+
+Include "pmsm_data.geo";
+
+DefineConstant[ Flag_NL = {0,
+    Choices{ 0="Linear",
+             1="Nonlinear BH curve"},
+    Label "Fe magnetic law",
+    Path "Input/3", Highlight "Blue"} ] ;
+
+DefineConstant[ Flag_SrcType_Stator = {1,
+    Choices{ 0="None",
+      1="Current" },
+    Label "Source Type in Stator",
+    Path "Input/4", Highlight "Blue", Visible 1} ] ;
+
+DefineConstant[ Flag_SrcType_Rotor = {0,
+    Choices{ 0="None",
+      1="Current" },
+    Label "Source Type in Rotor",
+    Path "Input/5", Highlight "Blue", Visible 0} ] ;
+
+DefineConstant[ Flag_Cir = {!Flag_SrcType_Stator, Choices{0,1},
+    Label "Use circuit in Stator", ReadOnly 1, Visible 0} ] ;
+
+Group {
+  Stator_Fe     = #STATOR_FE ;
+  Stator_Al     = #{};
+  Stator_Cu     = #{};
+  Stator_Air    = #STATOR_AIR ;
+  Stator_Airgap = #STATOR_AIRGAP ;
+
+  Stator_Bnd_A0 = #STATOR_BND_A0 ;
+  Stator_Bnd_A1 = #STATOR_BND_A1 ;
+
+  Rotor_Fe     = #ROTOR_FE ;
+  Rotor_Al     = #{};
+  Rotor_Cu     = #{};
+  Stator_Air    = #STATOR_AIR ;
+  Stator_Airgap = #STATOR_AIRGAP ;
+  Stator_Bnd_MB = #STATOR_BND_MOVING_BAND ;
+  Stator_Bnd_A0 = #STATOR_BND_A0 ;
+  Stator_Bnd_A1 = #STATOR_BND_A1 ;
+
+  Rotor_Fe     = #ROTOR_FE ;
+  Rotor_Air    = #ROTOR_AIR ;
+  Rotor_Airgap = #ROTOR_AIRGAP ;
+
+  Rotor_Bnd_A0 = #ROTOR_BND_A0 ;
+  Rotor_Bnd_A1 = #ROTOR_BND_A1 ;
+
+  MovingBand_PhysicalNb = #MOVING_BAND ;  // Fictitious number for moving band, not in the geo file
+  Surf_Inf = #SURF_EXT ;
+  Surf_bn0 = #SURF_INT ;
+  Surf_cutA0 = #{STATOR_BND_A0, ROTOR_BND_A0};
+  Surf_cutA1 = #{STATOR_BND_A1, ROTOR_BND_A1};
+
+  Dummy = #NICEPOS;
+
+  nbMagnets = NbrPolesTot/SymmetryFactor ;
+  For k In {1:nbMagnets}
+    Rotor_Magnet~{k} = Region[ (ROTOR_MAGNET+k-1) ];
+    Rotor_Magnets += Region[ Rotor_Magnet~{k} ];
+  EndFor
+
+  nbInds = (Flag_Symmetry) ? NbrPoles*NbrSectTotStator/NbrPolesTot : NbrSectTotStator ;
+  Printf("NbrPoles=%g, nbInds=%g SymmetryFactor=%g", NbrPoles, nbInds, SymmetryFactor);
+
+  Stator_Ind_Ap = #{};              Stator_Ind_Am = #{STATOR_IND_AM};
+  Stator_Ind_Bp = #{};              Stator_Ind_Bm = #{STATOR_IND_BM};
+  Stator_Ind_Cp = #{STATOR_IND_CP}; Stator_Ind_Cm = #{};
+  If(NbrPoles > 1)
+    Stator_Ind_Ap += #STATOR_IND_AP;
+    Stator_Ind_Bp += #STATOR_IND_BP;
+    Stator_Ind_Cm += #STATOR_IND_CM;
+  EndIf
+
+  PhaseA = Region[{ Stator_Ind_Ap, Stator_Ind_Am }];
+  PhaseB = Region[{ Stator_Ind_Bp, Stator_Ind_Bm }];
+  PhaseC = Region[{ Stator_Ind_Cp, Stator_Ind_Cm }];
+
+  // Provisional: Just one physical region for nice graph in Onelab
+  PhaseA_pos = Region[{ Stator_Ind_Am }];
+  PhaseB_pos = Region[{ Stator_Ind_Bm }];
+  PhaseC_pos = Region[{ Stator_Ind_Cp }];
+
+  Stator_IndsP = Region[{ Stator_Ind_Ap, Stator_Ind_Bp, Stator_Ind_Cp }];
+  Stator_IndsN = Region[{ Stator_Ind_Am, Stator_Ind_Bm, Stator_Ind_Cm }];
+
+  Stator_Inds = Region[ {PhaseA, PhaseB, PhaseC} ] ;
+  Rotor_Inds  = Region[ {} ] ;
+
+  StatorC  = Region[{ }] ;
+  StatorCC = Region[{ Stator_Fe }] ;
+  RotorC   = Region[{ }] ;
+  RotorCC  = Region[{ Rotor_Fe, Rotor_Magnets }] ;
+
+  // Moving band:  with or without symmetry, these BND lines must be complete
+  Stator_Bnd_MB = #STATOR_BND_MOVING_BAND;
+  For k In {1:SymmetryFactor}
+    Rotor_Bnd_MB~{k} = Region[ (ROTOR_BND_MOVING_BAND+k-1) ];
+    Rotor_Bnd_MB += Region[ Rotor_Bnd_MB~{k} ];
+  EndFor
+  Rotor_Bnd_MBaux = Region[ {Rotor_Bnd_MB, -Rotor_Bnd_MB~{1}}];
+
+}
+
+// --------------------------------------------------------------------------
+// --------------------------------------------------------------------------
+
+Function {
+
+  mur_fe = 1000 ;
+  sigma_fe = 0 ;
+
+  NbrPhases = 3 ;
+  NbrPolePairs = NbrPolesTot/2 ;
+
+  DefineConstant[ b_remanent = { 1.2, Label "Remanent induction", Path "Input/3", Highlight "AliceBlue"} ] ;
+  // For a radial remanent b
+  For k In {1:nbMagnets}
+    br[ Rotor_Magnet~{k} ] = (-1)^(k-1) * b_remanent * Vector[ Cos[Atan2[Y[],X[]]], Sin[Atan2[Y[],X[]]], 0 ];
+  EndFor
+
+  Inominal = 3.9 ; // Nominal current
+  Tnominal = 2.5 ; // Nominal torque
+
+  //Data for modeling a stranded inductor
+  NbWires[]  = 104 ; // Number of wires per slot
+  // STATOR_IND_AM comprises all the slots in that phase, we need thus to divide by the number of slots
+  nbSlots[] = Ceil[nbInds/NbrPhases/2] ;
+  SurfCoil[] = SurfaceArea[]{STATOR_IND_AM}/nbSlots[] ;//All inductors have the same surface
+
+  FillFactor_Winding = 0.5 ; // percentage of Cu in the surface coil side, smaller than 1
+  Factor_R_3DEffects = 1.5 ; // bigger than Adding 50% of resistance
+
+  DefineConstant[ rpm = { 500,
+                          Label "speed in rpm",
+                          Path "Input/7", Highlight "AliceBlue"} ]; // speed in rpm
+  wr = rpm/60*2*Pi ; // speed in rad_mec/s
+
+  // supply at fixed position
+  DefineConstant[ Freq = {wr*NbrPolePairs/(2*Pi), ReadOnly 1,
+                          Path "Output/1", Highlight "LightYellow" } ];
+  Omega = 2*Pi*Freq ;
+  T = 1/Freq ;
+
+  DefineConstant[ thetaMax_deg = { 180, Label "End rotor angle (loop)",
+      Path "Input/21", Highlight "AliceBlue" } ];
+
+  theta0   = InitialRotorAngle + 0. ;
+  thetaMax = thetaMax_deg * deg2rad ; // end rotor angle (used in doing a loop)
+
+  DefineConstant[ NbTurns  = { (thetaMax-theta0)/(2*Pi), Label "Number of revolutions",
+      Path "Input/24", Highlight "LightGrey", ReadOnly 1} ];
+
+  DefineConstant[ delta_theta_deg = { 1., Label "step in degrees",
+      Path "Input/22", Highlight "AliceBlue"} ];
+
+  delta_theta = delta_theta_deg * deg2rad ;
+
+  time0 = 0 ; // at initial rotor position
+  delta_time = delta_theta/wr;
+  timemax = thetaMax/wr;
+
+  DefineConstant[ NbSteps = { Ceil[(timemax-time0)/delta_time], Label "Number of steps",
+      Path "Input/23", Highlight "LightGrey", ReadOnly 1} ];
+
+  RotorPosition[] = InitialRotorAngle + $Time * wr ;
+  RotorPosition_deg[] = RotorPosition[]*180/Pi;
+
+  Flag_ParkTransformation = 1 ;
+  Theta_Park[] = ((RotorPosition[] + Pi/8) - Pi/6) * NbrPolePairs; // electrical degrees
+  Theta_Park_deg[] = Theta_Park[]*180/Pi;
+
+  DefineConstant[ ID = { 0, Path "Input/60", Label "Id stator current", Highlight "AliceBlue"},
+    IQ = { Inominal, Path "Input/61", Label "Iq stator current", Highlight "AliceBlue"},
+    I0 = { 0, Visible 0} ] ;
+
+  If(Flag_SrcType_Stator==0)
+    UndefineConstant["Input/60ID"];
+    UndefineConstant["Input/61IQ"];
+  EndIf
+}
+
+// --------------------------------------------------------------------------
+// --------------------------------------------------------------------------
+// --------------------------------------------------------------------------
+
+Dir="res/";
+ExtGmsh     = ".pos";
+ExtGnuplot  = ".dat";
+
+// --------------------------------------------------------------------------
+// --------------------------------------------------------------------------
+// --------------------------------------------------------------------------
+
+If(Flag_SrcType_Stator==1)
+    UndefineConstant["Input/ZR"];
+EndIf
+
+If(Flag_Cir)
+  Include "pmsm_8p_circuit.pro" ;
+EndIf
+Include "machine_magstadyn_a.pro" ;
+
+DefineConstant[ ResolutionChoices    = {"TimeDomain_Loop", Path "GetDP/1"} ];
+DefineConstant[ PostOperationChoices = {"Map_LocalFields", Path "GetDP/2"} ];
+DefineConstant[ ComputeCommand       = {"-solve -v 1 -v2", Path "GetDP/9"} ];
diff --git a/contrib/mobile/Android/res/raw/pmsm_rotor_geo b/contrib/mobile/Android/res/raw/pmsm_rotor_geo
new file mode 100644
index 0000000000..c051cf1a6d
--- /dev/null
+++ b/contrib/mobile/Android/res/raw/pmsm_rotor_geo
@@ -0,0 +1,163 @@
+//--------------------------------------------------------------------------------
+// Rotor PMSM
+//--------------------------------------------------------------------------------
+A = InitialRotorAngle-45/2*deg2rad + A1; // with Theta_Park
+
+sinA = Sin(A); cosA = Cos(A);
+pntR[]+=newp; Point(newp)={rR1*cosA, rR1*sinA, 0, pR1};
+pntR[]+=newp; Point(newp)={rR2*cosA, rR2*sinA, 0, pR1};
+pntR[]+=newp; Point(newp)={rR4*cosA, rR4*sinA, 0, pR1};
+pntR[]+=newp; Point(newp)={rR5*cosA, rR5*sinA, 0, pR1};
+pntR[]+=newp; Point(newp)={rB1*cosA, rB1*sinA, 0, pR2};
+
+For k In {0:#pntR[]-2}
+ linR0[]+=newl; Line(newl) = {pntR[k], pntR[k+1]};
+EndFor
+
+Transfinite Line{linR0[0]} = Ceil[(rR2-rR1)/pR1] ;
+Transfinite Line{linR0[1]} = Ceil[(rR4-rR2)/pR1] ;
+Transfinite Line{linR0[2]} = Ceil[(rR5-rR4)/pR1] ;
+Transfinite Line{linR0[3]} = Ceil[(rB1-rR5)/pR1] ;
+
+For k In {0:#linR0[]-1}
+ linR1[] += Rotate {{0, 0, 1}, {0, 0, 0}, A0+A1} { Duplicata{Line{linR0[k]};} };
+EndFor
+
+AA[] = {(A0-Th_magnet)/2+A1, Th_magnet, (A0-Th_magnet)/2+A1} ;
+
+lin[] = Extrude {{0, 0, 1}, {0, 0, 0}, AA[0]} { Point{pntR[0]}; };
+cirR[]+=lin[1];
+lin[] = Extrude {{0, 0, 1}, {0, 0, 0}, AA[1]} { Point{lin[0]}; };
+cirR[]+=lin[1];
+lin[] = Extrude {{0, 0, 1}, {0, 0, 0}, AA[2]} { Point{lin[0]}; };
+cirR[]+=lin[1];
+
+surfint[]=cirR[{0,1,2}] ; // boundary conditions
+
+pMagnet[] = Rotate {{0, 0, 1}, {0, 0, 0}, AA[0]} { Duplicata{Point{pntR[1]};} };
+lin[] = Extrude {{0, 0, 1}, {0, 0, 0}, AA[1]} { Point{pMagnet[0]}; };
+pMagnet[] += lin[0];
+cirR[] += lin[1] ;
+
+lin[] = Extrude {{0, 0, 1}, {0, 0, 0}, AA[0]} { Point{pntR[2]}; };
+cirR[]+=lin[1]; pMagnet[] += lin[0];
+pMagnet[] += Rotate {{0, 0, 1}, {0, 0, 0}, AA[1]} { Duplicata{Point{lin[0]};} };
+lin[] = Extrude {{0, 0, 1}, {0, 0, 0}, AA[2]} { Point{pMagnet[3]}; };
+cirR[]+=lin[1];
+
+lin[] = Extrude {{0, 0, 1}, {0, 0, 0}, AA[0]} { Point{pntR[3]}; };
+cirR[]+=lin[1];
+lin[] = Extrude {{0, 0, 1}, {0, 0, 0}, AA[1]} { Point{lin[0]}; };
+cirR[]+=lin[1];
+lin[] = Extrude {{0, 0, 1}, {0, 0, 0}, AA[2]} { Point{lin[0]}; };
+cirR[]+=lin[1];
+
+lin[] = Extrude {{0, 0, 1}, {0, 0, 0}, A0+A1} { Point{pntR[4]}; };
+cirR[]+=lin[1];
+
+linR2[] = Rotate {{0, 0, 1}, {0, 0, 0}, (A0-Th_magnet)/2+A1} { Duplicata{Line{linR0[{1,2}]};} };
+linR3[] = Rotate {{0, 0, 1}, {0, 0, 0},-(A0-Th_magnet)/2+A1} { Duplicata{Line{linR1[{1,2}]};} };
+
+// surfaces rotor
+Line Loop(newll) = {linR0[{0,1}], cirR[4], -linR2[0], cirR[3], linR3[0], cirR[5], -linR1[{1,0}], -cirR[{2,1,0}]};
+srotor[0]=news; Plane Surface(srotor[0]) = {newll-1};
+
+Line Loop(newl) = {linR2[1], cirR[7], -linR3[{1,0}], -cirR[3], linR2[0]};
+smagnet[0]=news; Plane Surface(smagnet[0]) = {newll-1};
+
+nn = #cirR[]-1 ;
+Line Loop(newll) = {cirR[{nn-5}], linR2[1], -cirR[{nn-3}], -linR0[2]};
+sairrotor[]+=news; Plane Surface(news) = {newll-1};
+Line Loop(newll) = {cirR[{nn-4}], linR1[2], -cirR[{nn-1}], -linR3[1]};
+sairrotor[]+=news; Plane Surface(news) = {newll-1};
+
+Line Loop(newll) = {linR0[3], cirR[nn], -linR1[3], -cirR[{nn-1:nn-3:-1}]};
+sairrotormb[]+=news; Plane Surface(news) = {newll-1};
+
+// -------------------------------------------------------------------------------
+// Moving band == AirGap rotor side
+// -------------------------------------------------------------------------------
+Transfinite Line{cirR[nn]} = NbrDivMB+1 ;
+
+//Filling the gap for the whole 2*Pi
+lineMBrotor[]=cirR[{nn}];
+For k In {1:NbrPolesTot-1}
+  lineMBrotoraux[]+=Rotate {{0, 0, 1}, {0, 0, 0}, k*A0} { Duplicata{Line{lineMBrotor[]};} };
+EndFor
+
+// -------------------------------------------------------------------------------
+// -------------------------------------------------------------------------------
+If(SymmetryFactor<8)
+// FULL MODEL ==> Rotation of NbrPolesTot*Pi/4
+// For simplicity: rotating first the interior and exterior boundaries
+
+  If (SymmetryFactor>1)
+    For k In {0:#linR1[]-1}
+      linR1_[] += Rotate {{0, 0, 1}, {0, 0, 0}, 2*Pi/SymmetryFactor-Pi/4} { Duplicata{Line{linR1[k]};} };
+    EndFor
+    linR1[] = linR1_[];
+  EndIf
+
+  For k In {1:NbrPoles-1}
+    surfint[] += Rotate {{0, 0, 1}, {0, 0, 0}, k*Pi/4} { Duplicata{ Line{surfint[{0:2}]};} };
+  EndFor
+  For k In {1:NbrPoles-1}
+    srotor[] += Rotate {{0, 0, 1}, {0, 0, 0}, k*Pi/4} { Duplicata{ Surface{srotor[0]};} };
+    smagnet[]+= Rotate {{0, 0, 1}, {0, 0, 0}, k*Pi/4} { Duplicata{ Surface{smagnet[0]};} };
+    sairrotor[]  += Rotate {{0, 0, 1}, {0, 0, 0}, k*Pi/4} { Duplicata{ Surface{sairrotor[{0,1}]};} };
+    sairrotormb[]+= Rotate {{0, 0, 1}, {0, 0, 0}, k*Pi/4} { Duplicata{ Surface{sairrotormb[0]};} };
+  EndFor
+EndIf
+
+
+// -------------------------------------------------------------------------------
+// Physical regions
+// -------------------------------------------------------------------------------
+
+Physical Surface(ROTOR_FE)     = {srotor[]};     // Rotor
+Physical Surface(ROTOR_AIR)    = {sairrotor[]};  // AirRotor
+Physical Surface(ROTOR_AIRGAP) = {sairrotormb[]};// AirRotor for possible torque computation with Maxwell stress tensor
+
+NN = (Flag_Symmetry)?NbrPoles:NbrPolesTot;
+For k In {0:NN-1}
+  Physical Surface(ROTOR_MAGNET+k) = {smagnet[k]}; // Magnets
+EndFor
+
+Physical Line(SURF_INT) = {surfint[]}; // SurfInt
+
+
+If(Flag_Symmetry)  //Lines for symmetry link
+  Physical Line(ROTOR_BND_A0)  = linR0[];
+  Physical Line(ROTOR_BND_A1)  = linR1[];
+EndIf
+
+lineMBrotor[] += lineMBrotoraux[] ;
+If(!Flag_Symmetry)
+  Physical Line(ROTOR_BND_MOVING_BAND)  = {lineMBrotor[]};
+EndIf
+If(Flag_Symmetry)
+  nr = #lineMBrotor[];
+  nnp = nr/(NbrPolesTot/NbrSect) ;
+  For k In {1:Floor[NbrPolesTot/NbrSect]}
+    kk= ((k*nnp-1) > nr) ? nr-1 : k*nnp-1 ;
+    Physical Line(ROTOR_BND_MOVING_BAND+k-1) = lineMBrotor[{(k-1)*nnp:kk}] ;
+  EndFor
+  k1 = Floor[NbrPolesTot/NbrSect];
+  k2 = Ceil[NbrPolesTot/NbrSect];
+  If (k2 > k1)
+    Physical Line(ROTOR_BND_MOVING_BAND+k2-1) = lineMBrotor[{(k2-1)*nnp:#lineMBrotor[]-1}] ;
+  EndIf
+EndIf
+
+// For nice visualisation...
+linRotor[]  = CombinedBoundary{Surface{srotor[]};};
+linMagnet[] = Boundary{Surface{smagnet[]};};
+
+nicepos_rotor[] += { linRotor[], linMagnet[] };
+
+Color SteelBlue {Surface{srotor[]};}
+Color SkyBlue {Surface{sairrotor[], sairrotormb[]};}
+Color Orchid {Surface{smagnet[{0:#smagnet[]-1:2}]};}
+If(#smagnet[]>1)
+Color Purple {Surface{smagnet[{1:#smagnet[]-1:2}]};}
+EndIf
diff --git a/contrib/mobile/Android/res/raw/pmsm_stator_geo b/contrib/mobile/Android/res/raw/pmsm_stator_geo
new file mode 100644
index 0000000000..e928a4a055
--- /dev/null
+++ b/contrib/mobile/Android/res/raw/pmsm_stator_geo
@@ -0,0 +1,215 @@
+// -------------------------------------------------------------------------------
+// Moving band == AirGap stator side
+// -------------------------------------------------------------------------------
+pntG[]+=newp; Point(newp) = {rB2, 0., 0., pS1}; // aligned with the stator
+circ[] = Extrude {{0, 0, 1}, {0, 0, 0}, A0} { Point{pntG[0]}; };
+pntG[]+=circ[0];
+lineMBstator[]=circ[1];
+Transfinite Line{lineMBstator[0]} = NbrDivMB+1 ;
+
+//Filling the gap for the whole 2*Pi
+For k In {1:NbrPolesTot-1}
+  lineMBstatoraux[]+= Rotate {{0, 0, 1}, {0, 0, 0}, k*A0} { Duplicata{Line{lineMBstator[0]};} };
+EndFor
+
+// -------------------------------------------------------------------------------
+// Stator
+// -------------------------------------------------------------------------------
+
+pntS[] = newp; Point(newp)={rS1, 0, 0, pS1};
+linS[] = newl; Line(newl) = {pntG[0], pntS[0]};
+linS[]+= Rotate {{0, 0, 1}, {0, 0, 0}, A0} { Duplicata{Line{linS[0]};} };
+
+pntS[]+=newp; Point(newp)={rS7,0,0,pS2};
+points[]=Boundary{Line{linS[1]};};
+pntS[]+=points[1];
+
+lin[] = Extrude {{0, 0, 1}, {0, 0, 0}, A0} { Point{pntS[1]}; };
+cirS[]= lin[1]; pntS[]+=lin[0];
+
+linS[]+=newl; Line(newl) = {pntS[0], pntS[1]};
+linS[]+=newl; Line(newl) = {pntS[2], pntS[3]};
+
+// -------------------------------------------------------------------------------
+// Slots
+// -------------------------------------------------------------------------------
+
+A2 = 0.0;
+AA[]=deg2rad*{2.77+A2, 4.0+A2, 5.52+A2, 5.56+A2, 5.65+A2, 9.35+A2, 9.44+A2, 9.48+A2, 11+A2, 12.23+A2} ;
+
+For k In {0:#AA[]-1}
+  cosAA[]+=Cos(AA[k]); sinAA[]+=Sin(AA[k]);
+EndFor
+
+pntSlot[]+=newp; Point(newp)={rS5*cosAA[0], rS5*sinAA[0], 0., pS3};
+pntSlot[]+=newp; Point(newp)={rS3*cosAA[1], rS3*sinAA[1], 0., pS3};
+pntSlot[]+=newp; Point(newp)={rS1*cosAA[2], rS1*sinAA[2], 0., pS3};
+pntSlot[]+=newp; Point(newp)={rS2*cosAA[3], rS2*sinAA[3], 0., pS3};
+pntSlot[]+=newp; Point(newp)={rS4*cosAA[3], rS4*sinAA[3], 0., pS3};
+pntSlot[]+=newp; Point(newp)={rS6*cosAA[4], rS6*sinAA[4], 0., pS3};
+pntSlot[]+=newp; Point(newp)={rS6*cosAA[5], rS6*sinAA[5], 0., pS3};
+pntSlot[]+=newp; Point(newp)={rS4*cosAA[6], rS4*sinAA[6], 0., pS3};
+pntSlot[]+=newp; Point(newp)={rS2*cosAA[6], rS2*sinAA[6], 0., pS3};
+pntSlot[]+=newp; Point(newp)={rS1*cosAA[7], rS1*sinAA[7], 0., pS3};
+pntSlot[]+=newp; Point(newp)={rS3*cosAA[8], rS3*sinAA[8], 0., pS3};
+pntSlot[]+=newp; Point(newp)={rS5*cosAA[9], rS5*sinAA[9], 0., pS3};
+
+// air slot 1
+linASlot[]+=newl ; Line(newl)={pntSlot[2], pntSlot[3]};
+linASlot[]+=newl ; Line(newl)={pntSlot[3], pntSlot[1]};
+linASlot[]+=newl ; Circle(newl)={pntSlot[1], cen, pntSlot[10]};
+linASlot[]+=newl ; Line(newl)={pntSlot[10], pntSlot[8]};
+linASlot[]+=newl ; Line(newl)={pntSlot[8], pntSlot[9]};
+linASlot[]+=newl ; Circle(newl)={pntSlot[9], cen, pntSlot[2]};
+
+Line Loop(newll) = {linASlot[]};
+sairslot[] += news ; Plane Surface(sairslot[0]) = {newll-1};
+
+// coil slot 1
+linSlot[]+=newl ; Line(newl)={pntSlot[1], pntSlot[0]};
+linSlot[]+=newl ; Circle(newl)= {pntSlot[0], pntSlot[4], pntSlot[5]};
+linSlot[]+=newl ; Line(newl)={pntSlot[5], pntSlot[6]};
+linSlot[]+=newl ; Circle(newl)={pntSlot[6], pntSlot[7],pntSlot[11]};
+linSlot[]+=newl ; Line(newl)={pntSlot[11], pntSlot[10]};
+
+Line Loop(newll) = {-linASlot[2],linSlot[]};
+sslot[] += news ; Plane Surface(sslot[0]) = {newll-1};
+
+// slots 2 and 3
+A2 = 15*deg2rad;
+
+pntSlot0[0] = pntSlot[2];
+pntSlot1[0] = pntSlot[9];
+For k In{1:2}
+  pntSlot0[] += Rotate {{0, 0, 1}, {0, 0, 0}, A2} { Duplicata{Point{pntSlot0[k-1]};} };
+  pntSlot1[] += Rotate {{0, 0, 1}, {0, 0, 0}, A2} { Duplicata{Point{pntSlot1[k-1]};} };
+EndFor
+
+For k In{1:2}
+  sslot[] += Rotate {{0, 0, 1}, {0, 0, 0}, A2} { Duplicata{Surface{sslot[k-1]};} };
+  sairslot[] += Rotate {{0, 0, 1}, {0, 0, 0}, A2} { Duplicata{Surface{sairslot[k-1]};} };
+EndFor
+
+cSlot[]+=newl; Circle(newl) = {pntS[0], cen, pntSlot[2]};
+cSlot[]+=newl; Circle(newl) = {pntSlot1[0], cen, pntSlot0[1]};
+cSlot[]+=newl; Circle(newl) = {pntSlot1[1], cen, pntSlot0[2]};
+cSlot[]+=newl; Circle(newl) = {pntSlot1[2], cen, pntS[2]};
+
+linesslot0[] = CombinedBoundary{ Surface{ sslot[0], sairslot[0] } ;};
+linesslot1[] = CombinedBoundary{ Surface{ sslot[1], sairslot[1] } ;};
+linesslot2[] = CombinedBoundary{ Surface{ sslot[2], sairslot[2] } ;};
+
+Line Loop(newll) = {-lineMBstator[0],linS[0], cSlot[0],-linesslot0[{4}],
+                    cSlot[1],-linesslot1[{9}],
+                    cSlot[2],-linesslot2[{9}], cSlot[3], -linS[1]};
+sairgapS[0]=news; Plane Surface(sairgapS[0]) = {newll-1};
+
+linesslot0[] -= linesslot0[{4}];
+linesslot1[] -= linesslot1[{9}];
+linesslot2[] -= linesslot2[{9}];
+Line Loop(newll) = { cSlot[0], linesslot0[],
+                     cSlot[1], linesslot1[],
+                     cSlot[2], linesslot2[],
+                     cSlot[3], linS[3], -cirS[0], -linS[2]};
+sstator[0]=news; Plane Surface(sstator[0]) = {newll-1};
+
+// -------------------------------------------------------------------------------
+// -------------------------------------------------------------------------------
+
+auxlink[]=linS[{1,3}]; // A1
+
+If(SymmetryFactor<8)
+  // FULL MODEL ==> Rotation of NbrPolesTot*Pi/4
+  // For simplicity: rotating the interior and exterior boundaries
+
+ If (SymmetryFactor>1)
+    For k In {0:#auxlink[]-1}
+      auxlink_[] += Rotate {{0, 0, 1}, {0, 0, 0}, 2*Pi/SymmetryFactor-Pi/4} { Duplicata{Line{auxlink[k]};} };
+    EndFor
+    auxlink[] = auxlink_[];
+  EndIf
+
+  For k In {1:NbrPoles-1}
+    cirS[] += Rotate {{0, 0, 1}, {0, 0, 0}, k*Pi/4} { Duplicata{ Line{cirS[{0}]};} };
+  EndFor
+  For k In {1:NbrPoles-1}
+    sstator[]+= Rotate {{0, 0, 1}, {0, 0, 0}, k*Pi/4} { Duplicata{ Surface{sstator[0]};} };
+    sairgapS[]+= Rotate {{0, 0, 1}, {0, 0, 0}, k*Pi/4} { Duplicata{ Surface{sairgapS[0]};} };
+    sairslot[]+= Rotate {{0, 0, 1}, {0, 0, 0}, k*Pi/4} { Duplicata{ Surface{sairslot[{0:2}]};} };
+    sslot[]+= Rotate {{0, 0, 1}, {0, 0, 0}, k*Pi/4} { Duplicata{ Surface{sslot[{0:2}]};} };
+  EndFor
+EndIf
+
+
+
+// -------------------------------------------------------------------------------
+// -------------------------------------------------------------------------------
+// Physical regions
+// -------------------------------------------------------------------------------
+// -------------------------------------------------------------------------------
+
+Physical Surface(STATOR_FE)     = {sstator[]};  // Stator
+Physical Surface(STATOR_AIR)    = {sairslot[]}; // AirStator
+Physical Surface(STATOR_AIRGAP) = {sairgapS[]}; // AirStator for possible torque computation with Maxwell stress tensor
+
+NN = (Flag_Symmetry)?NbrSectStator:NbrSectTotStator;
+//For k In {0:NN-1}
+//  Physical Surface(STATOR_IND+k) = {sslot[k]}; //Inds
+//EndFor
+
+Physical Surface(STATOR_IND_AM) = {sslot[{0:NN-1:6}]};
+Physical Surface(STATOR_IND_CP) = {sslot[{1:NN-1:6}]};
+Physical Surface(STATOR_IND_BM) = {sslot[{2:NN-1:6}]};
+If(NbrSectStator>2)
+  Physical Surface(STATOR_IND_AP) = {sslot[{3:NN-1:6}]};
+  Physical Surface(STATOR_IND_CM) = {sslot[{4:NN-1:6}]};
+  Physical Surface(STATOR_IND_BP) = {sslot[{5:NN-1:6}]};
+EndIf
+
+Color Pink         {Surface{ sslot[{0:NN-1:6}] };} // A-
+Color ForestGreen  {Surface{ sslot[{1:NN-1:6}] };} // C+
+Color PaleGoldenrod{Surface{ sslot[{2:NN-1:6}] };} // B-
+If (#sslot[]>=6)
+Color Red        {Surface{ sslot[{3:NN-1:6}] };} // A+
+Color SpringGreen{Surface{ sslot[{4:NN-1:6}] };} // C-
+Color Gold       {Surface{ sslot[{5:NN-1:6}] };} // B+
+EndIf
+
+
+Physical Line(SURF_EXT) = {cirS[]}; // SurfExt
+
+If(Flag_Symmetry) //Lines for symmetry link
+  Physical Line(STATOR_BND_A0) = linS[{0,2}];
+  Physical Line(STATOR_BND_A1) = auxlink[] ;
+EndIf
+
+
+lineMBstator[] += lineMBstatoraux[] ;
+If(!Flag_Symmetry)
+  Physical Line(STATOR_BND_MOVING_BAND) = {lineMBstator[]};
+EndIf
+If(Flag_Symmetry)
+ns = #lineMBstator[];
+nns = ns/SymmetryFactor ;
+For k In {1:SymmetryFactor}
+  kk= ((k*nns-1) > ns) ? ns-1 : k*nns-1 ;
+  Physical Line(STATOR_BND_MOVING_BAND+k-1) = {lineMBstator[{(k-1)*nns:kk}]};
+EndFor
+  k1 = Floor[NbrPolesTot/NbrSect];
+  k2 = Ceil[NbrPolesTot/NbrSect];
+  If (k2 > k1)
+    Physical Line(STATOR_BND_MOVING_BAND+k2-1) = lineMBstator[{(k2-1)*nns:#lineMBstator[]-1}] ;
+  EndIf
+EndIf
+
+
+// For nice visualisation...
+linStator[] = CombinedBoundary{Surface{sstator[]};};
+linSlot[] = CombinedBoundary{Surface{sslot[]};};
+
+nicepos_stator[] += {linStator[],linSlot[] };
+
+Color SteelBlue {Surface{sstator[]};}
+Color SkyBlue {Surface{sairslot[],sairgapS[]};}
+
+
diff --git a/contrib/mobile/Android/res/raw/test_geo b/contrib/mobile/Android/res/raw/test_geo
new file mode 100644
index 0000000000..d60f76efbb
--- /dev/null
+++ b/contrib/mobile/Android/res/raw/test_geo
@@ -0,0 +1,64 @@
+Point(1) = {0,0,0};
+
+DefineConstant
+[
+ n0 = {3,
+       Label "Number",
+       Path "Test widgets/Numbers"}
+ n01 = {3, Min 1, Max 4, Step 1,
+       Label "Number (with range)",
+       Path "Test widgets/Numbers"}
+ n1 = {3, ReadOnly 1,
+       Label "Number (read only)",
+       Path "Test widgets/Numbers"}
+ n12 = {3, ReadOnlyRange 1, Min 1, Max 4, Step 1,
+       Label "Number (read only range)",
+       Path "Test widgets/Numbers"}
+ n2 = {3, Choices{1, 2, 3, 4},
+       Label "Number (with choices)",
+       Path "Test widgets/Numbers"}
+ n3 = {1, Choices{0,1},
+       Label "Number (with binary choice) - Show String Options?",
+       Path "Test widgets/Numbers"},
+ n4 = {3, Choices{1 = "One",
+                  2 = "Two",
+                  3 = "Three",
+                  4 = "Go!!"},
+       Label "Number (with enumeration)",
+       Path "Test widgets/Numbers"}
+];
+
+Printf("N3 = %g", n3);
+
+If(n3) // test define/undefine
+Printf("N3 IS SET");
+DefineConstant[
+ s0 = {"a",
+       Label "String",
+       Path "Test widgets/Strings"}
+ s1 = {"a", ReadOnly 1,
+       Label "String (read only)",
+       Path "Test widgets/Strings"}
+ s2 = {"a", Choices {"a","b","c"},
+       Label "String with choices",
+       Path "Test widgets/Strings"}
+ s20 = {"a, c", Choices {"a","b","c"}, MultipleSelection "101",
+       Label "String with multiple selection",
+       Path "Test widgets/Strings"}
+ s3 = {"a.txt", Choices{"a.txt","b.txt","c.txt"}, Kind "file",
+       Label "File",
+       Path "Test widgets/Strings"}
+ s4 = {"a.txt", Kind "file", Macro "Gmsh",
+       Label "Macro",
+       Path "Test widgets/Strings"}
+];
+EndIf
+If(!n3)
+  Printf("N3 IS **NOT** SET");
+UndefineConstant[ "Test widgets/Strings/s0",
+                  "Test widgets/Strings/s1",
+                  "Test widgets/Strings/s2",
+                  "Test widgets/Strings/s20",
+                  "Test widgets/Strings/s3",
+                  "Test widgets/Strings/s4"];
+EndIf
diff --git a/contrib/mobile/Android/res/values-v11/styles.xml b/contrib/mobile/Android/res/values-v11/styles.xml
new file mode 100644
index 0000000000..d408cbc37a
--- /dev/null
+++ b/contrib/mobile/Android/res/values-v11/styles.xml
@@ -0,0 +1,5 @@
+<resources>
+
+    <style name="AppTheme" parent="android:Theme.Holo.Light" />
+
+</resources>
\ No newline at end of file
diff --git a/contrib/mobile/Android/res/values-v14/styles.xml b/contrib/mobile/Android/res/values-v14/styles.xml
new file mode 100644
index 0000000000..1c089a788c
--- /dev/null
+++ b/contrib/mobile/Android/res/values-v14/styles.xml
@@ -0,0 +1,5 @@
+<resources>
+
+    <style name="AppTheme" parent="android:Theme.Holo.Light.DarkActionBar" />
+
+</resources>
\ No newline at end of file
diff --git a/contrib/mobile/Android/res/values/strings.xml b/contrib/mobile/Android/res/values/strings.xml
new file mode 100644
index 0000000000..eaf9831ea8
--- /dev/null
+++ b/contrib/mobile/Android/res/values/strings.xml
@@ -0,0 +1,25 @@
+<resources>
+
+    <string name="app_name">Onelab</string>
+    <string name="button_open_external_file">Open MSH file on external storage</string>
+    <string name="button_ok">OK</string>
+    <string name="button_recalculate_param">Recalulate with new parameters</string>
+    <string name="dialog_title_choosefile">Choose a MSH file</string>
+    <string name="error_nosdcard">No SDcard found on your device</string>
+    <string name="title_parameter">Settings</string>
+    <string name="title_activity_main">Onelab</string>
+    <string name="error_nomshfile">No compatible files or directories in this folder</string>
+    <string name="menu_list">Load a model</string>
+    <string name="menu_settings">Settings</string>
+    <string name="menu_model">Show the model</string>
+    <string name="menu_postpro">Post-processing</string>
+    <string name="menu_hidebar">Hide the top bar</string>
+    <string name="menu_showbar">Show the top bar</string>
+    <string name="menu_view">Change the view</string>
+    <string name="menu_view_x">Set X view</string>
+    <string name="menu_view_y">Set Y view</string>
+    <string name="menu_view_z">Set Z view</string>
+    <string name="menu_view_scale">Reset unit scale</string>
+    <string name="menu_view_translation">Center the model</string>
+
+</resources>
\ No newline at end of file
diff --git a/contrib/mobile/Android/res/values/styles.xml b/contrib/mobile/Android/res/values/styles.xml
new file mode 100644
index 0000000000..4dba0d0a4c
--- /dev/null
+++ b/contrib/mobile/Android/res/values/styles.xml
@@ -0,0 +1,5 @@
+<resources>
+
+    <style name="AppTheme" parent="android:Theme.Light" />
+
+</resources>
\ No newline at end of file
diff --git a/contrib/mobile/Android/res/xml/models.xml b/contrib/mobile/Android/res/xml/models.xml
new file mode 100644
index 0000000000..80b25aa292
--- /dev/null
+++ b/contrib/mobile/Android/res/xml/models.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?> 
+
+<models>
+    <model>
+        <title>Magnet</title>
+        <summary>Simple magnet example</summary>
+        <file type="geo">magnet.geo</file>
+    </model>
+    
+    <model>
+        <title>Eight-pole permanent magnet synchronous machine</title>
+        <summary></summary>
+        <file type="geo">pmsm.geo</file>
+    </model>
+
+    <model>
+        <title>Test</title>
+        <summary>test all parameters of onelab</summary>
+        <file type="geo">test.geo</file>
+    </model>
+</models>
diff --git a/contrib/mobile/Android/src/org/geuz/onelab/GLESRender.java b/contrib/mobile/Android/src/org/geuz/onelab/GLESRender.java
new file mode 100644
index 0000000000..2cb182e27f
--- /dev/null
+++ b/contrib/mobile/Android/src/org/geuz/onelab/GLESRender.java
@@ -0,0 +1,45 @@
+package org.geuz.onelab;
+
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.opengles.GL10;
+
+import android.opengl.GLSurfaceView.Renderer;
+import android.os.Handler;
+
+public class GLESRender implements Renderer{
+
+	Gmsh mGModel;
+	Handler loadingHand;
+
+	public GLESRender(Gmsh model) {
+		this.mGModel = model;
+	}
+	
+	public void load(String filename){
+		mGModel.load(filename);
+	}
+	
+	public void translate(float tx, float ty, float tz){
+		mGModel.translation(tx, ty, tz);
+	}
+	public void scale(float sx, float sy, float sz){
+		mGModel.scale(sx, sy, sz);
+	}
+	public void rotate(float rx, float ry, float rz){
+		mGModel.rotate(rx, ry, rz);
+	}
+	
+	// OpenGL ES methods
+	public void onDrawFrame(GL10 gl) {
+		mGModel.viewDraw();
+	}
+
+	public void onSurfaceChanged(GL10 gl, int width, int height) {
+		mGModel.viewInit(width, height);
+	}
+
+	public void onSurfaceCreated(GL10 gl, EGLConfig config) {
+		
+	}
+
+}
diff --git a/contrib/mobile/Android/src/org/geuz/onelab/Gmsh.java b/contrib/mobile/Android/src/org/geuz/onelab/Gmsh.java
new file mode 100644
index 0000000000..f13d71f968
--- /dev/null
+++ b/contrib/mobile/Android/src/org/geuz/onelab/Gmsh.java
@@ -0,0 +1,90 @@
+package org.geuz.onelab;
+
+import android.os.Handler;
+
+public class Gmsh {
+	/** From C / C++ code **/
+	static {
+		System.loadLibrary("f2cblas");
+		System.loadLibrary("f2clapack");
+		System.loadLibrary("petsc");
+		System.loadLibrary("Gmsh");
+		System.loadLibrary("GetDP");
+		System.loadLibrary("Onelab");
+        
+    }
+	private native long init(String name); // Init Gmsh
+	private native void loadFile(long ptr, String name); // load a file(OpenProjet)
+	private native void initView(long ptr, int w, int h); // Called each time the GLView change
+	private native void drawView(long ptr); // Called each time the GLView request a render
+	private native void setTranslation(long ptr, float tx, float ty, float tz); // translate the current GModel
+	private native void setScale(long ptr, float sx, float sy, float sz); // scale the current GModel
+	private native void setRotate(long ptr, float rx, float ry, float rz); // rotate the current GModel
+	private native void setShow(long ptr, String what, boolean show); // select what to show / hide
+	private native long getOnelabInstance(); // return the singleton of the onelab server
+	public native String[] getParams(); // return the parameters for onelab
+	public native int setParam(String type, String name, String value); // change a parameters
+	public native String[] getPView(); // get a list of PViews
+	public native void setPView(int position, int intervalsType,int visible,int nbIso); // Change options for a PView
+	public native int onelabCB(String action); // Call onelab
+	
+	/** Java CLASS **/
+	private long ptr;
+	private long onelab;
+	private Handler handler;
+
+	public Gmsh(String name, Handler handler) {
+		ptr = this.init(name);
+		onelab = this.getOnelabInstance();
+		this.handler = handler;
+	}
+
+	public void viewInit(int w, int h) {
+		this.initView(ptr, w, h);
+	}
+
+	public void viewDraw() {
+		this.drawView(ptr);
+	}
+
+	public void load(String filename){
+		this.loadFile(ptr, filename);
+	}
+
+	public void translation(float tx, float ty, float tz)
+	{
+		this.setTranslation(ptr, tx, ty, tz);
+	}
+
+	public void scale(float sx, float sy, float sz)
+	{
+		this.setScale(ptr, sx, sy, sz);
+	}
+
+	public void rotate(float rx, float ry, float rz) {
+		this.setRotate(ptr, rx, ry, rz);
+	}
+	public void showGeom(boolean show)
+	{
+		this.setShow(ptr, "geom", show);
+	}
+	public void showMesh(boolean show)
+	{
+		this.setShow(ptr, "mesh", show);
+	}
+	public long getOnelab() {
+		return this.onelab;
+	}
+	public void ShowPopup(String message) {
+		handler.obtainMessage(0, message).sendToTarget();
+	}
+	public void RequestRender() {
+		handler.obtainMessage(1).sendToTarget();
+	}
+	public void SetLoading(String message) {
+		handler.obtainMessage(2, message).sendToTarget();
+	}
+	public void SetLoading(int percent) {
+		handler.obtainMessage(3, percent, 100).sendToTarget();
+	}
+}
diff --git a/contrib/mobile/Android/src/org/geuz/onelab/MainActivity.java b/contrib/mobile/Android/src/org/geuz/onelab/MainActivity.java
new file mode 100644
index 0000000000..885845d0ee
--- /dev/null
+++ b/contrib/mobile/Android/src/org/geuz/onelab/MainActivity.java
@@ -0,0 +1,806 @@
+package org.geuz.onelab;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import android.opengl.GLSurfaceView;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.os.Environment;
+import android.os.Handler;
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.app.ProgressDialog;
+
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.res.Configuration;
+import android.content.res.XmlResourceParser;
+import android.graphics.Color;
+import android.support.v4.view.PagerAdapter;
+import android.support.v4.view.ViewPager;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.util.Log;
+import android.view.MenuItem;
+import android.view.MotionEvent;
+import android.view.SubMenu;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup.LayoutParams;
+import android.view.KeyEvent;
+import android.view.Menu;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.AdapterView;
+import android.widget.AdapterView.OnItemClickListener;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.CheckBox;
+import android.widget.CompoundButton;
+import android.widget.EditText;
+import android.widget.LinearLayout;
+import android.widget.ListView;
+import android.widget.ScrollView;
+import android.widget.Spinner;
+import android.widget.TableLayout;
+import android.widget.TableRow;
+import android.widget.TextView;
+
+public class MainActivity extends Activity {
+
+	private mGLSurfaceView glView;
+	private GLESRender renderer;
+	private ProgressDialog loading;
+	private AlertDialog.Builder dialogBuilder;
+	private Models modelList;
+	private int model;
+	private Gmsh gmsh;
+	private Button run, reset;
+	private UndragableViewPager pager;
+	private List<Parameter> params = new ArrayList<Parameter>();
+	private SeparatedListView paramListView;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+    	super.onCreate(savedInstanceState);
+    	
+    	getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
+				WindowManager.LayoutParams.FLAG_FULLSCREEN);
+    	//this.requestWindowFeature(Window.FEATURE_NO_TITLE);
+    	
+    	LinearLayout layout = new LinearLayout(this);
+    	loading = new ProgressDialog(this);
+    	layout.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
+    	layout.setOrientation(LinearLayout.VERTICAL);
+    	pager = new UndragableViewPager(this);
+    	pager.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
+    	pager.setAdapter(new AdaptedPager());
+    	pager.setOffscreenPageLimit(3);
+    	pager.setCurrentItem(0);
+    	layout.addView(pager);
+    	dialogBuilder = new AlertDialog.Builder(this);
+    	
+    	gmsh = new Gmsh("", mainHandler);
+    	modelList = new Models();
+    	getModels();
+    	loadNative();
+    	if(modelList.size() > 0){
+    		model = 0;
+	    	String tmp = getFilesDir()+ "/" + modelList.getFile(model);
+	    	gmsh.load(tmp);
+    	}
+    	setContentView(layout);
+    }
+    
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+    	super.onCreateOptionsMenu(menu);
+    	MenuItem listitem = menu.add(Menu.NONE, Menu.NONE, Menu.NONE, R.string.menu_list);
+        if(getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT)
+        {
+        	MenuItem paramitem = menu.add(Menu.NONE, Menu.NONE, Menu.NONE, R.string.menu_settings);
+        	paramitem.setIcon(R.drawable.ic_settings);
+        	paramitem.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
+        }
+        MenuItem modelitem = menu.add(Menu.NONE, Menu.NONE, Menu.NONE, R.string.menu_model);
+        MenuItem postitem = menu.add(Menu.NONE, Menu.NONE, Menu.NONE, R.string.menu_postpro);
+        SubMenu viewitem = menu.addSubMenu(R.string.menu_view);
+        
+        
+        listitem.setIcon(R.drawable.ic_list);
+        modelitem.setIcon(R.drawable.ic_mesh);
+        listitem.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
+        modelitem.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
+        postitem.setShowAsAction(MenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW);
+        
+        viewitem.add(R.string.menu_view_x);
+        viewitem.add(R.string.menu_view_y);
+        viewitem.add(R.string.menu_view_z);
+        viewitem.add(R.string.menu_view_scale);
+        viewitem.add(R.string.menu_view_translation);
+        return true;
+    }
+    @Override
+    public boolean onMenuItemSelected(int featureId, MenuItem item) {
+    	if(item.getTitle().equals(getString(R.string.menu_settings)))
+    		pager.setCurrentItem(1, true);
+    	else if(item.getTitle().equals(getString(R.string.menu_list)))
+    		pager.setCurrentItem(0, true);
+    	else if (item.getTitle().equals(getString(R.string.menu_model)))
+    		pager.setCurrentItem(2, true);
+    	else if(item.getTitle().equals(getString(R.string.menu_postpro))){
+    		dialogBuilder.setTitle("Post proccessing")
+    			.setView(postproView())
+				.setPositiveButton("Ok", null)
+				.show();
+    	}
+    	else if(item.getTitle().equals(getString(R.string.menu_view_x))){
+    		renderer.rotate(0, 0, 0);
+    		renderer.rotate(90, 0, 0);
+    		glView.requestRender();
+    	}
+		else if(item.getTitle().equals(getString(R.string.menu_view_y))){
+			renderer.rotate(0, 0, 0);
+			renderer.rotate(0, 90, 0);
+			glView.requestRender();
+		}
+		else if(item.getTitle().equals(getString(R.string.menu_view_z))){
+			renderer.rotate(0, 0, 0);
+			glView.requestRender();
+		}
+		else if(item.getTitle().equals(getString(R.string.menu_view_scale))){
+			glView.resetScale();
+			glView.requestRender();
+		}
+		else if(item.getTitle().equals(getString(R.string.menu_view_translation))){
+			renderer.translate(0, 0, 0);
+			glView.requestRender();
+		}
+    	return super.onMenuItemSelected(featureId, item);
+    }
+    
+    private class UndragableViewPager extends ViewPager{
+
+		public UndragableViewPager(Context context) {
+			super(context);
+		}
+		@Override
+		public boolean onInterceptTouchEvent(MotionEvent arg0) {
+			return false;
+			//return super.onInterceptTouchEvent(arg0);
+		}
+    	
+    }
+    
+    private class AdaptedPager extends PagerAdapter {
+    	
+    	@Override
+    	public Object instantiateItem(ViewGroup container, int position) {
+    		switch (position) {
+			case 0: // Select a model
+				View listView = listView(container.getContext());
+				container.addView(listView);
+				listView.setPadding(15, 10, 10, 5);
+				listView.setBackgroundColor(Color.argb(255, 67, 67, 67));
+				return listView;
+			case 1: // Parameters
+				(MainActivity.this).getAvailableParam();
+				View paramView = (MainActivity.this).paramView(container.getContext());
+				container.addView(paramView);
+				paramView.setPadding(15, 10, 10, 5);
+				return paramView;
+			case 2: // OpenGL ES view
+				renderer = new GLESRender(gmsh);
+				glView = new mGLSurfaceView(container.getContext(), renderer);
+				//TODO the glView seems break the ViewPager (black square appear ...)
+				glView.setEGLContextClientVersion(1);
+				glView.setRenderer(renderer);
+				glView.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
+
+				container.addView(glView);
+				return glView;
+			default: // ???
+				View defaultView = new View(container.getContext());
+				defaultView.setBackgroundColor(Color.argb(255, 255, 0, 0));
+				container.addView(defaultView);
+				return defaultView;
+			}
+    	}
+
+		@Override
+		public int getCount() {
+			return 3;
+		}
+		
+		@Override
+		public float getPageWidth(int position) {
+			getResources().getConfiguration();
+			if(getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE)
+			{
+				switch (position) {
+				case 1:
+					if((MainActivity.this).getWindowManager().getDefaultDisplay().getWidth() < 500 )
+						return 1f;
+					return 0.25f;
+				case 2:
+					if((MainActivity.this).getWindowManager().getDefaultDisplay().getWidth() < 500 )
+						return 1f;
+					return 0.75f;
+				default:
+					return 1f;
+				}
+			}
+			switch (position) {
+			case 1:
+				if((MainActivity.this).getWindowManager().getDefaultDisplay().getWidth() < 500 )
+					return 1f;
+				return 0.5f;
+			case 2:
+				return 1f;
+			default:
+				return 1f;
+			}
+		}
+
+		@Override
+		public boolean isViewFromObject(View view, Object object) {
+			return(view == object);
+		}
+   	
+    }
+    
+    private void getAvailableParam(){
+    	String[] tmp = gmsh.getParams();
+		for(String s : tmp){ // for each parameters in onelab
+			boolean found = false;
+			for(Parameter p : params){ // for each parameters
+				if(s.split("\n")[2].equals(p.getName())){ // the parameter already exist, just refresh it
+					if(p.getType().equals("ParameterNumber"))
+						((ParameterNumber)p).fromString(s);
+					else if(p.getType().equals("ParameterString"))
+						((ParameterString)p).fromString(s);
+					found = true;
+					break;
+				}
+			}
+			if(found) continue;
+			// add new parameter
+			if(s.split("\n")[1].equals("number")){
+				final ParameterNumber mParam = new ParameterNumber(this, gmsh, glView, "");
+				if(mParam.fromString(s) == -1) continue;
+				params.add(mParam);
+				if(paramListView != null){
+					paramListView.addItem(mParam.getName().split("/")[0].equals("Parameters")? mParam.getName().split("/")[0] + " > " + mParam.getName().split("/")[1]: mParam.getName().split("/")[0], mParam.getView());
+				}
+			}
+			else if(s.split("\n")[1].equals("string")){
+				ParameterString mParam = new ParameterString(this, gmsh, glView, "");
+				if(mParam.fromString(s) != -1){
+					params.add(mParam);
+					if(paramListView != null)
+						paramListView.addItem(mParam.getName().split("/")[0], mParam.getView());
+				}
+			}
+		}
+    }
+
+    private void getModels()
+    {
+    	XmlResourceParser parser =  getResources().getXml(R.xml.models);
+    	int eventType;
+		try {
+			eventType = parser.getEventType();
+    	while (eventType != XmlPullParser.END_DOCUMENT) {
+            if(eventType == XmlPullParser.START_DOCUMENT){
+            	eventType = parser.next();
+            	continue;
+            }
+            else if(eventType == XmlPullParser.START_TAG && parser.getName().equals("model")) {
+            	String title = "", file = "", summary = "";
+            	while(eventType != XmlPullParser.END_TAG || !parser.getName().equals("model"))
+            	{
+            		
+            		eventType = parser.next();
+            		if(eventType == XmlPullParser.START_TAG && parser.getName().equals("title")){
+            			eventType = parser.next();
+            			if(eventType == XmlPullParser.TEXT)
+            				title = parser.getText();
+            		}
+            		else if(eventType == XmlPullParser.START_TAG && parser.getName().equals("summary")){
+            			eventType = parser.next();
+            			if(eventType == XmlPullParser.TEXT)
+            				summary = parser.getText();
+            		}
+            		else if(eventType == XmlPullParser.START_TAG && parser.getName().equals("file")){
+            			eventType = parser.next();
+            			if(eventType == XmlPullParser.TEXT)
+            				file = parser.getText();
+            		}
+            	}
+            	if(title.length() > 0) modelList.addModel(title, summary, file);
+            }
+            eventType = parser.next();
+           }
+		} catch (XmlPullParserException e) {
+			// TODO Error in XML file
+			e.printStackTrace();
+		} catch (IOException e) {
+			// TODO Error in XML file
+			e.printStackTrace();
+		}
+
+    }
+    
+    /**
+     * Load file from res/raw/ directory to the files directory of the application.
+     */
+    private void loadNative()
+    {
+    	for( Field f : R.raw.class.getFields()) {
+    		try {
+				int Msh = f.getInt(null), i;
+				String androidName = getResources().getResourceEntryName(Msh);
+				StringBuilder tmp = new StringBuilder(androidName);
+				tmp.setCharAt(androidName.lastIndexOf('_'), '.');
+				String nativeName = tmp.toString();
+				String nativeExtension = nativeName.substring(nativeName.lastIndexOf('.'));
+				/*if(new File(getFilesDir().toString()+"/"+nativeName).exists()){
+					//TODO check if the files are the same
+					continue;
+				}*/
+				InputStream mshFile = getResources().openRawResource(Msh);
+		    	
+		    	FileOutputStream outputStream = openFileOutput(nativeName, Context.MODE_WORLD_READABLE);
+		    	byte[] buffer = new byte[2048];
+		    	
+		    	while ((i = mshFile.read(buffer, 0, buffer.length)) > 0) 
+					outputStream.write(buffer,0,i);
+
+			} catch (IllegalArgumentException e) {
+				Log.e("Load files", "Error " + e.toString());
+				
+			} catch (IllegalAccessException e) {
+				Log.e("Load files", "Error " + e.toString());
+				
+			} catch (IOException e) {
+				Log.e("Load files", "Error " + e.toString());
+			}
+    	}
+    }
+    
+    private View postproView() {
+    	ScrollView scroll = new ScrollView(this);
+    	scroll.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
+    	String[] PViews = gmsh.getPView();
+    	if(PViews.length < 1){
+    		LinearLayout layout = new LinearLayout(this);
+    		TextView noPView = new TextView(this);
+    		noPView.setText("There is no post processing data !");
+    		layout.addView(noPView);
+    		return layout;
+    	}
+    	TableLayout table = new TableLayout(this);
+    	table.setColumnShrinkable(0, true);
+    	TableRow title = new TableRow(this);
+    	TextView title_name = new TextView(this);
+    	TextView title_intervalType = new TextView(this);
+    	TextView title_intervals = new TextView(this);
+    	title_name.setText("Name");
+    	title_intervals.setText("Intervals");
+    	title_intervalType.setText("Interval type");
+    	title.addView(title_name);
+    	title.addView(title_intervalType);
+    	title.addView(title_intervals);
+    	table.addView(title);
+    	for(int i=PViews.length-1; i >= 0;i--){
+    		TableRow row = new TableRow(this);
+    		final int myID =i;
+    		String[] infos = PViews[i].split("\n"); // name / IntervalsType (1=Iso 2=Continous 3=Discrete 4=Numeric)
+        	CheckBox checkbox = new CheckBox(this);
+        	final Spinner spinner = new Spinner(this);
+        	final EditText nbIso = new EditText(this);
+        	checkbox.setText(infos[0]);
+        	checkbox.setChecked(infos[2].equals("1"));
+        	checkbox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
+				
+				public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+					gmsh.setPView(myID, -1, (isChecked)? 1 : 0, -1);
+					spinner.setEnabled(isChecked);
+					glView.requestRender();
+				}
+			});
+        	spinner.setEnabled(infos[2].equals("1"));
+        	ArrayList<String> choices;
+        	ArrayAdapter<String> adapter;
+        	choices = new ArrayList<String>();
+    		choices.add("Iso-values");
+    		choices.add("Continous map");
+    		choices.add("Filled iso-values");
+    		adapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_dropdown_item, choices);
+    		adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+        	spinner.setAdapter(adapter);
+        	spinner.setSelection(Integer.parseInt(infos[1])-1);
+        	spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+
+				public void onItemSelected(AdapterView<?> parent, View view,
+						int pos, long id) {
+					gmsh.setPView(myID, pos+1, -1, -1);
+					glView.requestRender();
+					nbIso.setEnabled(pos == 0 || pos == 2);
+				}
+				public void onNothingSelected(AdapterView<?> arg0) {} // Unused Auto-generated method stub
+			});
+        	nbIso.setText(infos[3]);
+        	nbIso.setRawInputType(Configuration.KEYBOARD_12KEY);
+        	nbIso.setOnKeyListener(new View.OnKeyListener() {
+				
+				public boolean onKey(View v, int keyCode, KeyEvent event) {
+					if(keyCode == KeyEvent.KEYCODE_ENTER){ // hide the keyboard
+						InputMethodManager imm = (InputMethodManager)getSystemService(
+							      Context.INPUT_METHOD_SERVICE);
+							imm.hideSoftInputFromWindow(nbIso.getWindowToken(), 0);
+						return true;
+					}
+					return false;
+				}
+			});
+        	nbIso.addTextChangedListener(new TextWatcher() {
+				
+				public void onTextChanged(CharSequence s, int start, int before, int count) {
+					
+					int nIso = 1;
+					try {
+						if(s.length() < 1) nIso = 1;
+						else nIso = Integer.parseInt(s.toString());
+					}
+					catch(NumberFormatException e)
+					{
+						nIso = 1;
+						nbIso.setText("");
+					}
+					if(nIso > 1000) {gmsh.setPView(myID, -1, -1, 1000); nbIso.setText("1000");}
+					else if(nIso > 0) gmsh.setPView(myID, -1, -1, nIso);
+					else gmsh.setPView(myID, -1, -1, 1);
+					glView.requestRender();
+				}
+				
+				public void beforeTextChanged(CharSequence s, int start, int count, int after) {} // UNUSED Auto-generated method stub
+				public void afterTextChanged(Editable s) {} // UNUSED Auto-generated method stub
+
+			});
+        	row.addView(checkbox);
+        	row.addView(spinner);
+        	row.addView(nbIso);
+        	table.addView(row);
+    	}
+    	scroll.addView(table);
+    	return scroll;
+    }
+    
+    private View paramView(Context ctx) {
+    	LinearLayout layout = new LinearLayout(this);
+    	layout.setOrientation(LinearLayout.VERTICAL);
+    	/*TextView title = new TextView(ctx);
+    	title.setText(R.string.title_parameter);
+    	title.setTextAppearance(ctx, android.R.style.TextAppearance_DeviceDefault_Large);
+    	title.setTextColor(Color.BLACK);*/
+    	run = new Button(ctx);
+    	reset = new Button(ctx);
+    	run.setText("Run");
+    	reset.setText("Reset");
+    	//reset.setEnabled(false);
+    	run.setOnClickListener(new OnClickListener() {public void onClick(View v) {
+    		if(run.getText().equals("Show step"))
+    		{
+    			loading.show();
+    			return;
+    		}
+    		boolean changed = false;
+			for(Parameter p : params){
+				if(p.changed()){
+					changed = true;
+					break;
+				}
+			}
+			if(changed){
+				new Run().execute();
+				//gmsh.onelabCB("compute");
+				
+			}
+			getAvailableParam();
+				
+			pager.setCurrentItem(2, true);
+		}});
+    	reset.setOnClickListener(new OnClickListener() {public void onClick(View v) {
+    		if(gmsh.onelabCB("reset") == 1){
+    			getAvailableParam();
+				glView.requestRender();
+			}
+			pager.setCurrentItem(1, true);
+		}});
+    	LinearLayout onelabBtns = new LinearLayout(this);
+    	onelabBtns.setOrientation(LinearLayout.HORIZONTAL);
+    	LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
+    	lp.weight = 1;
+    	onelabBtns.addView(reset, lp);
+    	onelabBtns.addView(run, lp);
+    	CheckBox showMesh = new CheckBox(ctx);
+    	showMesh.setText("Show the mesh");
+    	showMesh.setChecked(false);
+    	showMesh.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
+			
+			public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+				gmsh.showMesh(isChecked);
+				glView.requestRender();
+			}
+		});
+    	CheckBox showGeom = new CheckBox(ctx);
+    	showGeom.setText("Show the geometry");
+    	showGeom.setChecked(true);
+    	showGeom.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
+			
+			public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+				gmsh.showGeom(isChecked);
+				glView.requestRender();
+			}
+		});
+    	paramListView = new SeparatedListView(ctx, new View[] {showMesh, showGeom, onelabBtns});
+    	paramListView.setDividerHeight(0);
+    	for(Parameter p : params)
+    	{
+    		paramListView.addItem(p.getName().split("/")[0].equals("Parameters")? p.getName().split("/")[0] + " > " + p.getName().split("/")[1]: p.getName().split("/")[0], p.getView());
+    		p.setList(paramListView);
+    	}
+    	/*LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
+    	layoutParams.weight = 1;
+    	layout.addView(paramListView, layoutParams);
+    	layoutParams = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
+    	layoutParams.weight = 0;
+    	layoutParams.gravity = Gravity.BOTTOM;
+    	layout.addView(onelabBtns,layoutParams);
+    	return layout;*/
+    	//layout.addView(onelabBtns);
+    	//layout.addView(paramListView);
+    	//return layout;
+    	return paramListView;
+    }
+    
+    private View listView(Context ctx) {
+    	LinearLayout layout = new LinearLayout(ctx);
+    	layout.setOrientation(LinearLayout.VERTICAL);
+    	ListView list = new ListView(ctx);
+    	list.setAdapter( new ModeleArrayAdapter(ctx, modelList));
+    	list.setOnItemClickListener(new OnItemClickListener() {
+
+			public void onItemClick(AdapterView<?> parent, View view, int position,
+					long id) {
+				model = (position < modelList.size())? position : 0;
+				String tmp = getFilesDir() + "/" + modelList.getFile(model);
+				gmsh.load(tmp);
+				
+				params.clear();
+				paramListView.clear();
+				getAvailableParam();
+				if(params.size()>0)params.get(params.size() - 1)._changed = true; // Hack for the first run
+				glView.requestRender();
+				pager.setCurrentItem(1);
+			}
+		});
+    	layout.addView(list);
+    	Button loadSD = new Button(ctx);
+    	loadSD.setText(R.string.button_open_external_file);
+    	loadSD.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.WRAP_CONTENT));
+    	loadSD.setOnClickListener(new OnClickListener() {
+			
+			public void onClick(View v) {
+				@SuppressWarnings("unused")
+				SDFileChooser f = new SDFileChooser();
+			}
+		});
+    	layout.addView(loadSD);
+    	return layout;
+    }
+
+    private class SDFileChooser{
+    	File curentPath;
+    	FileDialog dialog;
+    	
+    	public SDFileChooser() {
+    		String state = Environment.getExternalStorageState();
+    		if (Environment.MEDIA_MOUNTED.equals(state) || Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
+    			curentPath = Environment.getExternalStorageDirectory();
+
+    			showList(getFile(curentPath));
+    		}
+    		else
+    			showMessage(R.string.error_nosdcard);
+    	}
+    	
+    	public void setPath(String newPath) {
+    		curentPath = new File(newPath);
+    		showList(getFile(curentPath));
+    		
+    	}
+    	public String getPath() {
+    		return curentPath.toString();
+    	}
+    	
+    	private void showList(String[] list) {
+    		if(!curentPath.toString().equals(Environment.getExternalStorageDirectory().toString())){
+    			String[] newList = new String[list.length + 1];
+    			for(int i=0;i<list.length;i++)
+    				newList[i+1] = list[i];
+    			newList[0] = "..";
+    			list = newList;
+    		}	
+    		if(list.length < 1){
+    			showMessage(R.string.error_nomshfile);
+    			return;
+    		}
+    		if(dialog != null) dialog.dismiss();
+    		dialog = new FileDialog(this, list);
+    		dialog.show(getFragmentManager(), "files");
+    	}
+    	
+    	private void showMessage(int msg) {
+    		dialog = new FileDialog(this, msg);
+    		dialog.show(getFragmentManager(), "msg");
+    	}
+    	
+    	private String[] getFile(File path) {
+    		return path.list(new FilenameFilter() {
+    			
+    			public boolean accept(File dir, String filename) {
+    				String ext = filename.substring(filename.lastIndexOf(".") + 1, filename.length());
+    				File curent = new File(dir.toString()+"/"+filename);
+    				if(curent.isHidden())
+    					return false;
+    				else if(curent.isDirectory())
+    					return true;
+    				else if(ext.equals("MSH") || ext.equals("msh"))
+    					return true;
+    				else
+    					return false;
+    			}
+    		});
+    	}
+    	private class FileDialog extends DialogFragment {
+    		
+    		String[] list;
+    		int msg = -1;
+    		SDFileChooser parent;
+    		
+    		public FileDialog(SDFileChooser p, String[] l) {
+    			list = l;
+    			parent = p;
+    		}
+    		public FileDialog(SDFileChooser p, int m) {
+    			msg = m;
+    			parent = p;
+    		}
+    		
+    		@Override
+    		public Dialog onCreateDialog(Bundle savedInstanceState) {
+    			AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+    			if(msg > 0) {
+    				builder.setMessage(R.string.error_nomshfile)
+    				.setPositiveButton(R.string.button_ok, null);
+    			}
+    			else {
+    				builder.setTitle(R.string.dialog_title_choosefile);
+	        		builder.setItems(list, new DialogInterface.OnClickListener() {
+						
+						public void onClick(DialogInterface dialog, int which) {
+							if(list[which].equals(".."))
+								parent.setPath(curentPath.getParentFile().toString());
+							else if( new File(parent.getPath() + "/" + list[which]).isDirectory())
+								parent.setPath(parent.getPath() + "/" + list[which]);
+							else {
+								String ext = list[which].substring(list[which].lastIndexOf(".") + 1, list[which].length());
+			    				if(ext.equals("MSH") || ext.equals("msh")) {
+			    					gmsh.load(curentPath+"/"+getFile(curentPath)[which]);
+			    					glView.requestRender();
+			    				}
+							}
+						}
+					});
+    			}
+    			return builder.create();
+    		};
+    	}
+    	
+    }
+    
+    private class Run extends AsyncTask<Void, Void, Integer[]> {
+
+    	@Override
+    	protected void onPreExecute() {
+    		loading.setTitle("Please wait");
+        	loading.setButton(DialogInterface.BUTTON_NEUTRAL, "Hide", new DialogInterface.OnClickListener() {
+    			
+    			public void onClick(DialogInterface dialog, int which) {
+    				loading.dismiss();
+    			}
+    		});
+        	loading.setButton(DialogInterface.BUTTON_NEGATIVE, "Stop", new DialogInterface.OnClickListener() {
+    			
+    			public void onClick(DialogInterface dialog, int which) {
+    				//loading.dismiss();
+    				//run.setText("Run");
+    				gmsh.onelabCB("stop");
+    				run.setEnabled(false);
+    				//cancel(true);
+    			}
+    		});
+    		loading.setMessage("...");
+    		loading.show();
+    		//run.setEnabled(false);
+    		run.setText("Show progress");
+    		super.onPreExecute();
+    	}
+    	
+		@Override
+		protected Integer[] doInBackground(Void... params) {
+				gmsh.onelabCB("compute");
+			return new Integer[] {1};
+		}
+
+		@Override
+		protected void onPostExecute(Integer[] result) {
+			loading.dismiss();
+			//run.setEnabled(true);
+			run.setText("Run");
+			run.setEnabled(true);
+			glView.requestRender();
+			super.onPostExecute(result);
+		}
+    	
+    }
+
+    private final Handler mainHandler = new Handler(){
+    	public void handleMessage(android.os.Message msg) {
+    		switch (msg.what) {
+			case 0: // we get a message from gmsh library
+				String message =(String) msg.obj;
+				dialogBuilder
+			    .setTitle("Erreur Gmsh/GetDP")
+			    .setMessage(message)
+			    .setPositiveButton("Continue", new DialogInterface.OnClickListener() {
+			        public void onClick(DialogInterface dialog, int which) { 
+			            dialog.dismiss();
+			        }
+			     })
+			     .show();
+
+				break;
+			case 1: // request render from gmsh library
+				if(glView != null)
+				glView.requestRender();
+				getAvailableParam();
+				break;
+			case 2: // we get a message for loading
+				String loadingMessage =(String) msg.obj;
+				loading.setMessage(loadingMessage);
+				break;
+			case 3: // we get a progress for loading
+				loading.setProgress(msg.arg1);
+				break;
+			default:
+				break;
+			}
+    	};
+    };
+}
diff --git a/contrib/mobile/Android/src/org/geuz/onelab/ModeleArrayAdapter.java b/contrib/mobile/Android/src/org/geuz/onelab/ModeleArrayAdapter.java
new file mode 100644
index 0000000000..03b200a8d9
--- /dev/null
+++ b/contrib/mobile/Android/src/org/geuz/onelab/ModeleArrayAdapter.java
@@ -0,0 +1,54 @@
+package org.geuz.onelab;
+
+import android.content.Context;
+import android.graphics.Color;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+public class ModeleArrayAdapter extends ArrayAdapter<String> {
+	private Context context;
+	private String[] titres;
+	private String[] descriptions;
+
+	public ModeleArrayAdapter(Context context, String[] titres) {
+		super(context, R.layout.model, titres);
+		this.context = context;
+		this.titres = titres;
+	}
+	public ModeleArrayAdapter(Context context, String[] titres, String[] descriptions) {
+		this(context,titres);
+		this.descriptions = descriptions;
+	}
+	public ModeleArrayAdapter(Context context, Models models) {
+		super(context, R.layout.model, models.getNames());
+		this.context = context;
+		titres = new String[models.size()];
+		descriptions = new String[models.size()];
+		for(int i=0;i < models.size();i++) {
+			titres[i] = models.getName(i);
+			descriptions[i] = models.getSummary(i);
+		}
+		
+	}
+	
+	@Override
+	public View getView(int position, View convertView, ViewGroup parent){
+		LayoutInflater inflater = (LayoutInflater) context
+				.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+
+		View rowView = inflater.inflate(R.layout.model, parent, false);
+		TextView Titre = (TextView) rowView.findViewById(R.id.titre);
+		TextView Description = (TextView) rowView.findViewById(R.id.description);
+		ImageView Icone = (ImageView) rowView.findViewById(R.id.icone);
+		if(this.titres != null) Titre.setText(this.titres[position]);
+		if(this.descriptions != null) Description.setText(this.descriptions[position]);
+		if(Icone != null) Icone.setImageResource(R.drawable.ic_launcher);
+		Icone.setPadding(10, 10, 10, 10);
+		
+		return rowView;
+	}
+}
diff --git a/contrib/mobile/Android/src/org/geuz/onelab/Models.java b/contrib/mobile/Android/src/org/geuz/onelab/Models.java
new file mode 100644
index 0000000000..e5ab6f962a
--- /dev/null
+++ b/contrib/mobile/Android/src/org/geuz/onelab/Models.java
@@ -0,0 +1,40 @@
+package org.geuz.onelab;
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+class Models {
+	private List<String> _name;
+	private List<String> _summary;
+	private List<String> _file;
+	
+	public Models(){
+		_name = new ArrayList<String>();
+		_summary = new ArrayList<String>();
+		_file = new ArrayList<String>();
+	}
+	
+	public int size() {
+		return _name.size();
+	}
+	public String getName(int pos) {
+		return _name.get(pos);
+	}
+	public String[] getNames() {
+		String[] ret = new String[_name.size()];
+    	ret = _name.toArray(ret);
+    	return ret;
+	}
+	public String getSummary(int pos) {
+		return _summary.get(pos);
+	}
+	public String getFile(int pos) {
+		return _file.get(pos);
+	}
+	public void addModel(String name, String summary, String file){
+		_name.add(name);
+		_file.add(file);
+		_summary.add(summary);
+	}
+}
diff --git a/contrib/mobile/Android/src/org/geuz/onelab/Parameter.java b/contrib/mobile/Android/src/org/geuz/onelab/Parameter.java
new file mode 100644
index 0000000000..4e0040f566
--- /dev/null
+++ b/contrib/mobile/Android/src/org/geuz/onelab/Parameter.java
@@ -0,0 +1,85 @@
+package org.geuz.onelab;
+
+
+import android.content.Context;
+import android.graphics.Color;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+
+public class Parameter {
+	protected Context _context;
+	protected Gmsh _gmsh;
+	protected SeparatedListView _listView;
+	protected mGLSurfaceView _glView;
+	protected String _name;
+	protected String _label;
+	protected boolean _readOnly;
+	protected boolean _changed;
+	protected TextView _title;
+
+	public Parameter(Context context, Gmsh gmsh, mGLSurfaceView glView, String name){
+		_context = context;
+		_gmsh = gmsh;
+		_glView = glView;
+		_readOnly = false;
+		_name = name;
+		_title = new TextView(context);
+		_title.setText(name);
+		_title.setTextAppearance(context, android.R.style.TextAppearance_DeviceDefault_Medium);
+		_title.setTextColor(Color.DKGRAY);
+	}
+	public Parameter(Context context, Gmsh gmsh, mGLSurfaceView glView, String name, boolean readOnly){
+		this(context, gmsh, glView, name);
+		_readOnly = readOnly;
+		_changed = false;
+	}
+	
+	protected void update(){
+		if(_label != null && !_label.equals(""))
+			_title.setText(_label);
+		else {
+			String tmp[] = _name.split("/");
+			_title.setText(tmp[tmp.length-1]);
+		}
+		if(isReadOnly()) _title.setAlpha(0.423f);
+	}
+	
+	public void setName(String name) {_name = name;this.update();}
+	public void setReadOnly(boolean readOnly) {_readOnly = readOnly;this.update();}
+	public void setLabel(String label) {_label = label;this.update();}
+	public String getName() {return _name;}
+	public boolean isReadOnly() {return _readOnly;}
+	public String getLabel() {return _label;}
+	public int fromString(String s){
+		String[] infos = s.split("\n");
+		int pos=0;
+		pos++;// version
+		pos++;// type
+		setName(infos[pos++]);// name
+		setLabel(infos[pos++]);// label
+		pos++;// help
+		pos++;// never change
+		pos++;// changed
+		if(Integer.parseInt(infos[pos++]) != 1)return -1;// visible
+		this.setReadOnly((infos[pos++].equals("1")));// read only
+		int nAttributes = Integer.parseInt(infos[pos++]);// number of attributes
+		pos+=(nAttributes*2);// key+value
+		int nClients = Integer.parseInt(infos[pos++]);// number of client
+		pos+=nClients;// clients
+		this.update();
+		return pos;
+	}
+	public boolean changed() { if(_changed){_changed=false; return true;}return _changed;}
+	public String getType(){return "Parameter";}
+	
+	public void setList(SeparatedListView list){ _listView = list;}
+	
+	public LinearLayout getView() {
+		LinearLayout paramLayout = new LinearLayout(_context);
+		paramLayout.setOrientation(LinearLayout.VERTICAL);
+		paramLayout.addView(_title);
+		return paramLayout;
+	}
+}
+
diff --git a/contrib/mobile/Android/src/org/geuz/onelab/ParameterNumber.java b/contrib/mobile/Android/src/org/geuz/onelab/ParameterNumber.java
new file mode 100644
index 0000000000..73f0ce1659
--- /dev/null
+++ b/contrib/mobile/Android/src/org/geuz/onelab/ParameterNumber.java
@@ -0,0 +1,270 @@
+package org.geuz.onelab;
+
+import java.util.ArrayList;
+
+import android.content.Context;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.CheckBox;
+import android.widget.CompoundButton;
+import android.widget.EditText;
+import android.widget.LinearLayout;
+import android.widget.SeekBar;
+import android.widget.Spinner;
+
+public class ParameterNumber extends Parameter{
+	private double _value, _min, _max, _step;
+	private SeekBar _bar;
+	private ArrayList<Double> _values;
+	private ArrayList<String> _choices;
+	private ArrayAdapter<String> _adapter;
+	private Spinner _spinner;
+	private CheckBox _checkbox;
+	private EditText _edittext;
+	
+	public ParameterNumber(Context context, Gmsh gmsh, mGLSurfaceView glView, String name){
+		super(context, gmsh, glView, name);
+	}
+	public ParameterNumber(Context context, Gmsh gmsh, mGLSurfaceView glView, String name,  double value, double min, double max, double step)
+	{
+		this(context, gmsh, glView, name);
+		_value = value;
+		_min = min;
+		_max = max;
+		_step = step;
+	}
+	public ParameterNumber(Context context, Gmsh gmsh, mGLSurfaceView glView, String name, boolean readOnly, double value, double min, double max, double step)
+	{
+		this(context, gmsh, glView, name, value, min, max, step);
+		_readOnly = readOnly;
+	}
+	
+	protected void update(){
+		super.update();
+		int nDecimal = String.valueOf(this.getStep()).length() - String.valueOf(this.getStep()).lastIndexOf('.') - 1; // hack for double round
+		if(_bar != null){
+			if(_label != null && !_label.equals(""))
+			_title.setText(_label + " (" + Math.round(_value*Math.pow(10, nDecimal))/Math.pow(10, nDecimal) + ")");
+			else {
+				String tmp[] = _name.split("/");
+				_title.setText(tmp[tmp.length-1] + " (" + Math.round(_value*Math.pow(10, nDecimal))/Math.pow(10, nDecimal) + ")");
+			}
+			_bar.setProgress((int) ((_value-_min)/_step));
+			_bar.setMax((int) ((_max-_min)/_step));
+			_bar.setEnabled(!this.isReadOnly());
+		}
+		else if(_spinner != null)
+		{
+			for(int i=0;i<_choices.size();i++)
+				if(_values.get(i) == _value)
+					_spinner.setSelection(i, true);
+		}
+		else if(_checkbox != null)
+		{
+			if(_label != null) _checkbox.setText(_label);
+			else _checkbox.setText(_name);
+			_checkbox.setChecked((_value == 0)? false : true);
+		}
+		else if(_edittext != null)
+		{
+			_edittext.setText(""+Math.round(_value*Math.pow(10, nDecimal))/Math.pow(10, nDecimal));
+		}
+	}
+	
+	public void setValue(double value) {
+		if(value < _min || value > _max) {
+			Log.w("ParameterNumber", "Incorect value "+value+" (max="+_max+" min="+_min+")");
+			return;
+		}
+		if(value != _value)
+			_changed = true;
+		_value = value;
+		this.update();
+	}
+	public void setMin(double min) {_min = min;this.update();}
+	public void setMax(double max) {_max = max;this.update();}
+	public void setStep(double step) {_step = step;this.update();}
+	public void addChoice(double choice, String value) {
+		if(_values == null) {
+			_values = new ArrayList<Double>();
+			_choices = new ArrayList<String>();
+			_values.add(choice);
+			_choices.add(value);
+			if(_spinner == null) {
+				_spinner = new Spinner(_context);
+				_adapter = new ArrayAdapter<String>(_context, android.R.layout.simple_spinner_dropdown_item, _choices);
+				_adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+				_spinner.setAdapter(_adapter);
+			}
+		}
+		else
+		{
+			for(int i=0;i<_values.size();i++) {
+				if(_values.get(i).equals(choice) && _choices.size() > i) {
+					_choices.set(i, value);
+					return;
+				}
+				else if(_values.get(i).equals(choice))
+				{
+					_choices.add(value);
+					return;
+				}
+			}
+			_values.add(choice);
+			_choices.add(value);
+		}
+	}
+	public double getValue() {return _value;}
+	public double getMax() {return _max;}
+	public double getMin() {return _min;}
+	public double getStep() {return _step;}
+	public int fromString(String s){
+		int pos = super.fromString(s);
+		if(pos <= 0) return -1; // error
+		String[] infos = s.split("\n");
+		String tmpVal = infos[pos++];
+		if(tmpVal.equals("Inf")) // TODO set value to max ???
+			_value = 1;
+		else
+			_value = Double.parseDouble(tmpVal);
+		this.setMin(Double.parseDouble(infos[pos++]));
+		this.setMax(Double.parseDouble(infos[pos++]));
+		this.setStep(Double.parseDouble(infos[pos++]));
+		pos++;// index
+		int nChoix = Integer.parseInt(infos[pos++]); // choices' size
+		double choices[] = new double[nChoix];
+		for(int i=0; i<nChoix; i++)
+			if(nChoix == 2)
+				choices[i] = Double.parseDouble(infos[pos++]); // choice
+			else pos++;
+		int nLabels = Integer.parseInt(infos[pos++]); // labels' size
+		if(nChoix == 2 && choices[0] == 0 && choices[1] == 1 && nLabels == 0) {
+			_checkbox = new CheckBox(_context);
+			this.update();
+			return pos;
+		}
+		for(int i=0; i<nLabels && nChoix == nLabels; i++)
+		{
+			double val = Double.parseDouble(infos[pos++]); // choice
+			this.addChoice(val, infos[pos++]); // label
+		}
+		// ...
+		if(nLabels < 1 && _step == 0)
+			_edittext = new EditText(_context);
+		else if(nLabels < 1)
+			_bar = new SeekBar(_context);
+		this.update();
+		return pos;
+	}
+	public String getType(){return "ParameterNumber";}
+	public LinearLayout getView(){
+		LinearLayout paramLayout = new LinearLayout(_context);
+		paramLayout.setOrientation(LinearLayout.VERTICAL);
+		paramLayout.addView(_title);
+		if(_spinner != null) {
+			paramLayout.addView(_spinner);
+			_spinner.setEnabled(!_readOnly);
+			_spinner.setOnFocusChangeListener(new View.OnFocusChangeListener() {
+				
+				public void onFocusChange(View v, boolean hasFocus) {
+					if(_listView != null) _listView.refresh();
+				}
+			});
+			_spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+
+				public void onNothingSelected(AdapterView<?> arg0) {}
+
+				public void onItemSelected(AdapterView<?> parent, View view,
+						int pos, long id) {
+					if(_listView != null) _listView.refresh();
+					setValue(_values.get(pos));
+					_gmsh.setParam(getType(), getName(), String.valueOf(_values.get(pos)));
+					if(_gmsh.onelabCB("check") == 1 && _glView != null)
+						_glView.requestRender();
+				}
+
+			});
+		}
+		else if(_bar != null) {
+			paramLayout.addView(_bar);
+			_bar.setEnabled(!_readOnly);
+			_bar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
+				
+				public void onStopTrackingTouch(SeekBar seekBar) {
+					_gmsh.setParam(getType(), getName(), String.valueOf(getValue())); // update parameter and the perform a check
+					if(_gmsh.onelabCB("check") == 1  && _glView != null)
+						_glView.requestRender();
+				}
+				
+				public void onStartTrackingTouch(SeekBar seekBar) {}
+				
+				public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+					if(_listView != null) _listView.refresh();
+					setValue(getMin() + getStep()*(double)progress);
+				}
+			});
+		}
+		else if(_checkbox != null) {
+			paramLayout.removeView(_title);
+			paramLayout.addView(_checkbox);
+			_checkbox.setEnabled(!_readOnly);
+			_checkbox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
+				
+				public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+					if(_listView != null) _listView.refresh();
+					setValue((isChecked)? 1 : 0);
+					_gmsh.setParam(getType(), getName(), String.valueOf(_value));
+				}
+			});
+		}
+		else if(_edittext != null){
+			paramLayout.addView(_edittext);
+			_edittext.setEnabled(!_readOnly);
+			
+			_edittext.setOnKeyListener(new View.OnKeyListener() {
+				public boolean onKey(View v, int keyCode, KeyEvent event) {
+					if(keyCode == KeyEvent.KEYCODE_ENTER){ // hide the keyboard
+						InputMethodManager imm = (InputMethodManager)_context.getSystemService(
+							      Context.INPUT_METHOD_SERVICE);
+							imm.hideSoftInputFromWindow(_edittext.getWindowToken(), 0);
+							_gmsh.setParam(getType(), getName(), String.valueOf(_value));
+						_edittext.clearFocus();
+						return true;
+					}
+					if(keyCode > KeyEvent.KEYCODE_9 && keyCode != KeyEvent.KEYCODE_NUMPAD_DOT && (keyCode <KeyEvent.KEYCODE_NUMPAD_0 || keyCode >KeyEvent.KEYCODE_NUMPAD_9) && keyCode != KeyEvent.KEYCODE_DEL)
+							return true;
+					return false;
+				}
+			});
+			_edittext.addTextChangedListener(new TextWatcher() {
+				
+				public void onTextChanged(CharSequence s, int start, int before, int count) {
+					if(_listView != null) _listView.refresh();
+					double value = 1;
+					try {
+						if(s.length() < 1) value = 1;
+						else value = Double.parseDouble(s.toString());
+					}
+					catch(NumberFormatException e)
+					{
+						value = 1;
+						//_edittext.setText("");
+					}
+					_value = value;
+					_changed = true;
+				}
+				
+				public void beforeTextChanged(CharSequence s, int start, int count, int after) {} // UNUSED Auto-generated method stub
+				public void afterTextChanged(Editable s) {} // UNUSED Auto-generated method stub
+
+			});
+		}
+		return paramLayout;
+	}
+}
diff --git a/contrib/mobile/Android/src/org/geuz/onelab/ParameterString.java b/contrib/mobile/Android/src/org/geuz/onelab/ParameterString.java
new file mode 100644
index 0000000000..d1048d0d2c
--- /dev/null
+++ b/contrib/mobile/Android/src/org/geuz/onelab/ParameterString.java
@@ -0,0 +1,152 @@
+package org.geuz.onelab;
+
+import java.util.ArrayList;
+
+import android.content.Context;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.EditText;
+import android.widget.LinearLayout;
+import android.widget.Spinner;
+
+public class ParameterString extends Parameter{
+	
+	private  String _kind;
+	private int _index;
+	private ArrayList<String> _choices;
+	private ArrayAdapter<String> _adapter;
+	private Spinner _spinner;
+	private EditText _edittext;
+	
+	public ParameterString(Context context, Gmsh gmsh, mGLSurfaceView glView, String name) {
+		super(context, gmsh, glView, name);
+		_choices = new ArrayList<String>();
+		_choices.add("-"); // Default choice
+	}
+	
+	private void createSpinner()
+	{
+		if(_spinner != null) return;
+		_spinner = new Spinner(_context);
+		_adapter = new ArrayAdapter<String>(_context, android.R.layout.simple_spinner_dropdown_item, _choices);
+		_adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+		_spinner.setAdapter(_adapter);
+	}
+	
+	protected void update(){
+		super.update();
+		if(_spinner != null)
+			_spinner.setSelection(_index);
+		else if(_edittext != null && _choices.size() > 0)
+			_edittext.setText(_choices.get(0));
+	}
+	
+	public void setValue(int index) {if(index != _index)_changed = true;_index = index;this.update();}
+	public void setValue(String value) {
+		int index = _choices.indexOf(value);
+		if(index < 0) { // the value is not in the list, add it
+			this.addChoices(value);
+			index = _choices.indexOf(value);
+		}
+		if(index != _index)_changed = true;
+		_index = index;this.update();
+	}
+	public void setKind(String kind) {_kind = kind;}
+	public void addChoices(String choice) {
+		if(_edittext == null && _spinner == null) createSpinner();
+		for(String c : _choices) // do not add a duplicate value
+			if(c.equals(choice))return;
+		if(_choices.get(0).equals("-")) // remove the default choice with the first added choice
+			_choices.remove(0);
+		_choices.add(choice);
+		this.update();
+	}
+	public String getValue() {if( _index < 0) return "";return _choices.get(_index);}
+	public String getKind() {return _kind;}
+	public int getIndex() {return _index;}
+	public ArrayList<String> getChoices() {return _choices;}
+	public int fromString(String s){
+		int pos = super.fromString(s);
+		if(pos <= 0) return -1; // error
+		String[] infos = s.split("\n");
+		String value = infos[pos++];
+		setKind(infos[pos++]); // generic file 
+		if(_kind.equals("file"))
+			return -1;
+		int nChoices = Integer.parseInt(infos[pos++]);
+		if(nChoices < 1 && _kind.equals("generic"))
+			_edittext = new EditText(_context);
+		for(int i=0;i<nChoices;i++) this.addChoices(infos[pos++]);
+		// ...
+		setValue(value);
+		this.update();
+		return pos;
+	}
+	public String getType(){return "ParameterString";}
+	public LinearLayout getView() {
+		LinearLayout paramLayout = new LinearLayout(_context);
+		paramLayout.setOrientation(LinearLayout.VERTICAL);
+		paramLayout.addView(_title);
+		if(_spinner != null){
+			paramLayout.addView(_spinner);
+			_spinner.setEnabled(!_readOnly);
+			_spinner.setOnFocusChangeListener(new View.OnFocusChangeListener() {
+				
+				public void onFocusChange(View v, boolean hasFocus) {
+					if(_listView != null) _listView.refresh();
+				}
+			});
+			_spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+
+				public void onNothingSelected(AdapterView<?> arg0) {}
+
+				public void onItemSelected(AdapterView<?> parent, View view,
+						int pos, long id) {
+					if(_listView != null) _listView.refresh();
+					setValue(pos);
+					_gmsh.setParam(getType(), getName(), String.valueOf(getValue()));
+					if(_gmsh.onelabCB("check") == 1 && _glView != null)
+						_glView.requestRender();
+				}
+
+			});
+		}
+		else if(_edittext != null){
+			paramLayout.addView(_edittext);
+			_edittext.setEnabled(!_readOnly);
+			_edittext.setOnKeyListener(new View.OnKeyListener() {
+				
+				public boolean onKey(View v, int keyCode, KeyEvent event) {
+					if(keyCode == KeyEvent.KEYCODE_ENTER){ // hide the keyboard
+						InputMethodManager imm = (InputMethodManager)_context.getSystemService(
+							      Context.INPUT_METHOD_SERVICE);
+							imm.hideSoftInputFromWindow(_edittext.getWindowToken(), 0);
+							_edittext.clearFocus();
+						return true;
+					}
+					return false;
+				}
+			});
+			_edittext.addTextChangedListener(new TextWatcher() {
+				
+				public void onTextChanged(CharSequence s, int start, int before, int count) {
+					if(_listView != null) _listView.refresh();
+				}
+				
+				public void beforeTextChanged(CharSequence s, int start, int count,
+						int after) {} // UNUSED Auto-generated method stub
+				
+				public void afterTextChanged(Editable s) {
+					_gmsh.setParam(getType(), getName(), _choices.get(0));
+				}
+			});
+		}
+		return paramLayout;
+	}
+	
+}
diff --git a/contrib/mobile/Android/src/org/geuz/onelab/SeparatedListView.java b/contrib/mobile/Android/src/org/geuz/onelab/SeparatedListView.java
new file mode 100644
index 0000000000..a88285ef46
--- /dev/null
+++ b/contrib/mobile/Android/src/org/geuz/onelab/SeparatedListView.java
@@ -0,0 +1,144 @@
+package org.geuz.onelab;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.ListView;
+import android.widget.TextView;
+
+
+public class SeparatedListView extends ListView{
+
+	private SeparatedListAdaptater adapter;
+	private Context _context;
+	
+	public SeparatedListView(Context context) {
+		super(context);
+		_context = context;
+		adapter = new SeparatedListAdaptater();
+		this.setAdapter(adapter);
+	}
+	public SeparatedListView(Context context, View[] footer) {
+		super(context);
+		_context = context;
+		for(View v : footer)
+			this.addFooterView(v);
+		adapter = new SeparatedListAdaptater();
+		this.setAdapter(adapter);
+	}
+	
+	public void addItem(String header, View item) {
+		TextView title = (TextView)((LayoutInflater) _context.getSystemService( Context.LAYOUT_INFLATER_SERVICE )).inflate(R.layout.list_header, null);
+		title.setText(header);
+		adapter.addItem(header, title, item);
+		adapter.notifyDataSetChanged();
+		this.invalidateViews();
+	}
+	
+	public void refresh()
+	{
+		adapter.notifyDataSetChanged();
+		this.invalidateViews();
+	}
+	
+	public void clear()
+	{
+		adapter.clear();
+		adapter.notifyDataSetChanged();
+	}
+	
+	private class Section{
+		private String _name;
+		private List<View> _items;
+		public Section(String name){
+			_name = name;
+			_items = new ArrayList<View>();
+		}
+		public void addItem(View v){
+			_items.add(v);
+		}
+		public String getName(){
+			return _name;
+		}
+		public int getItemsCount(){
+			return _items.size();
+		}
+		public View getItem(int pos){
+			return _items.get(pos);
+		}
+	}
+	
+	private class SeparatedListAdaptater extends BaseAdapter{
+
+		List<Section> sections;
+		List<View> titles;
+		
+		public SeparatedListAdaptater() {
+			sections = new ArrayList<SeparatedListView.Section>();
+			titles = new ArrayList<View>();
+		}
+		
+		public void addItem(String header, View title, View item) {
+			for(Section s : sections){
+				if(s.getName().equals(header)){
+					s.addItem(item);
+					return;
+				}
+			}
+			Section s = new Section(header);
+			s.addItem(item);
+			sections.add(s);
+			titles.add(title);
+		}
+		
+		//@Override
+		public int getCount() {
+			int count = 0;
+			for(Section s : sections) count += s.getItemsCount() + 1;
+			return count;
+		}
+
+		//@Override
+		public Object getItem(int position) {
+			// UNUSED Auto-generated method stub
+			return null;
+		}
+
+		//@Override
+		public long getItemId(int position) {
+			// UNUSED Auto-generated method stub
+			return 0;
+		}
+
+		//@Override
+		public View getView(int position, View convertView, ViewGroup parent) {
+			int section = -1,
+					lastPosition = -1;
+			while(lastPosition<position){
+				int itemsCount = sections.get(section+1).getItemsCount();
+				if(lastPosition+1 == position)// this is a section
+					return titles.get(section+1);
+				else if(lastPosition+1+itemsCount >= position){ // the view is in this section
+					if(section<0) return sections.get(section+1).getItem(position-1);
+					return sections.get(section+1).getItem(position-lastPosition-2);
+				}
+				lastPosition+= 1 + itemsCount;
+				section++;
+			}
+			return null;
+		}
+		public void clear()
+		{
+			sections.clear();
+			titles.clear();
+		}
+		
+	}
+
+}
+
diff --git a/contrib/mobile/Android/src/org/geuz/onelab/mGLSurfaceView.java b/contrib/mobile/Android/src/org/geuz/onelab/mGLSurfaceView.java
new file mode 100644
index 0000000000..d57d57dfc6
--- /dev/null
+++ b/contrib/mobile/Android/src/org/geuz/onelab/mGLSurfaceView.java
@@ -0,0 +1,133 @@
+package org.geuz.onelab;
+
+import android.content.Context;
+import android.opengl.GLSurfaceView;
+import android.support.v4.view.MotionEventCompat;
+import android.view.GestureDetector;
+import android.view.MotionEvent;
+import android.view.ScaleGestureDetector;
+import android.view.View;
+import android.view.GestureDetector.OnDoubleTapListener;
+import android.view.GestureDetector.OnGestureListener;
+import android.view.ScaleGestureDetector.OnScaleGestureListener;
+
+class mGLSurfaceView extends GLSurfaceView {
+	private float scaleFactor = 1f;
+	private GestureDetector gesture;
+	private ScaleGestureDetector scaleGesture;
+	private float lastX, lastY;
+	private GLESRender _renderer;
+	public mGLSurfaceView(Context context, GLESRender renderer) {
+		super(context);
+		_renderer = renderer;
+		gesture = new GestureDetector(context, new GestureListener(this));
+		scaleGesture = new ScaleGestureDetector(context, new OnScaleGestureListener() {
+			
+			public void onScaleEnd(ScaleGestureDetector detector) {}// UNUSED Auto-generated method stub
+			
+			public boolean onScaleBegin(ScaleGestureDetector detector) {return true;}// UNUSED Auto-generated method stub
+			
+			public boolean onScale(ScaleGestureDetector detector) {
+				scaleFactor *= detector.getScaleFactor();
+				scaleFactor = Math.max(0.1f, Math.min(scaleFactor, 50.0f)); 
+				_renderer.scale(scaleFactor, scaleFactor, scaleFactor);
+				requestRender();
+				return true;
+				
+			}
+		});
+	}
+		
+	@Override
+	public boolean onTouchEvent(MotionEvent event) {
+		if(event.getPointerCount() >= 3){
+			scaleGesture.onTouchEvent(MotionEvent.obtain(0, 0, MotionEvent.ACTION_CANCEL, 0,0, 0));
+			
+			final float x = MotionEventCompat.getX(event, 1);
+	        final float y = MotionEventCompat.getY(event, 1);
+	        
+	        int action = MotionEventCompat.getActionMasked(event);
+	        
+	        if(action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_POINTER_1_DOWN){
+	        	lastX = x;
+	        	lastY = y;
+	        }
+	        else if(action == MotionEvent.ACTION_MOVE){
+	        	float dx = x - lastX,
+	        			dy = y - lastY;
+	        	if(dx != 0 || dy != 0)
+	        		_renderer.rotate(dy, dx, 0);
+	        	requestRender();
+	        	lastX = x;
+	        	lastY = y;
+	        }
+
+			return true;
+		}
+		else {
+			scaleGesture.onTouchEvent(event);
+			return gesture.onTouchEvent(event);
+		}
+		
+	}
+	
+	private class GestureListener implements OnGestureListener, OnDoubleTapListener{
+		//private View view;
+		public GestureListener(View view) {
+			//this.view = view;
+		}
+		public boolean onDown(MotionEvent e) {
+			// UNUSED Auto-generated method stub
+			return true;
+		}
+
+		public boolean onFling(MotionEvent e1, MotionEvent e2,
+				float velocityX, float velocityY) {
+			// UNUSED Auto-generated method stub
+			return false;
+		}
+
+		public void onLongPress(MotionEvent e) {
+			// UNUSED Auto-generated method stub
+			
+		}
+
+		public boolean onScroll(MotionEvent e1, MotionEvent e2,
+				float distanceX, float distanceY) {
+			_renderer.translate(-distanceX, distanceY, 0f);
+			requestRender();
+			return false;
+		}
+
+		public void onShowPress(MotionEvent e) {
+			// UNUSED Auto-generated method stub
+			
+		}
+
+		public boolean onSingleTapUp(MotionEvent e) {
+			// UNUSED Auto-generated method stub
+			return false;
+		}
+		public boolean onDoubleTap(MotionEvent e) {
+			// UNUSED Auto-generated method stub
+			return false;
+		}
+		public boolean onDoubleTapEvent(MotionEvent e) {
+			_renderer.translate(0f, 0f, 0f);
+			scaleFactor = 1f;
+			_renderer.scale(scaleFactor, scaleFactor, scaleFactor);
+			_renderer.rotate(0, 0, 0);
+			requestRender();
+			return false;
+		}
+		public boolean onSingleTapConfirmed(MotionEvent e) {
+			// UNUSED Auto-generated method stub
+			return false;
+		}
+		
+	}
+	public void resetScale(){
+		scaleFactor = 1f;
+		_renderer.scale(scaleFactor, scaleFactor, scaleFactor);
+	}	
+}
-- 
GitLab