User Tools

Site Tools


android

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
android [2015/02/21 16:25] – [ScrolView] skipidarandroid [2022/09/03 22:42] (current) skipidar
Line 1: Line 1:
 +==== Linux environment ====
 +How to set up a headless build environment.
 +
 +|OS|Ubuntu 20.04|
 +|Android SDK|Android 11 (API level 30) as of 26.11.2021|
 +
 +
 +==== Install android-sdk on Ubuntu ====
 +
 +<sxh bash>
 +# install openjdk8 - tested android sdk and its compatible
 +sudo apt-get install openjdk-8-jdk
 +# activate the 8th version if you have multiple using:
 +# sudo update-alternatives --config java
 +
 +
 +# install android-sdk under /usr/lib/android-sdk/
 +sudo apt update && sudo apt install android-sdk
 +
 +
 +
 +# download the commandlinetools and add them to sdk
 +# <sdk>/cmdline-tools/latest/
 +wget -P /tmp/ https://dl.google.com/android/repository/commandlinetools-linux-6858069_latest.zip
 +
 +# check https://stackoverflow.com/questions/60440509/android-command-line-tools-sdkmanager-always-shows-warning-could-not-create-se
 +sudo mkdir -p /usr/lib/android-sdk/cmdline-tools/
 +
 +sudo unzip /tmp/commandlinetools-*.zip -d /usr/lib/android-sdk/cmdline-tools/
 +sudo mv /usr/lib/android-sdk/cmdline-tools/cmdline-tools/ /usr/lib/android-sdk/cmdline-tools/tools/
 +
 +# open bashrc and modify the environment variables
 +vim ~/.bashrc
 +export ANDROID_HOME="/usr/lib/android-sdk/"
 +export PATH=$PATH:$ANDROID_HOME/cmdline-tools/tools/bin:$ANDROID_HOME/platform-tools
 +
 +# apply changes in bashrc
 +source ~/.bashrc
 +
 +
 +# setting the rights 
 +sudo chown $USER:$USER $ANDROID_HOME -R
 +
 +
 +
 +# can successfully access the sdkmanager
 +sdkmanager --version
 +
 +# install the platform tools https://developer.android.com/studio/releases/platform-tools
 +sdkmanager "platform-tools" "platforms;android-29"
 +
 +# install the build tools https://developer.android.com/studio/releases/build-tools
 +sdkmanager "build-tools;29.0.3"
 +
 +
 +# confirm all the licenses for the android tools otherwise they wont work
 +yes | sdkmanager --licenses
 +
 +
 +# check for android sdk updates
 +sdkmanager --update
 +
 +
 +
 +
 +# you can build android project now 
 +cd <YOUR_ANDROID_PROJECT>
 +./gradlew build
 +
 +
 +
 +
 +</sxh>
 +
 +
 +
 +
 +==== HOWTO ====
 +
 +=== Plan app's Layout ===
 +  * use Fragments for top level elements which may be reused, since fragments **can not be nested**.
 +  * implement Views with custom Layout, implemented in **xml** to use these blocks on deeper levels. \\ These views can be nested. \\ implement layout in xml and assign the xml layout to the view (see Create a View class which will wrap the XML Layout)
 +
 +==== Declaring custom XML attributes ====
 +
 +An in detail describtion about declaring custom XML attributes for custom views can be found here:
 +[[http://stackoverflow.com/questions/2695646/declaring-a-custom-android-ui-element-using-xml]]
 +
 +<fc #FF0000>ACHTUNG:</fc>
 +
 +  - Nutze diesen Namespace, statt den der eigenen App: <code>xmlns:app="http://schemas.android.com/apk/res-auto"</code>
 +==== Fading Background ====
 +Is described here: http://nathanael.hevenet.com/android-dev-fading-background-animation/
 +
 +==== ListView ====
 +
 +== Select Item ==
 +<sxh java>
 + listView.setItemChecked(1, true);
 +</sxh>
 +== Iterate Items==
 +<sxh java>
 +  ContentListAdapter contentListAdapter = (ContentListAdapter) listView.getAdapter();
 +
 + for(int i=0; i<contentListAdapter.getCount(); i++){
 + View v = (View) contentListAdapter.getItem(i);
 + Log.d("View","Child is "+v );
 +</sxh>
 +
 +==== Using JAR Libs ====
 +A Jar can be added to android, by putting it into the **libs** folder!
 +
 +
 +**ACHTUNG:** 
 +
 +Adroid kann nur JARs nutzen, die mit dem Compiler 1.7 gebaut wurden.
 +Falls dies nicht der Fall ist - wird eine NoClassDefFound exception geworfen.
 +
 +{{http://i520.photobucket.com/albums/w327/schajtan/2013-08-20_11-09-46_zps4723ec3c.png}}
 +
 +
 +==== Tools ====
 +The tool monitor.bat can be used as a Standalone logger! Details are [[http://developer.android.com/tools/debugging/ddms.html#running|here]]
 +
 +{{http://i520.photobucket.com/albums/w327/schajtan/2013-09-02_11-00-07_zps3bb644a0.png}}
 +
 +
 +=== Aapt  ===
 +Inspect the APK is done via
 +
 +<code>
 +D:\Development\Eclipse Juno - Android\sdk\build-tools\android-4.2.2\aapt.exe dump badging theApp.apk
 +</code>
 +
 +=== Unpackaging the APK is done via ===
 +https://code.google.com/p/android-apktool/downloads/detail?name=apktool-install-windows-2.2_r01-3.tar.bz2
 +
 +<code>
 +apktool d HelloWorld.apk ./HelloWorld
 +</code>
 +
 +=== Genimotion  ===
 +Genimotion is a nice and fast Android VM.
 +
 +It may support ARM Architecture, but this option must be enabled.
 +How to do that is described here: http://forum.xda-developers.com/showthread.php?t=2528952
 +==== Maven ====
 +
 +== Dependncies ==
 +
 +**ACHTUNG:** 
 +For some reason the dependencies form parent pom are not inherited to the child pom. 
 +So always add dependencies directly to children
 +
 +Dependency to my own apklib:
 +
 +The apklib
 +<code>
 + <artifactId>barcode-lib-commons-dataproject</artifactId>
 +    <name>BarcodeLibCommonsDataProject</name>
 +    <version>1.0.0</version>
 +    <packaging>apklib</packaging>
 +</code>
 +
 +The dependency
 +<code>
 +        <!-- Barcode Helper Lib  -->
 +        <dependency>
 +            <groupId>de.ivu.fare.apps-13.2.PIROL</groupId>
 +            <artifactId>barcode-lib-commons-dataproject</artifactId>
 +            <version>1.0.0</version>
 +            <type>apklib</type>
 +        </dependency>
 +</code>
 +
 +
 +
 +==Package type==
 +
 +
 +The apk is an App.
 +<code>
 +    <artifactId>barcodelib2</artifactId>
 +    <version>1.0.0</version>
 +    <packaging>apk</packaging>
 +    <name>Barcode-Lib2</name>
 +</code>
 +
 +The apklib - is the android lib project
 +<code>
 +    <artifactId>barcodelib2</artifactId>
 +    <version>1.0.0</version>
 +    <packaging>apklib</packaging>
 +    <name>Barcode-Lib2</name>
 +</code>
 +
 +
 +==Signieren==
 +Wie man Maven einrichtet, um eine signierte APK bauen zu können steth hier: \\
 +http://www.simpligility.com/2010/07/sign-zipalign-and-to-market-to-market-with-maven/
 +
 +Danach kann eine signierte **apk** z.B. durch erzeugt werden: 
 +<code>
 +mvn clean install
 +</code>
 +
 +
 +==ZipAlign==
 +TO do the zipalign - use the code as described here: http://stackoverflow.com/questions/10915922/how-to-check-that-maven-goal-called-during-phase
 +
 +DO not forget the **<skip>false</skip>**
 +<code>
 +        <plugin>
 +            <groupId>com.jayway.maven.plugins.android.generation2</groupId>
 +            <artifactId>android-maven-plugin</artifactId>
 +            <version>3.2.0</version>
 +            <extensions>true</extensions>
 +            <configuration>
 +                <sdk>
 +                    <platform>8</platform>
 +                </sdk>
 +                <emulator>
 +                    <avd>2.3.3_API-10</avd>
 +                </emulator>
 +                <undeployBeforeDeploy>true</undeployBeforeDeploy>
 +                <assetsDirectory>${project.build.directory}/filtered-assets</assetsDirectory>
 +                <androidManifestFile>${project.build.directory}/filtered-manifest/AndroidManifest.xml</androidManifestFile>
 +                <zipalign>
 +                    <skip>false</skip>
 +                    <verbose>${build.verbosity}</verbose>
 +                    <inputApk>${project.build.directory}/${project.artifactId}-${build.version.name}.apk</inputApk>
 +                    <outputApk>${project.build.directory}/${project.artifactId}-${build.version.name}-aligned.apk</outputApk>
 +                </zipalign>
 +            </configuration>
 +            <executions>
 +                <execution>
 +                    <id>zipalign</id>
 +                    <phase>package</phase>
 +                    <goals>
 +                        <goal>zipalign</goal>
 +                    </goals>
 +                </execution>
 +            </executions>
 +        </plugin>
 +</code>
 +
 +==Release==
 +Bauene in release mode, so dass die Variable **BuildConfig.DEBUG==false** ist:
 +ist beim plugin **android-maven-plugin** am besten über einen Parameter **-Dandroid.release=true** steuerbar.
 +
 +Die Details sind hier beschrieben: [[http://stackoverflow.com/questions/15055961/android-maven-plugin-disable-debug-build-for-apk|http://stackoverflow.com/questions/15055961/android-maven-plugin-disable-debug-build-for-apk]]
 +
 +<code>
 +clean install -Dandroid.release=true
 +</code>
 +==== In-App Payments ====
 +
 +^Method ^ Describtion ^ Methods ^ Transaction fee ^
 +|Native  Android Play In-App Payments| Billed via Google Play Account. Service https://wallet.google.com is used. | Credit Card (Visa) \\ Debit Card (Master Card) | [[https://support.google.com/googleplay/android-developer/answer/112622?hl=en&ref_topic=15867|30%]] |
 +||||
 +
 +==== Certificates ====
 +Check Signature
 +<code>
 +jarsigner -verify -verbose -certs my_application.apk
 +</code>
 +
 +
 +The Certificate can be extracted from an APK.
 +Just Exctract the File META-INF\ADT.RSA from the apk file, since an apk can be entered as a normal zip.
 +Then use the following code to convert the ADT.RSA to the certificate.
 +<code>
 +openssl.exe pkcs7 -in ADT.RSA -print_certs -inform DER -out ADT.RSA.CER
 +</code>
 +
 +
 +==== Services ====
 +Services may run, after the app was stopped.
 +
 +<sxh java>
 +public class MyService extends IntentService {
 +
 + public MyService() {
 + super("MyService");
 + }
 +
 + @Override
 + protected void onHandleIntent(Intent intent) { }
 +
 +
 +
 + /**
 + * Services has to use Handlers to toast messages
 + * @param context - the app context
 + * @param message - the message to toast
 + * @param handler - the handler to reuse
 + */
 + public static void toastFromService(final Context context,
 + final String message, Handler handler) {
 + handler.post(new Runnable() {
 + @Override
 + public void run() {
 + Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
 + LOG.info("Service message: "+ message);
 + }
 + });
 + }
 +
 +        /** Start the instance of IntentService service by sending an Intent */
 + public static final void start(Context context) {
 + Intent intent = new Intent(context, MyService.class);
 + context.startService(intent);
 + }
 +
 +        /** to toast stuff use  the handler */
 + void toastMessage(final String message){
 + handler.post(new Runnable() {
 + @Override
 + public void run() {
 + Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show();
 + }
 + });
 + }
 +</sxh>
 +
 +==== Automatic Testing ====
 +  - Create a new Test Project, as [http://developer.android.com/tools/testing/testing_android.html|stated here]]
 +
 +== android.test.ActivityInstrumentationTestCase2<MyActivityUnderTest> ==
 +Use this clss to test activities.
 +
 +  * Every method in this class will be executed as a JUnitTest.
 +  * Before every test  - the method **setUp()** is executed
 +  * test methods names have to start with **"test"**, or they won't be found
 +
 +
 +=== Espresso - UI tests ===
 +
 +<sxh java>
 +package digital.alf.geosound;
 +
 +import static androidx.test.espresso.Espresso.onView;
 +import static androidx.test.espresso.assertion.ViewAssertions.matches;
 +import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
 +import static androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility;
 +import static androidx.test.espresso.matcher.ViewMatchers.withText;
 +import static org.hamcrest.CoreMatchers.allOf;
 +
 +import android.Manifest;
 +import android.app.Activity;
 +import android.os.Bundle;
 +
 +import androidx.navigation.NavController;
 +import androidx.navigation.Navigation;
 +import androidx.test.espresso.action.ViewActions;
 +import androidx.test.espresso.matcher.ViewMatchers;
 +import androidx.test.ext.junit.rules.ActivityScenarioRule;
 +import androidx.test.ext.junit.runners.AndroidJUnit4;
 +import androidx.test.filters.LargeTest;
 +import androidx.test.rule.GrantPermissionRule;
 +
 +import org.junit.Rule;
 +import org.junit.Test;
 +import org.junit.runner.RunWith;
 +
 +@RunWith(AndroidJUnit4.class)
 +@LargeTest
 +public class JustOpenAllWindows {
 +
 +    @Rule
 +    public ActivityScenarioRule<MainActivity> activityRule = new ActivityScenarioRule<>(MainActivity.class);
 +
 +    @Rule
 +    public GrantPermissionRule mRuntimePermissionRuleFine = GrantPermissionRule.grant(android.Manifest.permission.ACCESS_FINE_LOCATION);
 +
 +    @Rule
 +    public GrantPermissionRule mRuntimePermissionRuleCoarse = GrantPermissionRule.grant(Manifest.permission.ACCESS_COARSE_LOCATION);
 +
 +    @Rule
 +    public GrantPermissionRule mRuntimePermissionRuleBackground = GrantPermissionRule.grant(Manifest.permission.ACCESS_BACKGROUND_LOCATION);
 +
 +
 +    @Test
 +    public void openPreferences() {
 +
 +        activityRule.getScenario().onActivity(activity -> {
 +            Bundle args = new Bundle();
 +            NavController navController = Navigation.findNavController(activity, R.id.map);
 +            navController.navigate(R.id.action_fragment_maps_to_fragment_preferences, args);
 +        });
 +
 +        onView(allOf(ViewMatchers.withText(R.string.dialog_preference_label), withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
 +                .check(matches(isDisplayed()));
 +
 +        onView(ViewMatchers.withText(R.string.dialog_default_onout_volume_title))
 +                .perform(ViewActions.click());
 +
 +        //Click on cancel button
 +        onView(ViewMatchers.withId(android.R.id.button2))
 +                .perform(ViewActions.click());
 +
 +
 +        onView(ViewMatchers.withText(R.string.dialog_default_onout_volume_title))
 +                .perform(ViewActions.click());
 +
 +        //Click on cancel button
 +        onView(ViewMatchers.withId(android.R.id.button2))
 +                .perform(ViewActions.click());
 +
 +        System.out.println("done");
 +    }
 +
 +}
 +
 +</sxh>
 +
 +=== Execution in CodeBuild ===
 +https://devops.stackexchange.com/questions/3965/configuration-of-aws-codepipeline-for-android-ci-cd
 +
 +
 +==== Snippets ====
 +
 +=== Preference Item with value in Summary ===
 +
 +Declare an own xml attribute for custom Views. Add this to **res/values/attrs.xml**
 +This attribute will contain the Mask for the summary, as known by //String.format(mask, value)//
 +<code>
 +    <declare-styleable name="PreferenceSummaryValue">
 +        <attr name="summaryFormat" format="string"/>
 +    </declare-styleable>
 +</code>
 +
 +Use own attribute
 +<code>
 +        <de.ivu.eticket.app.gui.PreferenceSummaryValue
 +        android:key="deadline"
 +        android:defaultValue="12"
 +        android:title="The Deadline" 
 +        app:summaryFormat="end in %s days"/>
 +</code>
 +
 +Implement own preference view
 +<code>
 +public class PreferenceSummaryValue extends EditTextPreference {
 +
 + private String summaryFormat = "%s";
 +
 + public PreferenceSummaryValue(Context context) {
 + super(context);
 + init(null, context);
 + }
 +
 + public PreferenceSummaryValue(Context context, AttributeSet attrs) {
 + super(context, attrs);
 + init(attrs, context);
 + }
 +
 + public PreferenceSummaryValue(Context context, AttributeSet attrs,
 + int defStyle) {
 + super(context, attrs, defStyle);
 + init(attrs, context);
 + }
 +
 + private void init(AttributeSet attributes, Context context){
 + if(attributes != null){
 + TypedArray tarr = context.obtainStyledAttributes(attributes, R.styleable.PreferenceSummaryValue);
 + String attribute = tarr.getString(R.styleable.PreferenceSummaryValue_summaryFormat);
 + if(attribute != null) summaryFormat = attribute;
 + tarr.recycle();
 + }
 + }
 +
 + @Override
 + public void setText(String text) {
 + super.setText(text);
 + setSummary(String.format(summaryFormat, text));
 + }
 +
 + @Override
 + public void setSummary(CharSequence summary) {
 + super.setSummary(summary);
 + }
 +
 + public void setSummaryFormat(String summaryFormat) {
 + this.summaryFormat = summaryFormat;
 + }
 +}
 +</code>
 +
 +
 +
 +==== Layouts ====
 +
 +=== TableLayout ===
 +
 +  * Kann wirklich nur gleichmaeßige Zellen darstellen.
 +  * Kann kein RowSpan
 +  * Die Rows existieren als ein besonderes Objekt "TableRow"
 +  * Die Columns als besondere Objekte existieren nicht - es werden die CHildViews einfach gleich groß gehalten werden
 +  * Nur gleiche layouts sollten als Columns benutzt werden. TableLayout mit 1 TabeRow und LinearLayout als Table Column klappt gut.
 +  * Nutze Lieber GridLayout
 +
 +
 +<sxh java>
 +<?xml version="1.0" encoding="utf-8"?>
 +<LinearLayout android:layout_width="match_parent"
 +    android:layout_height="match_parent"
 +    android:orientation="vertical" xmlns:android="http://schemas.android.com/apk/res/android">
 +
 +    <TableLayout
 +        android:layout_width="match_parent"
 +        android:layout_height="wrap_content"
 +        android:stretchColumns="0" >
 +
 +        <TableRow android:id="@+id/tableRow1" android:layout_width="match_parent" android:layout_height="wrap_content">
 +
 +            <TableLayout
 +                android:layout_width="match_parent"
 +                android:layout_height="wrap_content" >
 +
 +                <TableRow android:id="@+id/tableRow1" android:layout_width="match_parent" android:layout_height="wrap_content">
 +                    <TextView android:padding="5dp" android:id="@+id/textView1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textAppearance="?android:attr/textAppearanceMedium" android:text="Text"></TextView> </TableRow>
 +                
 +                <View android:background="@color/grey_light" android:layout_height="1px"></View>
 +                
 +                <TableRow android:id="@+id/tableRow1" android:layout_width="match_parent" android:layout_height="wrap_content"> 
 +                    <TextView android:padding="5dp" android:id="@+id/textView1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textAppearance="?android:attr/textAppearanceMedium" android:text="Text"></TextView> </TableRow>
 +    </TableLayout>
 +   
 +            <TableLayout
 +                android:layout_width="match_parent"
 +                android:layout_height="wrap_content" >
 +
 +                <TableRow android:id="@+id/tableRow1" android:layout_width="match_parent" android:layout_height="wrap_content">
 +                    <TextView android:padding="5dp" android:id="@+id/textView1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textAppearance="?android:attr/textAppearanceMedium" android:text="Text"></TextView> </TableRow>
 +                
 +                <View android:background="@color/grey_light" android:layout_height="1px"></View>
 +                
 +                <TableRow android:id="@+id/tableRow1" android:layout_width="match_parent" android:layout_height="wrap_content"> 
 +                    <TextView android:padding="5dp" android:id="@+id/textView1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textAppearance="?android:attr/textAppearanceMedium" android:text="Text"></TextView> </TableRow>
 +    </TableLayout>
 +   
 +            <TableLayout
 +                android:layout_width="match_parent"
 +                android:layout_height="wrap_content" >
 +
 +                <TableRow android:id="@+id/tableRow1" android:layout_width="match_parent" android:layout_height="wrap_content">
 +                    <TextView android:padding="5dp" android:id="@+id/textView1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textAppearance="?android:attr/textAppearanceMedium" android:text="Text"></TextView> </TableRow>
 +                
 +                <View android:background="@color/grey_light" android:layout_height="1px"></View>
 +                
 +                <TableRow android:id="@+id/tableRow1" android:layout_width="match_parent" android:layout_height="wrap_content"> 
 +                    <TextView android:padding="5dp" android:id="@+id/textView1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textAppearance="?android:attr/textAppearanceMedium" android:text="Text"></TextView> </TableRow>
 +    </TableLayout>
 +
 +            <TableLayout
 +                android:layout_width="wrap_content"
 +                android:layout_height="wrap_content" >
 +
 +                <TableRow
 +                    android:id="@+id/tableRow2"
 +                    android:layout_width="wrap_content"
 +                    android:layout_height="wrap_content" >
 +
 +                    <LinearLayout
 +                        android:layout_width="wrap_content"
 +                        android:layout_height="wrap_content"
 +                        android:orientation="vertical" >
 +
 +                        <TextView
 +                            android:id="@+id/textView1"
 +                            android:layout_width="wrap_content"
 +                            android:layout_height="wrap_content"
 +                            android:padding="5dp"
 +                            android:text="Text"
 +                            android:textAppearance="?android:attr/textAppearanceMedium" />
 +
 +                    </LinearLayout>
 +
 +                </TableRow>
 +            </TableLayout>
 +
 +                    
 +                </TableRow>
 +       
 +        <!-- display this button in 3rd column via layout_column(zero based) -->
 +
 +        <!-- display this button in 2nd column via layout_column(zero based) -->
 +    </TableLayout>
 +
 +</LinearLayout>
 +</sxh>
 +
 +
 +
 +=== GridLayout ===
 +  * Has row-span which tableLayout does not have
 +  * **CAN NOT DISTRIBUTE HORIZONTAL SPACE** e.g. when you need multiple columns which occupy the parent \\{{http://i520.photobucket.com/albums/w327/schajtan/2014-04-05_11-31-28_zpse32d1857.png?600}}
 +
 +How to use GridLayout is described in this video:
 +{{youtube>tsOr0QhJZaE?medium}}
 +
 +=== LinearLayout ===
 +  * Can order items in a row.
 +  * Children must have either a **given size** or a **weight**
 +  * You can also set the view with some content to **wrap_content**. Then LinearLayout will **respect the size of content** for this view when distributing space via **weight**.
 +  * CAN NOT make a child take all the **remaning space**. (Use **RelativeLayout** for that!) 
 +
 +Achieving that is easy, when the width of children is given: \\
 +{{http://i520.photobucket.com/albums/w327/schajtan/2014-04-06_09-53-05_zps41dc325e.png?300}}
 +<code>
 +<?xml version="1.0" encoding="utf-8"?>
 +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 +    android:orientation="horizontal" 
 +    android:layout_width="fill_parent" 
 +    android:layout_height="fill_parent">
 +    <ImageView android:layout_width="50dip" android:layout_height="100dip" android:background="#cc0000"/>
 +    <TableLayout android:layout_width="wrap_content" android:layout_height="wrap_content">
 +        <TableRow>
 +            <ImageView android:layout_width="50dip" android:layout_height="50dip" android:background="#aaaa00"/>
 +            <ImageView android:layout_width="50dip" android:layout_height="50dip" android:background="#00aa00"/>
 +            <ImageView android:layout_width="50dip" android:layout_height="50dip" android:background="#aaaa00"/>
 +        </TableRow>
 +        <TableRow>
 +            <ImageView android:layout_width="50dip" android:layout_height="50dip" android:background="#00aa00"/>
 +            <ImageView android:layout_width="50dip" android:layout_height="50dip" android:background="#aaaa00"/>
 +            <ImageView android:layout_width="50dip" android:layout_height="50dip" android:background="#00aa00"/>
 +        </TableRow>
 +    </TableLayout>
 +    <ImageView android:layout_width="50dip" android:layout_height="100dip" android:background="#cc0000"/>
 +</LinearLayout>
 +</code>
 +
 +Trying to make the table in the middle filling the remaning space fails, because the table \\
 +{{http://i520.photobucket.com/albums/w327/schajtan/2014-04-06_09-24-52_zps57daa4b2.png?300}}
 +
 +Example about how to use weight, width, wrap_content:
 +
 +{{http://i520.photobucket.com/albums/w327/schajtan/2014-04-06_09-58-29_zps8e7b5d64.png?300}}
 +
 +{{http://i520.photobucket.com/albums/w327/schajtan/2014-04-06_09-59-40_zpsd6056e19.png?300}}
 +
 +
 +
 +
 +=== FlowLayout ===
 +
 +There is a custom FlowLayout here https://github.com/ApmeM/android-flowlayout  which allows:
 +  * Automatical **breaking the line to wrap the content**, when the space is exceeded. No default layout is able to do that.
 +
 +Maven dependency:
 +<code>
 +<dependency>
 +    <groupId>org.apmem.tools</groupId>
 +    <artifactId>app</artifactId>
 +    <version>1.0</version>
 +</dependency>
 +</code>
 +
 +{{http://i520.photobucket.com/albums/w327/schajtan/2014-04-08_10-14-18_zpsbca7faaa.png}}
 +{{http://i520.photobucket.com/albums/w327/schajtan/2014-04-08_10-14-27_zpsab68927a.png}}
 +
 +
 +==== Dialogs ====
 +The Dialogs are quite nice in Android.
 +They are customizable and may have a complete custom layout.
 +
 +
 +<code>
 +// Create custom dialog object with layout R.layout.dialog
 +
 +                final Dialog dialog = new Dialog(CustomDialog.this);
 +                // Include dialog.xml file
 +                dialog.setContentView(R.layout.dialog);
 +                // Set dialog title
 +                dialog.setTitle("Custom Dialog");
 + 
 +                // set values for custom dialog components - text, image and button
 +                TextView text = (TextView) dialog.findViewById(R.id.textDialog);
 +                text.setText("Custom dialog Android example.");
 +                ImageView image = (ImageView) dialog.findViewById(R.id.imageDialog);
 +                image.setImageResource(R.drawable.image0);
 + 
 +                dialog.show();
 +                 
 +                Button declineButton = (Button) dialog.findViewById(R.id.declineButton);
 +                // if decline button is clicked, close the custom dialog
 +                declineButton.setOnClickListener(new OnClickListener() {
 +                    @Override
 +                    public void onClick(View v) {
 +                        // Close dialog
 +                        dialog.dismiss();
 +                    }
 +                });
 +</code>
 +
 +
 +However it is difficult to style the dialog completele!
 +E.g. you can not make the DialogDivider in native DIalogs to have a custom color.
 +
 +== android-styled-dialogs ==
 +Allows to style the dialogs completele.
 +
 +|On GitHub  | https://github.com/inmite/android-styled-dialogs |
 +|On Maven |<WRAP> 
 +<code>
 +<dependency>
 +    <groupId>eu.inmite.android.lib</groupId>
 +    <artifactId>android-styled-dialogs</artifactId>
 +    <version>1.1.2</version>
 +    <type>apklib</type>
 +</dependency>
 +</code>
 +</WRAP> |
 +
 +{{https://github.com/inmite/android-styled-dialogs/raw/master/graphics/screenshot-small.png}}
 +
 +
 +== ListView AlerDialog ==
 +
 +ListView dialogs with custom Views in the list may be very useful!
 +They look native too so use them if possible!
 +
 +To achieve that do the follwing:
 +
 +== 1. Create a custom ListView Item==
 +  * It should Inherit from a ViewGroup
 +  * It should have **blockdescedants** attribute set. Otherwise you wont be able to choose it in the list
 +  * Achtung: you may not use the methods, which make the items clickable, focuasble ... Otherwise the items in the list will not be clickable. <code>
 +//cant use this for items in lists using android.content.DialogInterface.OnClickListener
 +item.setClickable(true);
 +item.setFocusable(true);
 +item.setFocusableInTouchMode(true);
 +</code>
 +
 +See this thread: http://stackoverflow.com/questions/5551042/onitemclicklistener-not-working-in-listview-android
 +
 +<code>
 +<?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:descendantFocusability="blocksDescendants"
 +    android:orientation="vertical" >
 +
 +    <RelativeLayout
 +        android:layout_width="match_parent"
 +        android:layout_height="wrap_content">
 +
 +        <LinearLayout
 +            android:id="@+id/rightCenteredContainer"
 +            android:layout_width="wrap_content"
 +            android:layout_height="wrap_content"
 +            android:layout_alignParentRight="true"
 +            android:orientation="vertical" >
 +
 +            <Button
 +                android:id="@+id/buttonChooseTrip"
 +                style="@style/Green.Button"
 +                android:layout_width="wrap_content"
 +                android:layout_height="wrap_content"
 +                android:clickable="true"
 +                android:height="@dimen/btn_trip_size"
 +                android:text=">"
 +                android:width="60dp" />
 +        </LinearLayout>
 +
 +        <TableLayout
 +            android:layout_width="wrap_content"
 +            android:layout_height="60dp"
 +            android:layout_alignParentLeft="true"
 +            android:layout_toLeftOf="@id/rightCenteredContainer"
 +            android:gravity="center_vertical"
 +            android:padding="5dp" >
 +
 +            <TableRow
 +                android:layout_width="wrap_content"
 +                android:layout_height="wrap_content">
 +
 +                <TextView
 +                    android:id="@+id/dialogTripsDestinations"
 +                    android:layout_width="wrap_content"
 +                    android:layout_height="wrap_content"
 +                    android:background="@color/transparent"
 +                    android:text="München (ZOB) - Augsburg (Zentrum)"
 +                    android:textStyle="bold" />
 +            </TableRow>
 +
 +            <TableRow
 +                android:layout_width="wrap_content"
 +                android:layout_height="wrap_content">
 +
 +                <TextView
 +                    android:id="@+id/dialogTripsTimes"
 +                    android:layout_width="wrap_content"
 +                    android:layout_height="wrap_content"
 +                    android:background="@color/transparent"
 +                    android:text="16.55 - 16.10.2014"
 +                    android:textSize="12dp" />
 +            </TableRow>
 +        </TableLayout>
 +    </RelativeLayout>
 +
 +</LinearLayout>
 +</code>
 +
 +
 +== 2. Create a View class which will wrap the XML Layout ==
 +<sxh java>
 +
 +import android.content.Context;
 +import android.util.AttributeSet;
 +import android.view.LayoutInflater;
 +import android.widget.Button;
 +import android.widget.LinearLayout;
 +import android.widget.TextView;
 +
 +public class DialogueTripItem extends LinearLayout{
 +
 + Context mContext;
 +
 + TextView dialogTripsDestinations;
 + TextView dialogTripsTimes;
 + Button buttonChooseTrip;
 +
 + public DialogueTripItem(Context context) {
 + super(context);
 + init(context);
 + }
 + public DialogueTripItem(Context context, AttributeSet attrs) {
 + super(context, attrs);
 + init(context);
 + }
 + public DialogueTripItem(Context context, AttributeSet attrs, int defStyle) {
 + super(context, attrs, defStyle);
 + init(context);
 + }
 +
 + private void init(Context context){
 + this.mContext = context;
 + LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
 + inflater.inflate(R.layout.dialog__select_current_trip_item, this, true);
 +
 + dialogTripsDestinations = (TextView) findViewById(R.id.dialogTripsDestinations);
 + dialogTripsTimes = (TextView) findViewById(R.id.dialogTripsTimes);
 + buttonChooseTrip = (Button) findViewById(R.id.buttonChooseTrip);
 + }
 +
 + public void setDestinations(String dialogTripsDestinations){
 + this.dialogTripsDestinations.setText(dialogTripsDestinations);
 + }
 + public void setDialogTripsTimes(String dialogTripsTimes){
 + this.dialogTripsTimes.setText(dialogTripsTimes);
 + }
 + public Button getButton(){
 + return buttonChooseTrip;
 + }
 +}
 +</sxh>
 +
 +== 3. Create the AlerDialog ==
 +
 +<sxh java>
 +ListAdapter adapter = new ListAdapter();
 +final DialogueTripItem item = new DialogueTripItem(activity);
 +adapter.content.add(item);
 +
 +AlertDialog.Builder builder = new IvuColorsAlertDialogBuilder(activity);
 +        builder.setAdapter(adapter, new android.content.DialogInterface.OnClickListener() {
 + @Override
 + public void onClick(DialogInterface dialog, int which) {
 + Toast.makeText(getApplicationContext(), "Click "+which, Toast.LENGTH_LONG).show();
 + }
 + });
 +        builder.setTitle("Title");
 +        builder.setIcon(activity.getResources().getDrawable(R.drawable.icon_xhdpi));
 +        builder.setNegativeButton("Cancel", cancelListener);
 +</sxh>
 +
 +
 +==== Installing an Application programmatically ====
 +An APK installation may be started programmatically.
 +The use case was to put a second (library) application into the assets folder of the main applicaiton. Install the library application on demand.
 +
 +Important:
 +  * The applicaiton may not be started from the **assets** folder. It has to be copied to the external storage
 +
 +<sxh java>
 +private void installApk() {
 + Intent intent = new Intent(Intent.ACTION_VIEW);
 +
 + // the name of the apk in the assests folder 
 + String assetFileName = "CommonBarcode115.apk";
 +
 + // location where the app will be temporary copied to
 + File cacheFolder = new File(Environment.getExternalStorageDirectory().getAbsolutePath()+"//Android//data//de.example.maintestapp");
 +
 + // the ful path to the cache file
 + File fileCache = new File(cacheFolder, assetFileName);
 +
 + // copy the file to the cache
 + try {
 + // needs android.permission.WRITE_EXTERNAL_STORAGE
 + fileCache.getParentFile().mkdirs();
 + fileCache.createNewFile();
 +
 + // delete old file
 + if (fileCache.exists()) {
 + fileCache.delete();
 + }
 +
 + copyAsset(assetFileName, cacheFolder);
 +
 + } catch (Exception e) {
 + Toast.makeText(getApplicationContext(), "Ein Fehler beim kopieren",
 + Toast.LENGTH_LONG);
 + }
 +
 + if (!fileCache.exists()) {
 + // if (!assetExists(this.getAssets(), assetFile)) {
 + Toast.makeText(getApplicationContext(), "APK not found",
 + Toast.LENGTH_LONG).show();
 + return;
 + }
 + intent.setDataAndType(Uri.fromFile(fileCache),"application/vnd.android.package-archive");
 + startActivity(intent);
 + }
 +
 + private void copyAsset(String assetFileName, File copyToFolderPath) {
 +     AssetManager assetManager = getAssets();
 +     String[] files = null;
 +     try {
 +         files = assetManager.list("");
 +     } catch (IOException e) {
 +     Toast.makeText(getApplicationContext(), "Failed to load assets",
 + Toast.LENGTH_LONG).show();
 +     }
 +     for(String filename : files) {
 +     if(!filename.equals(assetFileName)){
 +     continue;
 +     }
 +    
 +         InputStream in = null;
 +         OutputStream out = null;
 +         try {
 +           in = assetManager.open(filename);
 +           File outFile = new File(copyToFolderPath, filename);
 +           out = new FileOutputStream(outFile);
 +           copyFile(in, out);
 +           in.close();
 +           in = null;
 +           out.flush();
 +           out.close();
 +           out = null;
 +         } catch(IOException e) {
 +             Toast.makeText(getApplicationContext(), "Failed to copy asset file",
 + Toast.LENGTH_LONG).show();
 +         }       
 +     }
 + }
 +
 + private void copyFile(InputStream in, OutputStream out) throws IOException {
 + byte[] buffer = new byte[1024];
 + int read;
 + while ((read = in.read(buffer)) != -1) {
 + out.write(buffer, 0, read);
 + }
 + }
 +
 + private static boolean assetExists(AssetManager assets, String name) {
 + try {
 + // using File to extract path / filename
 + // alternatively use name.lastIndexOf("/") to extract the path
 + File f = new File(name);
 + String parent = f.getParent();
 + if (parent == null)
 + parent = "";
 + String fileName = f.getName();
 + // now use path to list all files
 + String[] assetList = assets.list(parent);
 + if (assetList != null && assetList.length > 0) {
 + for (String item : assetList) {
 + if (fileName.equals(item))
 + return true;
 + }
 + }
 + } catch (IOException e) {
 + // Log.w(TAG, e); // enable to log errors
 + }
 + return false;
 + }
 +</sxh>
 +
 +
 +==== Debugging HTTP Communication ====
 +
 +To Capture HTTP Communication of Android,
 +to simulate slow connection etc. use the following Tools:
 +
 +  * Genymotion Simulator - http://www.genymotion.com/
 +  * Fiddler - http://www.telerik.com/fiddler
 +  * Connectify as alternative to Genymotion  - http://www.connectify.me/
 +
 +
 +In your virtual device,
 +
 +  * Go to Android settings menu
 +  * In Wireless & Networks section, select Wi-Fi
 +  * Press and hold for 2 seconds WiredSSID network in the list
 +  * Choose Modify Network
 +  * Check Show advanced options
 +  * Select Manual for Proxy settings menu entry
 +  * Enter the proxy address: the Fiddler-running PC's IPAddress and Port 8888
 +  * Press the Save button 
 +
 +In Fiddler,
 +
 +  * Click Tools menu > Fiddler Options > Connections
 +  * Tick the Allow Remote Computers to connect box
 +  * Restart Fiddler.
 +
 +== As an alternative to Genymotion==
 +Use the Connectify, to connect your Phone with the Net via the PC with Fiddler. \\
 +Configure FIddler as described above.
 +
 +
 +==== Fragments ====
 +
 +== Fallpits ==
 +  * Fragments can not be nested. So use Fragments only for top level pieces when planning app's layout
 +
 +
 +Fragments can be defined in XML by using a  
 +  * a **fragment** tag
 +  * a **class** attribute
 +
 +<code>
 +              <fragment android:id="@+id/fragmentMainContent"
 +         class="com.amberfog.mapslidingtest.app.FragmentMainContent"
 +         android:layout_width="match_parent"
 +         android:layout_height="match_parent"/>
 +</code>
 +
 +The minimal fragment class looks as following
 +
 +<sxh java>
 +public class FragmentMainContent extends Fragment {
 +
 + @Override
 + public View onCreateView(LayoutInflater inflater, ViewGroup container,
 + Bundle savedInstanceState) {
 + return inflater.inflate(R.layout.fragment_maincontent_layout, container,false);
 + }
 +}
 +</sxh>
 +
 +where the **fragment_maincontent_layout** may look as whatever you like. For example:
 +<code>
 +<?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="vertical" >
 +
 +    <GridLayout
 +        android:layout_width="match_parent"
 +        android:layout_height="match_parent"
 +        android:columnCount="1" >
 +
 +        <AnalogClock
 +            android:id="@+id/analogClock1"
 +            android:layout_column="0"
 +            android:layout_gravity="center"
 +            android:layout_row="0" />
 +
 +    </GridLayout>
 +
 +</LinearLayout>
 +</code>
 +
 +
 +  * The function, which makes Android restore the Fragment without information loss //fragment.setRetainInstance(true)// makes the platform find the fragment on configuration change and re-instantiate it, when the application lifecycle is restarted on configuraiton change. \\ This means that the Application has to make sure, that the newly restored fragment is not overridden //onCreate()// <WRAP><code> 
 +
 +// ACHTUNG: when using setRetainInstance(true) on a fragment to restore it's vars on configchange - check whether the fragment already exists before recreating it
 +this.fragmentDetails = (Fragment1Details) fragmentManager.findFragmentByTag("fragmentTag");
 +if(this.fragmentDetails==null) {
 +  // create the fragment here and tag it with "fragmentTag"
 +}
 +</code></WRAP>
 +  * The function //fragment.setRetainInstance(true)// only works, if the fragment is not added to the back stack
 +
 +^Class^Usage^Details^
 +|FragmentManager|<code>Activity.getFragmentManager()</code>|Used to control the Fragments|
 +|FragmentTransaction|<code>getFragmentManager().beginTransaction()</code>| Is able to create, update, remove fragments |
 +
 +Fragments may be either created in xml or programmatically.
 +
 +In XML
 +<code>
 +    <fragment
 +        android:id="@+id/fragmentId"
 +        android:layout_width="wrap_content"
 +        android:layout_height="wrap_content">
 +    </fragment>
 +</code>
 +
 +Programmatically. Programmatically fragment operations are done via **FragmentManager** which create **FragmentTranscation** \\
 +**ACHTUNG:** The fragment must live inside a ViewGroup **R.id.fragmentContainer** ist such a ViewGroup here
 +<code>
 +// get Fragment manager
 +FragmentManager fragmentManager = getFragmentManager();
 +
 +// ACHTUNG: when using setRetainInstance(true) on a fragment to restore it's vars on configchange - check whether the fragment already exists before recreating it
 +this.fragmentDetails = (Fragment1Details) fragmentManager.findFragmentByTag("fragmentDetails");
 +
 +if(this.fragmentDetails==null) {
 +    // start a transaction
 +    FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
 +    // create a fragment
 +    this.fragmentDetails = new Fragment1Details();
 +    // set the id to the fragment
 +    // The Fragment should not be recreated when the Application is killed
 +    this.fragmentDetails.setRetainInstance(true);
 +    // add the fragment to the view
 +    fragmentTransaction.add(R.id.fragmentContainer, this.fragmentDetails, "fragmentDetails");
 +//        //make transaction reversable by undoing the action on the fragmentmanager
 +//        fragmentTransaction.addToBackStack(null);
 +    // commit the transaction
 +    fragmentTransaction.commit();
 +
 +    // init the value from model of fragmentDetails.
 +    myActivityModel.setText(myActivityModel.getText());
 +}else{
 +    Log.d(TAG,"Fragment already exists. Do not recreate it!");
 +}
 +</code>
 +
 +
 +
 +==== ScrolView ====
 +To scroll the View continous prgrammatic scrolling.
 +To scroll continously the view has to be scrolled by a little delta in a regular time period. \\
 +The period of time should be nearly 24 Frames per second, which is **every 41 ms**. \\
 +The distance-change in px per ms depend from the speed you wish to achieve.
 +
 +|0.1 - 0.2 PX per MS| Slow movement|
 +|0.4 - 0.7 PX per MS| Middle speed|
 +|1 PX - 1.4 PX per MS| Fast speed|
 +
 +|12PFS| Seems to be not enough eince you can see the picture jerking  | {{http://i520.photobucket.com/albums/w327/schajtan/12fps_zpstu39zc1b.gif?400}} |
 +|24PFS| Seems to be ok | {{http://i520.photobucket.com/albums/w327/schajtan/24fps_zpszjodthm9.gif?400}} |
 +|36PFS| No difference to 24FPS | {{http://i520.photobucket.com/albums/w327/schajtan/36fps_zpsokht1ouu.gif?400}} |
 +
 +
 +COde to test differend scroll speeds
 +
 +<sxh java>
 +
 +        return new Thread(new Runnable() {
 +            @Override
 +            public void run() {
 +
 +                    // scroll time
 +                    int scrollTimeMs = 4000;
 +
 +                    // SPEED IN PX / MS, IF THE IMAGE WULD MOVE CONTIONOUSLY
 +                    double pxPerMsStart = 0.2;
 +                    double pxPerEnd = 0.8;
 +                    double pxPerMsChangeBy =  0.1;
 +
 +                    // FPS
 +                    int fpsStart = 24; //per sec
 +                    int fpsEnd = 24;
 +                    int fpsChangeBy = 12;
 +
 +
 +                    // iterate pause time
 +                    for(double scrollspeedPxPerMs = pxPerMsStart; scrollspeedPxPerMs <=pxPerEnd; scrollspeedPxPerMs +=pxPerMsChangeBy){
 +
 +                        // iterate steps
 +                        for(int fps=fpsStart; fps<= fpsEnd; fps+=fpsChangeBy){
 +
 +                            // pauses in ms are computed from fps
 +                            pauseMs    = 1000/fps;
 +
 +                            /*  the speed is given for the case, when the image moves contingously
 +                                because there is a redraw pause between movements - we have to multiply the pause in MS with the speed
 +                                to know to which amount the image has to be moved after every pause
 +                            */
 +                            steppx = (int) Math.round((double)pauseMs * scrollspeedPxPerMs);
 +
 +
 +                            // timestemp for next iteration
 +                            timestampWhenToStop = System.currentTimeMillis() + scrollTimeMs;
 +
 +                            // annouce settings
 +                            final String message = String.format("Step by %s px, every %s ms  - FPS: %s Scroll by %s px per MS", steppx, pauseMs, fps, scrollspeedPxPerMs );
 +                            Log.d("stepscroll", message);
 +
 +                            // jump to the top
 +                            ViewGroupAnimatedActivity6.this.runOnUiThread(new Runnable() {
 +                                public void run() {
 +                                    Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show();
 +                                    scrollView.setSmoothScrollingEnabled(false);
 +                                    scrollView.scrollTo(0, 0);
 +                                    scrollView.setSmoothScrollingEnabled(true);
 +                                }
 +                            });
 +
 +                            // scroll to the bottom
 +                            boolean stopIteration = false;
 +                            while (!stopIteration){
 +
 +                                ViewGroupAnimatedActivity6.this.runOnUiThread(new Runnable() {
 +                                    public void run() {
 +                                        scrollView.smoothScrollBy(0, steppx);
 +                                    }
 +                                });
 +
 +                                if(timestampWhenToStop < System.currentTimeMillis()){
 +                                    stopIteration = true;
 +                                    continue;
 +                                }
 +                                try {
 +                                    Thread.sleep(pauseMs);
 +                                } catch (InterruptedException e) {
 +                                    e.printStackTrace();
 +                                }
 +
 +                                if(!isRunning){
 +                                    return;
 +                                }
 +                            }
 +
 +                        }// for fps
 +                    } // for pxPerEnd
 +
 +            isRunning = false;
 +            }
 +        });
 +    }
 +</sxh>
 +
 +
 +
 +
 +==== Gradle ====
 +
 +To execute gradle tasks - a gradle wrapper file is used.
 +The wrapper is a shell / batch script, which downloads the gradle and so does not require gradle to be installed previously.
 +The wrapper uses it's own gradle version
 +The name of the file is **gradlew.bat**
 +
 +To generate the gradle wrapper use gradle and add the wrapper :
 +<code>
 +gradle wrapper
 +</code>
 +
 +
 +==== AIDL====
 +**aidl**
 +
 +- all aidl have to be located in th same packages
 +- can pass Parcels or primitives
 +- implement aidl to be able to retrieve a common interface to communicate between different applicaitons, which are different processes
 +<code>
 + public void onServiceConnected(ComponentName name, IBinder service) {
 + IServiceReadTicketBinder serviceReadTicketBinder = IServiceReadTicketBinder.Stub.asInterface(service);
 + // IServiceReadTicketBinder serviceReadTicketBinder = (IServiceReadTicketBinder)service; // not allowed when retriveing service from another application. service var is of type proxy
 +</code>
 +
 +- add in out inout as stated here http://www.app-solut.com/blog/2011/05/using-self-defined-parcelable-objects-during-an-android-aidl-rpc-ipc-call/
 +- use Bundle.class to exchange data with the Service. It provides possibility to restore the stored values typesafe. Bundle is like a Hashmap which can store different types of values result.getString("Test")
 +
 +
 +==== Bindings ====
 +
 +The bare minimum in code
 +<sxh java>
 +    @Override
 +    public View onCreateView(LayoutInflater inflater, ViewGroup container,
 +                             Bundle savedInstanceState) {
 +
 +        final ViewDataBinding binding = DataBindingUtil.inflate(
 +                inflater, R.layout.fragment_poidialog, container, false);
 +        final View view = binding.getRoot();
 +        return view;
 +    }
 +</sxh>
 +
 +The binding in xml
 +
 +https://stackoverflow.com/questions/35287302/android-data-binding-how-to-pass-variable-to-include-layout
 +<code>
 +<?xml version="1.0" encoding="utf-8"?>
 +<layout
 +    xmlns:android="http://schemas.android.com/apk/res/android"
 +    xmlns:app="http://schemas.android.com/apk/res-auto">
 +
 +    <LinearLayout
 +        android:layout_width="match_parent"
 +        android:layout_height="match_parent"
 +        >
 +
 +        <include
 +            layout="@layout/layout_common"
 +            app:passedText="@{@string/app_name}" // here we pass any String 
 +            />
 +
 +    </LinearLayout>
 +</layout>
 +
 +
 +
 +
 +
 +<?xml version="1.0" encoding="utf-8"?>
 +<layout
 +    xmlns:android="http://schemas.android.com/apk/res/android"
 +    >
 +
 +    <data>
 +        // declare fields
 +        <variable
 +            name="passedText"
 +            type="String"/>
 +    </data>
 +
 +    <TextView
 +        android:layout_width="wrap_content"
 +        android:layout_height="wrap_content"
 +        android:text="@{passedText}"/> //set field to your view.
 +
 +</layout>
 +
 +</code>
 +
 +
 +
 +==== Style ====
 +
 +=== Styles, attributes ===
 +
 +{{https://s3.eu-central-1.amazonaws.com/alf-digital-wiki-pics/sharex/0A2xTQpLXn.png}}
 +
 +
 +=== TextAppearance ===
 +The text size in android is controlled by "TextAppearance"
 +
 +
 +Material Design provides 13 type “styles” that are applied to all the text in your app. Each of these have a design term (eg. “Body 1”) along with a corresponding type attribute that can be overridden in your app theme (eg. textAppearanceBody1). There are default “baseline” values (text size, letter spacing, capitalization, etc.) for each style.
 +
 +https://material.io/blog/android-material-theme-type
 +
 +{{https://s3.eu-central-1.amazonaws.com/alf-digital-wiki-pics/sharex/9SsVsrtpPT.png}}
 +
 +
 +== Usage in your view ==
 +
 +At the end, 
 +to express which size the text in your custom view should have 
 +instead of influencing "textSize" directly
 +which will lead to difficulties with consistancy across app and consistancy with android native textSizes
 +
 +you should set "android:textAppearance=" on your view.
 +
 +and the value should be one of androids own textAppearance **attributes**: 
 +  * textAppearanceHeadline1
 +  * textAppearanceHeadline2
 +  * textAppearanceHeadline3
 +  * textAppearanceHeadline4
 +  * textAppearanceBody1
 +  * textAppearanceBody2
 +
 +The same attributes are used by android too, so your view will be consistant with android natives
 +
 +In your someAppPartLayout.xml
 +<code>
 +                <!-- My title in my app view -->
 +                <TextView
 +                    android:layout_width="wrap_content"
 +                    android:layout_height="wrap_content"
 +                    android:text="Title"
 +                    android:textAppearance="?attr/textAppearanceHeadline4" />
 +</code>
 +
 +
 +== Changing the value of attributes in AppTheme ==
 +
 +In your theme, maybe defined in your styles.xml
 +you can change single android attributes.
 +
 +In my theme, which is defined in this style - overriding the single attributes "textAppearance*"
 +referencing MY styles, which can interfere and override the default values for textAppearance.
 +
 +**Remark:** 
 +Those textAppearance* attributes are also used in android native views,
 +like buttons
 +see https://material.io/blog/android-material-theme-type.
 +So overriding those in a theme - changes the behavior also for Android native elements
 +
 +THose attributes are not just strings, but are introduced as typed attributes in attrs.xml
 +with format="reference".
 +format="reference" means, that one can take a "<style></style>" element as a value.
 +In the value-style element - the items a la  android:textSize are expected (convention).
 +
 +USAGE of attributes
 +The attribute can be USED in views, by refering to the attribute in the view
 +e.g.
 +<code>android:textAppearance="?attr/textAppearanceHeadline4" /> </code>
 +
 +In your styles.xml pointing textAppearanceHeadline1 attribute of type "reference"
 +to my own style.
 +
 +The style inherits from androids own style but I still can override some values in my inherited style.
 +
 +<code>
 +    <!-- Base application theme. -->
 +    <style name="AppTheme" parent="Theme.MaterialComponents.Light.DarkActionBar">
 +        <!-- Customize your theme here. -->
 +        <item name="colorPrimary">@color/colorPrimary</item>
 +        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
 +        <item name="colorAccent">@color/colorAccent</item>
 +
 +       
 +        <item name="textAppearanceHeadline1">
 +            @style/TextAppearance.Headline1
 +        </item>
 +</code>
 +
 +
 +== Introducing own styles, to refer from overridden attributes textAppearance* ==
 +
 +THe value of an overridden attribute **textAppearance*** is a style
 +
 +
 +in your styles.xml 
 +parallel to the AppTheme - introduce styles, to refer from attributes.
 +<code>
 +
 +    <!-- here I can change attributes of the STYLES.
 +    by Inheriting from "TextAppearance.MaterialComponents.*" I inherit all the native properties
 +    but get the possibility to override them here
 +    -->
 +    <style name="TextAppearance.Headline1" parent="TextAppearance.MaterialComponents.Headline1">
 +        <item name="android:textSize">96sp</item>
 +    </style>
 +
 +    <style name="TextAppearance.Headline2" parent="TextAppearance.MaterialComponents.Headline2">
 +        <item name="android:textSize">60sp</item>
 +    </style>
 +
 +    <style name="TextAppearance.Headline3" parent="TextAppearance.MaterialComponents.Headline3">
 +        <item name="android:textSize">48sp</item>
 +    </style>
 +
 +    <style name="TextAppearance.Headline4" parent="TextAppearance.MaterialComponents.Headline4">
 +        <item name="android:textSize">34sp</item>
 +    </style>
 +
 +    <style name="TextAppearance.Headline5" parent="TextAppearance.MaterialComponents.Headline5">
 +        <item name="android:textSize">24sp</item>
 +    </style>
 +
 +    <style name="TextAppearance.Headline6" parent="TextAppearance.MaterialComponents.Headline6">
 +        <item name="android:textSize">20sp</item>
 +    </style>
 +
 +    <style name="TextAppearance.Body1" parent="TextAppearance.MaterialComponents.Body1">
 +        <item name="android:textSize">16sp</item>
 +    </style>
 +
 +    <style name="TextAppearance.Body2" parent="TextAppearance.MaterialComponents.Body2">
 +        <item name="android:textSize">14sp</item>
 +    </style>
 +</code>