SlideShare a Scribd company logo
Hacking the Source - Part IV
Now that we have the general drift lets move on to Android. In one aspect Android is easier than iOS as it's based on Java. However, other aspects make it a bit painful
and in most regards harder to work with than iOS.
Android Studio
© Codename One 2017 all rights reserved
We will use Android Studio 3.x to build the project since this is pretty much what Google demands.

The first step in building on Android is mostly about running through the IDE steps. The first step is the new project option
Package Name
© Codename One 2017 all rights reserved
When setting the project details the most important bit is the package name. It should match our main package name!
Target Devices
© Codename One 2017 all rights reserved
I left the default settings for the target platform unchanged, this should work fine
Activity
© Codename One 2017 all rights reserved
I chose the blank activity, I'll create one manually later. We are now presented with a progress indicator and then after a while Android Studio finally loads. Notice that you
might need to resolve issues in the IDE if it connects to older versions of the Android SDK installed in your system.
Java 8
© Codename One 2017 all rights reserved
The first thing we need to do once the IDE has finished loading is configure Java 8 support.

The Codename One build servers translate the built bytecodes so they will work without Java 8 support on Android. We need to do that since we have no access to the
source code in the servers and we want to remain compatible.

However, Java 8 is now supported in Android Studio and this will allow your code to compile unchanged. Notice that the core Codename One code is still Java 5
compatible. 

To do this we need to first pick the project structure option from the menu. We then need to set the source & target compatibility to Java 8
apply plugin: 'com.android.application'
android {
compileSdkVersion 26
defaultConfig {
applicationId "com.codename1.demos.kitchen"
minSdkVersion 15
targetSdkVersion 26
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
sourceSets {
main.java.srcDirs += 'src/main'
main.java.srcDirs += '../../KitchenSink/src'
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
build.gradle
The next step is to edit the build.gradle file and add support for our sources.

Notice that there are two build.gradle files in the project, you only need to edit the one for the Android project itself which in my case was marked as (Module: app).

After you make changes to system files Android Studio offers to sync the project again which you should accept.

This is the full code but you should probably only take the lines I highlight in the modifications. Lets scroll down to look at the changes
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
sourceSets {
main.java.srcDirs += 'src/main'
main.java.srcDirs += '../../KitchenSink/src'
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'com.android.support:appcompat-v7:26.1.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.1'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
compile 'com.google.android.gms:play-services-identity:8.3.0'
compile 'com.google.android.gms:play-services-plus:8.3.0'
compile 'com.google.android.gms:play-services-location:8.3.0'
compile 'com.google.android.gms:play-services-auth:8.3.0'
compile 'com.facebook.android:facebook-android-sdk:4.7.0'
}
build.gradle
I added a source set section that points at the sources of the kitchen sink project, that way they appear in the hierarchy but we don't need to copy them
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
sourceSets {
main.java.srcDirs += 'src/main'
main.java.srcDirs += '../../KitchenSink/src'
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'com.android.support:appcompat-v7:26.1.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.1'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
compile 'com.google.android.gms:play-services-identity:8.3.0'
compile 'com.google.android.gms:play-services-plus:8.3.0'
compile 'com.google.android.gms:play-services-location:8.3.0'
compile 'com.google.android.gms:play-services-auth:8.3.0'
compile 'com.facebook.android:facebook-android-sdk:4.7.0'
}
build.gradle
I added all of these dependencies to the build.

Notice that we don't actually need all of the dependencies. The build servers delete code that you don't need based on build hints. So if Facebook support isn't
necessary it will delete the FacebookImpl class and won't place the facebook dependency. The same is true for the other dependencies mentioned.
android.enableAapt2=false
gradle.properties
We also need to make a minor change to the `gradle.properties` file by adding this line. This is required for some of the style code later on.
cp -Rf ../cn1/CodenameOne/src/* ../
KitchenSinkAndroid/app/src/main/java/
cp -Rf ../cn1/Ports/Android/src/* ../
KitchenSinkAndroid/app/src/main/java/
rm ../KitchenSinkAndroid/app/src/main/java/*
Copy Sources
The next step is copying the Android implementation sources into the project. Since the Android implementation sources don't include the Codename One sources we
need to start with that.

These commands are executed from the KitchenSink directory so they are relative to that path. 

Notice we copy the Codename One code first and the Android code second so files get overwritten. Also notice we delete all the files in the root of the project source
(not recursively). The root of the Codename One and Android projects include resource files that should be placed in a different location.

Android expects all resources that aren't in the res file to be within an assets directory. We need to create that directory in the hierarchy where the res directory resides.
mkdir ../KitchenSinkAndroid/app/src/main/assets
cp ../cn1/CodenameOne/src/* ../KitchenSinkAndroid/
app/src/main/assets/
cp ../cn1/Ports/Android/src/* ../
KitchenSinkAndroid/app/src/main/assets/
cp src/* ../KitchenSinkAndroid/app/src/main/assets
Copy Assets
This copies the files from the roots of all of these projects. Notice the order of commands sets the priority since a project on the way can override the parent project.

Following these instructions you might be thinking “Why Copy?”.

We included the source of the Kitchen Sink, why not do the same for the implementation?

The main problem is overriden files. Codename One redefines the CodenameOneThread class in the Android implementation and relies on that redefinition taking the
priority. We might do more of that in the future.

This is also important because you might want to delete some files such as Facebook support. So copy makes more sense in this special case.
package com.codename1.demos.kitchen;
import com.codename1.impl.android.AndroidImplementation;
import com.codename1.impl.android.CodenameOneActivity;
import com.codename1.ui.Dialog;
import com.codename1.ui.Display;
import com.codename1.ui.Form;
public class KitchenSinkStub extends CodenameOneActivity implements Runnable {
private static KitchenSink i;
private static boolean firstTime = true;
private Form currentForm;
private static final Object LOCK = new Object();
protected void onResume() {
super.onResume();
AndroidImplementation.startContext(this);
if (i == null) {
i = new KitchenSink();
}
Display.getInstance().callSerially(this);
}
public void run() {
if (firstTime) {
firstTime = false;
i.init(this);
KitchenSinkStub
The next step is the activity class which is Androids lifecycle object. This is a pretty standard class in Android so I'll add the code & step over it like before.

We have a CodenameOneActivity base class which is important for the main activity as we handle some nuanced events there
package com.codename1.demos.kitchen;
import com.codename1.impl.android.AndroidImplementation;
import com.codename1.impl.android.CodenameOneActivity;
import com.codename1.ui.Dialog;
import com.codename1.ui.Display;
import com.codename1.ui.Form;
public class KitchenSinkStub extends CodenameOneActivity implements Runnable {
private static KitchenSink i;
private static boolean firstTime = true;
private Form currentForm;
private static final Object LOCK = new Object();
protected void onResume() {
super.onResume();
AndroidImplementation.startContext(this);
if (i == null) {
i = new KitchenSink();
}
Display.getInstance().callSerially(this);
}
public void run() {
if (firstTime) {
firstTime = false;
i.init(this);
KitchenSinkStub
Most Android apps use onCreate to detect app launch. We use onResume which is more consistent for our needs in terms of suspend/resume behavior
package com.codename1.demos.kitchen;
import com.codename1.impl.android.AndroidImplementation;
import com.codename1.impl.android.CodenameOneActivity;
import com.codename1.ui.Dialog;
import com.codename1.ui.Display;
import com.codename1.ui.Form;
public class KitchenSinkStub extends CodenameOneActivity implements Runnable {
private static KitchenSink i;
private static boolean firstTime = true;
private Form currentForm;
private static final Object LOCK = new Object();
protected void onResume() {
super.onResume();
AndroidImplementation.startContext(this);
if (i == null) {
i = new KitchenSink();
}
Display.getInstance().callSerially(this);
}
public void run() {
if (firstTime) {
firstTime = false;
i.init(this);
KitchenSinkStub
These lines effectively initialize Codename One and start the EDT if it isn't running. We also allocate the KitchenSink main class if it isn't allocated yet
package com.codename1.demos.kitchen;
import com.codename1.impl.android.AndroidImplementation;
import com.codename1.impl.android.CodenameOneActivity;
import com.codename1.ui.Dialog;
import com.codename1.ui.Display;
import com.codename1.ui.Form;
public class KitchenSinkStub extends CodenameOneActivity implements Runnable {
private static KitchenSink i;
private static boolean firstTime = true;
private Form currentForm;
private static final Object LOCK = new Object();
protected void onResume() {
super.onResume();
AndroidImplementation.startContext(this);
if (i == null) {
i = new KitchenSink();
}
Display.getInstance().callSerially(this);
}
public void run() {
if (firstTime) {
firstTime = false;
i.init(this);
KitchenSinkStub
I did the allocation on the Android thread which isn't ideal but the callback should be invoked on the Codename One thread which is why we have this callSerially here
public void run() {
if (firstTime) {
firstTime = false;
i.init(this);
} else {
synchronized (LOCK) {
if (currentForm != null) {
if (currentForm instanceof Dialog) {
((Dialog) currentForm).showModeless();
} else {
currentForm.show();
}
fireIntentResult();
currentForm = null;
setWaitingForResult(false);
return;
}
}
}
i.start();
}
protected void onPause() {
super.onPause();
KitchenSinkStub
Now on the EDT if this is the first time we need to invoke the `init(Object)` method of the main class
public void run() {
if (firstTime) {
firstTime = false;
i.init(this);
} else {
synchronized (LOCK) {
if (currentForm != null) {
if (currentForm instanceof Dialog) {
((Dialog) currentForm).showModeless();
} else {
currentForm.show();
}
fireIntentResult();
currentForm = null;
setWaitingForResult(false);
return;
}
}
}
i.start();
}
protected void onPause() {
super.onPause();
KitchenSinkStub
Otherwise if we are resuming we try to be "smart" about the current Form since Android has a tendency to restart activities for everything
public void run() {
if (firstTime) {
firstTime = false;
i.init(this);
} else {
synchronized (LOCK) {
if (currentForm != null) {
if (currentForm instanceof Dialog) {
((Dialog) currentForm).showModeless();
} else {
currentForm.show();
}
fireIntentResult();
currentForm = null;
setWaitingForResult(false);
return;
}
}
}
i.start();
}
protected void onPause() {
super.onPause();
KitchenSinkStub
start() is invoked with every call to resume to match the lifecycle behavior of Codename One. The same holds true to stop and destroy both of which are pretty trivial
i.start();
}
protected void onPause() {
super.onPause();
synchronized (LOCK) {
currentForm = Display.getInstance().getCurrent();
}
}
protected void onStop() {
super.onStop();
if (isWaitingForResult()) {
return;
}
synchronized (LOCK) {
currentForm = null;
}
Display.getInstance().callSerially(() -> i.stop());
}
protected void onDestroy() {
super.onDestroy();
Display.getInstance().callSerially(() -> {
i.destroy();
Display.deinitialize();
});
}
}
KitchenSinkStub
The rest of the code is just boilerplate and uninteresting. We invoke stop in onStop and invoke destroy in onDestroy()
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.codename1.demos.kitchen">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/CustomTheme" >
<activity android:name=".KitchenSinkStub"
android:configChanges="orientation|keyboardHidden|screenSize"
android:launchMode="singleTop">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Manifest
Now that all of that is out of the way we just need to configure the XML files. First we have the manifest file which represents all the activities in the application. The
manifest isn't really important here. I just used the default manifest generated by the IDE and updated the activity entry. Notice that most of the entries within the activity
are essential for the app.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#ff000000">
</RelativeLayout>
main.xml
We also need a layout for the main application so under the res/layout directory we need to add the file main.xml. That's a pretty simple layout just to give room for
Codename One itself.
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="CustomTheme" parent="android:Theme.Black">
<item name="attr/cn1Style">@style/CN1.EditText.Style</item>
</style>
<attr name="cn1Style" format="reference" />
<style name="CN1.EditText.Style"
parent="@android:style/Widget.EditText">
<item name="android:textCursorDrawable">@null</item>
</style>
</resources>
styles.xml
We need 3 style files to support all this, the first is styles.xml which resides in the directory src/main/res/values. Which just includes a theme and not much else.
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="CustomTheme"
parent="@android:style/Theme.Holo.Light">
<item name="attr/cn1Style">@style/CN1.EditText.Style</item>
<item name="android:windowActionBar">false</item>
<item name="android:windowTitleSize">0dp</item>
</style>
<style name="CN1.EditText.Style"
parent="@android:style/Widget.EditText">
<item name="android:textCursorDrawable">@null</item>
</style>
</resources>
styles.xml (v11)
The second bares the same name but resides in the directory src/main/res/values-v11. Again this is pretty trivial and hardcoded for all the apps
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="CustomTheme"
parent="@android:style/Theme.Material.Light">
<item name="attr/cn1Style">@style/CN1.EditText.Style</item>
<item name="android:windowActionBar">false</item>
<item name="android:windowTitleSize">0dp</item>
<item name="android:colorPrimary">@color/colorPrimary</item>
<item name="android:colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="android:colorAccent">@color/colorAccent</item>
</style>
<style name="CN1.EditText.Style"
parent="@android:style/Widget.EditText">
<item name="android:textCursorDrawable">@null</item>
</style>
</resources>
styles.xml (v21)
The final one also has the same name but resides in the directory src/main/res/values-v21. It includes some additional settings for newer versions of Android. 

Now that all this is done you can just press play in the IDE and run on an Android device! There was a bit of boilerplate but I hope it’s clear

More Related Content

Similar to Hacking the Codename One Source Code - Part IV - Transcript.pdf

React Native: Is It Worth It? UA Mobile 2017.
React Native: Is It Worth It? UA Mobile 2017.React Native: Is It Worth It? UA Mobile 2017.
React Native: Is It Worth It? UA Mobile 2017.
UA Mobile
 
React Native
React NativeReact Native
React Native
Craig Jolicoeur
 
Android OS & SDK - Getting Started
Android OS & SDK - Getting StartedAndroid OS & SDK - Getting Started
Android OS & SDK - Getting Started
Hemant Chhapoliya
 
Android Lab
Android LabAndroid Lab
Android Lab
Leo Nguyen
 
Level Up Your Android Build -Droidcon Berlin 2015
Level Up Your Android Build -Droidcon Berlin 2015Level Up Your Android Build -Droidcon Berlin 2015
Level Up Your Android Build -Droidcon Berlin 2015
Friedger Müffke
 
Bird.pdf
 Bird.pdf Bird.pdf
Bird.pdf
RebaMaheen
 
Getting started with building your own standalone Gradle plugin
Getting started with building your own standalone Gradle pluginGetting started with building your own standalone Gradle plugin
Getting started with building your own standalone Gradle plugin
tobiaspreuss
 
Android application development
Android application developmentAndroid application development
Android application developmentslidesuren
 
Getting started with appium
Getting started with appiumGetting started with appium
Getting started with appium
Pratik Patel
 
Final NEWS.pdf
Final NEWS.pdfFinal NEWS.pdf
Final NEWS.pdf
RebaMaheen
 
Final NewsApp.pdf
Final NewsApp.pdfFinal NewsApp.pdf
Final NewsApp.pdf
RebaMaheen
 
Android
AndroidAndroid
Android
BVP GTUG
 
androidstudio.pptx
androidstudio.pptxandroidstudio.pptx
androidstudio.pptx
SundaresanB5
 
Android Development project
Android Development projectAndroid Development project
Android Development projectMinhaj Kazi
 
Building a Native Camera Access Library - Part II - Transcript.pdf
Building a Native Camera Access Library - Part II - Transcript.pdfBuilding a Native Camera Access Library - Part II - Transcript.pdf
Building a Native Camera Access Library - Part II - Transcript.pdf
ShaiAlmog1
 
Android activity, service, and broadcast recievers
Android activity, service, and broadcast recieversAndroid activity, service, and broadcast recievers
Android activity, service, and broadcast recievers
Jagdish Gediya
 
Android programming-basics
Android programming-basicsAndroid programming-basics
Android programming-basics
Aravindharamanan S
 
[Devoxx Morocco 2015] Apache Cordova In Action
[Devoxx Morocco 2015] Apache Cordova In Action[Devoxx Morocco 2015] Apache Cordova In Action
[Devoxx Morocco 2015] Apache Cordova In Action
Hazem Saleh
 
Hello, Android Studio 3.2 & Android App Bundle @ I/O Extended Bangkok 2018
Hello, Android Studio 3.2 & Android App Bundle @ I/O Extended Bangkok 2018Hello, Android Studio 3.2 & Android App Bundle @ I/O Extended Bangkok 2018
Hello, Android Studio 3.2 & Android App Bundle @ I/O Extended Bangkok 2018
Somkiat Khitwongwattana
 

Similar to Hacking the Codename One Source Code - Part IV - Transcript.pdf (20)

React Native: Is It Worth It? UA Mobile 2017.
React Native: Is It Worth It? UA Mobile 2017.React Native: Is It Worth It? UA Mobile 2017.
React Native: Is It Worth It? UA Mobile 2017.
 
React Native
React NativeReact Native
React Native
 
Android OS & SDK - Getting Started
Android OS & SDK - Getting StartedAndroid OS & SDK - Getting Started
Android OS & SDK - Getting Started
 
Android Lab
Android LabAndroid Lab
Android Lab
 
Android
Android Android
Android
 
Level Up Your Android Build -Droidcon Berlin 2015
Level Up Your Android Build -Droidcon Berlin 2015Level Up Your Android Build -Droidcon Berlin 2015
Level Up Your Android Build -Droidcon Berlin 2015
 
Bird.pdf
 Bird.pdf Bird.pdf
Bird.pdf
 
Getting started with building your own standalone Gradle plugin
Getting started with building your own standalone Gradle pluginGetting started with building your own standalone Gradle plugin
Getting started with building your own standalone Gradle plugin
 
Android application development
Android application developmentAndroid application development
Android application development
 
Getting started with appium
Getting started with appiumGetting started with appium
Getting started with appium
 
Final NEWS.pdf
Final NEWS.pdfFinal NEWS.pdf
Final NEWS.pdf
 
Final NewsApp.pdf
Final NewsApp.pdfFinal NewsApp.pdf
Final NewsApp.pdf
 
Android
AndroidAndroid
Android
 
androidstudio.pptx
androidstudio.pptxandroidstudio.pptx
androidstudio.pptx
 
Android Development project
Android Development projectAndroid Development project
Android Development project
 
Building a Native Camera Access Library - Part II - Transcript.pdf
Building a Native Camera Access Library - Part II - Transcript.pdfBuilding a Native Camera Access Library - Part II - Transcript.pdf
Building a Native Camera Access Library - Part II - Transcript.pdf
 
Android activity, service, and broadcast recievers
Android activity, service, and broadcast recieversAndroid activity, service, and broadcast recievers
Android activity, service, and broadcast recievers
 
Android programming-basics
Android programming-basicsAndroid programming-basics
Android programming-basics
 
[Devoxx Morocco 2015] Apache Cordova In Action
[Devoxx Morocco 2015] Apache Cordova In Action[Devoxx Morocco 2015] Apache Cordova In Action
[Devoxx Morocco 2015] Apache Cordova In Action
 
Hello, Android Studio 3.2 & Android App Bundle @ I/O Extended Bangkok 2018
Hello, Android Studio 3.2 & Android App Bundle @ I/O Extended Bangkok 2018Hello, Android Studio 3.2 & Android App Bundle @ I/O Extended Bangkok 2018
Hello, Android Studio 3.2 & Android App Bundle @ I/O Extended Bangkok 2018
 

More from ShaiAlmog1

The Duck Teaches Learn to debug from the masters. Local to production- kill ...
The Duck Teaches  Learn to debug from the masters. Local to production- kill ...The Duck Teaches  Learn to debug from the masters. Local to production- kill ...
The Duck Teaches Learn to debug from the masters. Local to production- kill ...
ShaiAlmog1
 
create-netflix-clone-06-client-ui.pdf
create-netflix-clone-06-client-ui.pdfcreate-netflix-clone-06-client-ui.pdf
create-netflix-clone-06-client-ui.pdf
ShaiAlmog1
 
create-netflix-clone-01-introduction_transcript.pdf
create-netflix-clone-01-introduction_transcript.pdfcreate-netflix-clone-01-introduction_transcript.pdf
create-netflix-clone-01-introduction_transcript.pdf
ShaiAlmog1
 
create-netflix-clone-02-server_transcript.pdf
create-netflix-clone-02-server_transcript.pdfcreate-netflix-clone-02-server_transcript.pdf
create-netflix-clone-02-server_transcript.pdf
ShaiAlmog1
 
create-netflix-clone-04-server-continued_transcript.pdf
create-netflix-clone-04-server-continued_transcript.pdfcreate-netflix-clone-04-server-continued_transcript.pdf
create-netflix-clone-04-server-continued_transcript.pdf
ShaiAlmog1
 
create-netflix-clone-01-introduction.pdf
create-netflix-clone-01-introduction.pdfcreate-netflix-clone-01-introduction.pdf
create-netflix-clone-01-introduction.pdf
ShaiAlmog1
 
create-netflix-clone-06-client-ui_transcript.pdf
create-netflix-clone-06-client-ui_transcript.pdfcreate-netflix-clone-06-client-ui_transcript.pdf
create-netflix-clone-06-client-ui_transcript.pdf
ShaiAlmog1
 
create-netflix-clone-03-server.pdf
create-netflix-clone-03-server.pdfcreate-netflix-clone-03-server.pdf
create-netflix-clone-03-server.pdf
ShaiAlmog1
 
create-netflix-clone-04-server-continued.pdf
create-netflix-clone-04-server-continued.pdfcreate-netflix-clone-04-server-continued.pdf
create-netflix-clone-04-server-continued.pdf
ShaiAlmog1
 
create-netflix-clone-05-client-model_transcript.pdf
create-netflix-clone-05-client-model_transcript.pdfcreate-netflix-clone-05-client-model_transcript.pdf
create-netflix-clone-05-client-model_transcript.pdf
ShaiAlmog1
 
create-netflix-clone-03-server_transcript.pdf
create-netflix-clone-03-server_transcript.pdfcreate-netflix-clone-03-server_transcript.pdf
create-netflix-clone-03-server_transcript.pdf
ShaiAlmog1
 
create-netflix-clone-02-server.pdf
create-netflix-clone-02-server.pdfcreate-netflix-clone-02-server.pdf
create-netflix-clone-02-server.pdf
ShaiAlmog1
 
create-netflix-clone-05-client-model.pdf
create-netflix-clone-05-client-model.pdfcreate-netflix-clone-05-client-model.pdf
create-netflix-clone-05-client-model.pdf
ShaiAlmog1
 
Creating a Whatsapp Clone - Part II.pdf
Creating a Whatsapp Clone - Part II.pdfCreating a Whatsapp Clone - Part II.pdf
Creating a Whatsapp Clone - Part II.pdf
ShaiAlmog1
 
Creating a Whatsapp Clone - Part IX - Transcript.pdf
Creating a Whatsapp Clone - Part IX - Transcript.pdfCreating a Whatsapp Clone - Part IX - Transcript.pdf
Creating a Whatsapp Clone - Part IX - Transcript.pdf
ShaiAlmog1
 
Creating a Whatsapp Clone - Part II - Transcript.pdf
Creating a Whatsapp Clone - Part II - Transcript.pdfCreating a Whatsapp Clone - Part II - Transcript.pdf
Creating a Whatsapp Clone - Part II - Transcript.pdf
ShaiAlmog1
 
Creating a Whatsapp Clone - Part V - Transcript.pdf
Creating a Whatsapp Clone - Part V - Transcript.pdfCreating a Whatsapp Clone - Part V - Transcript.pdf
Creating a Whatsapp Clone - Part V - Transcript.pdf
ShaiAlmog1
 
Creating a Whatsapp Clone - Part IV - Transcript.pdf
Creating a Whatsapp Clone - Part IV - Transcript.pdfCreating a Whatsapp Clone - Part IV - Transcript.pdf
Creating a Whatsapp Clone - Part IV - Transcript.pdf
ShaiAlmog1
 
Creating a Whatsapp Clone - Part IV.pdf
Creating a Whatsapp Clone - Part IV.pdfCreating a Whatsapp Clone - Part IV.pdf
Creating a Whatsapp Clone - Part IV.pdf
ShaiAlmog1
 
Creating a Whatsapp Clone - Part I - Transcript.pdf
Creating a Whatsapp Clone - Part I - Transcript.pdfCreating a Whatsapp Clone - Part I - Transcript.pdf
Creating a Whatsapp Clone - Part I - Transcript.pdf
ShaiAlmog1
 

More from ShaiAlmog1 (20)

The Duck Teaches Learn to debug from the masters. Local to production- kill ...
The Duck Teaches  Learn to debug from the masters. Local to production- kill ...The Duck Teaches  Learn to debug from the masters. Local to production- kill ...
The Duck Teaches Learn to debug from the masters. Local to production- kill ...
 
create-netflix-clone-06-client-ui.pdf
create-netflix-clone-06-client-ui.pdfcreate-netflix-clone-06-client-ui.pdf
create-netflix-clone-06-client-ui.pdf
 
create-netflix-clone-01-introduction_transcript.pdf
create-netflix-clone-01-introduction_transcript.pdfcreate-netflix-clone-01-introduction_transcript.pdf
create-netflix-clone-01-introduction_transcript.pdf
 
create-netflix-clone-02-server_transcript.pdf
create-netflix-clone-02-server_transcript.pdfcreate-netflix-clone-02-server_transcript.pdf
create-netflix-clone-02-server_transcript.pdf
 
create-netflix-clone-04-server-continued_transcript.pdf
create-netflix-clone-04-server-continued_transcript.pdfcreate-netflix-clone-04-server-continued_transcript.pdf
create-netflix-clone-04-server-continued_transcript.pdf
 
create-netflix-clone-01-introduction.pdf
create-netflix-clone-01-introduction.pdfcreate-netflix-clone-01-introduction.pdf
create-netflix-clone-01-introduction.pdf
 
create-netflix-clone-06-client-ui_transcript.pdf
create-netflix-clone-06-client-ui_transcript.pdfcreate-netflix-clone-06-client-ui_transcript.pdf
create-netflix-clone-06-client-ui_transcript.pdf
 
create-netflix-clone-03-server.pdf
create-netflix-clone-03-server.pdfcreate-netflix-clone-03-server.pdf
create-netflix-clone-03-server.pdf
 
create-netflix-clone-04-server-continued.pdf
create-netflix-clone-04-server-continued.pdfcreate-netflix-clone-04-server-continued.pdf
create-netflix-clone-04-server-continued.pdf
 
create-netflix-clone-05-client-model_transcript.pdf
create-netflix-clone-05-client-model_transcript.pdfcreate-netflix-clone-05-client-model_transcript.pdf
create-netflix-clone-05-client-model_transcript.pdf
 
create-netflix-clone-03-server_transcript.pdf
create-netflix-clone-03-server_transcript.pdfcreate-netflix-clone-03-server_transcript.pdf
create-netflix-clone-03-server_transcript.pdf
 
create-netflix-clone-02-server.pdf
create-netflix-clone-02-server.pdfcreate-netflix-clone-02-server.pdf
create-netflix-clone-02-server.pdf
 
create-netflix-clone-05-client-model.pdf
create-netflix-clone-05-client-model.pdfcreate-netflix-clone-05-client-model.pdf
create-netflix-clone-05-client-model.pdf
 
Creating a Whatsapp Clone - Part II.pdf
Creating a Whatsapp Clone - Part II.pdfCreating a Whatsapp Clone - Part II.pdf
Creating a Whatsapp Clone - Part II.pdf
 
Creating a Whatsapp Clone - Part IX - Transcript.pdf
Creating a Whatsapp Clone - Part IX - Transcript.pdfCreating a Whatsapp Clone - Part IX - Transcript.pdf
Creating a Whatsapp Clone - Part IX - Transcript.pdf
 
Creating a Whatsapp Clone - Part II - Transcript.pdf
Creating a Whatsapp Clone - Part II - Transcript.pdfCreating a Whatsapp Clone - Part II - Transcript.pdf
Creating a Whatsapp Clone - Part II - Transcript.pdf
 
Creating a Whatsapp Clone - Part V - Transcript.pdf
Creating a Whatsapp Clone - Part V - Transcript.pdfCreating a Whatsapp Clone - Part V - Transcript.pdf
Creating a Whatsapp Clone - Part V - Transcript.pdf
 
Creating a Whatsapp Clone - Part IV - Transcript.pdf
Creating a Whatsapp Clone - Part IV - Transcript.pdfCreating a Whatsapp Clone - Part IV - Transcript.pdf
Creating a Whatsapp Clone - Part IV - Transcript.pdf
 
Creating a Whatsapp Clone - Part IV.pdf
Creating a Whatsapp Clone - Part IV.pdfCreating a Whatsapp Clone - Part IV.pdf
Creating a Whatsapp Clone - Part IV.pdf
 
Creating a Whatsapp Clone - Part I - Transcript.pdf
Creating a Whatsapp Clone - Part I - Transcript.pdfCreating a Whatsapp Clone - Part I - Transcript.pdf
Creating a Whatsapp Clone - Part I - Transcript.pdf
 

Recently uploaded

Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
Tobias Schneck
 
To Graph or Not to Graph Knowledge Graph Architectures and LLMs
To Graph or Not to Graph Knowledge Graph Architectures and LLMsTo Graph or Not to Graph Knowledge Graph Architectures and LLMs
To Graph or Not to Graph Knowledge Graph Architectures and LLMs
Paul Groth
 
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
UiPathCommunity
 
De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...
De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...
De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...
Product School
 
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Product School
 
JMeter webinar - integration with InfluxDB and Grafana
JMeter webinar - integration with InfluxDB and GrafanaJMeter webinar - integration with InfluxDB and Grafana
JMeter webinar - integration with InfluxDB and Grafana
RTTS
 
Connector Corner: Automate dynamic content and events by pushing a button
Connector Corner: Automate dynamic content and events by pushing a buttonConnector Corner: Automate dynamic content and events by pushing a button
Connector Corner: Automate dynamic content and events by pushing a button
DianaGray10
 
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
Sri Ambati
 
Monitoring Java Application Security with JDK Tools and JFR Events
Monitoring Java Application Security with JDK Tools and JFR EventsMonitoring Java Application Security with JDK Tools and JFR Events
Monitoring Java Application Security with JDK Tools and JFR Events
Ana-Maria Mihalceanu
 
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdfFIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance
 
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
DanBrown980551
 
Software Delivery At the Speed of AI: Inflectra Invests In AI-Powered Quality
Software Delivery At the Speed of AI: Inflectra Invests In AI-Powered QualitySoftware Delivery At the Speed of AI: Inflectra Invests In AI-Powered Quality
Software Delivery At the Speed of AI: Inflectra Invests In AI-Powered Quality
Inflectra
 
PCI PIN Basics Webinar from the Controlcase Team
PCI PIN Basics Webinar from the Controlcase TeamPCI PIN Basics Webinar from the Controlcase Team
PCI PIN Basics Webinar from the Controlcase Team
ControlCase
 
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdfFIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance
 
The Art of the Pitch: WordPress Relationships and Sales
The Art of the Pitch: WordPress Relationships and SalesThe Art of the Pitch: WordPress Relationships and Sales
The Art of the Pitch: WordPress Relationships and Sales
Laura Byrne
 
When stars align: studies in data quality, knowledge graphs, and machine lear...
When stars align: studies in data quality, knowledge graphs, and machine lear...When stars align: studies in data quality, knowledge graphs, and machine lear...
When stars align: studies in data quality, knowledge graphs, and machine lear...
Elena Simperl
 
Essentials of Automations: Optimizing FME Workflows with Parameters
Essentials of Automations: Optimizing FME Workflows with ParametersEssentials of Automations: Optimizing FME Workflows with Parameters
Essentials of Automations: Optimizing FME Workflows with Parameters
Safe Software
 
Knowledge engineering: from people to machines and back
Knowledge engineering: from people to machines and backKnowledge engineering: from people to machines and back
Knowledge engineering: from people to machines and back
Elena Simperl
 
From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...
From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...
From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...
Product School
 
Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...
Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...
Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...
Thierry Lestable
 

Recently uploaded (20)

Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
 
To Graph or Not to Graph Knowledge Graph Architectures and LLMs
To Graph or Not to Graph Knowledge Graph Architectures and LLMsTo Graph or Not to Graph Knowledge Graph Architectures and LLMs
To Graph or Not to Graph Knowledge Graph Architectures and LLMs
 
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
 
De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...
De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...
De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...
 
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
 
JMeter webinar - integration with InfluxDB and Grafana
JMeter webinar - integration with InfluxDB and GrafanaJMeter webinar - integration with InfluxDB and Grafana
JMeter webinar - integration with InfluxDB and Grafana
 
Connector Corner: Automate dynamic content and events by pushing a button
Connector Corner: Automate dynamic content and events by pushing a buttonConnector Corner: Automate dynamic content and events by pushing a button
Connector Corner: Automate dynamic content and events by pushing a button
 
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
 
Monitoring Java Application Security with JDK Tools and JFR Events
Monitoring Java Application Security with JDK Tools and JFR EventsMonitoring Java Application Security with JDK Tools and JFR Events
Monitoring Java Application Security with JDK Tools and JFR Events
 
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdfFIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
 
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
 
Software Delivery At the Speed of AI: Inflectra Invests In AI-Powered Quality
Software Delivery At the Speed of AI: Inflectra Invests In AI-Powered QualitySoftware Delivery At the Speed of AI: Inflectra Invests In AI-Powered Quality
Software Delivery At the Speed of AI: Inflectra Invests In AI-Powered Quality
 
PCI PIN Basics Webinar from the Controlcase Team
PCI PIN Basics Webinar from the Controlcase TeamPCI PIN Basics Webinar from the Controlcase Team
PCI PIN Basics Webinar from the Controlcase Team
 
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdfFIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
 
The Art of the Pitch: WordPress Relationships and Sales
The Art of the Pitch: WordPress Relationships and SalesThe Art of the Pitch: WordPress Relationships and Sales
The Art of the Pitch: WordPress Relationships and Sales
 
When stars align: studies in data quality, knowledge graphs, and machine lear...
When stars align: studies in data quality, knowledge graphs, and machine lear...When stars align: studies in data quality, knowledge graphs, and machine lear...
When stars align: studies in data quality, knowledge graphs, and machine lear...
 
Essentials of Automations: Optimizing FME Workflows with Parameters
Essentials of Automations: Optimizing FME Workflows with ParametersEssentials of Automations: Optimizing FME Workflows with Parameters
Essentials of Automations: Optimizing FME Workflows with Parameters
 
Knowledge engineering: from people to machines and back
Knowledge engineering: from people to machines and backKnowledge engineering: from people to machines and back
Knowledge engineering: from people to machines and back
 
From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...
From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...
From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...
 
Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...
Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...
Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...
 

Hacking the Codename One Source Code - Part IV - Transcript.pdf

  • 1. Hacking the Source - Part IV Now that we have the general drift lets move on to Android. In one aspect Android is easier than iOS as it's based on Java. However, other aspects make it a bit painful and in most regards harder to work with than iOS.
  • 2. Android Studio © Codename One 2017 all rights reserved We will use Android Studio 3.x to build the project since this is pretty much what Google demands. The first step in building on Android is mostly about running through the IDE steps. The first step is the new project option
  • 3. Package Name © Codename One 2017 all rights reserved When setting the project details the most important bit is the package name. It should match our main package name!
  • 4. Target Devices © Codename One 2017 all rights reserved I left the default settings for the target platform unchanged, this should work fine
  • 5. Activity © Codename One 2017 all rights reserved I chose the blank activity, I'll create one manually later. We are now presented with a progress indicator and then after a while Android Studio finally loads. Notice that you might need to resolve issues in the IDE if it connects to older versions of the Android SDK installed in your system.
  • 6. Java 8 © Codename One 2017 all rights reserved The first thing we need to do once the IDE has finished loading is configure Java 8 support. The Codename One build servers translate the built bytecodes so they will work without Java 8 support on Android. We need to do that since we have no access to the source code in the servers and we want to remain compatible. However, Java 8 is now supported in Android Studio and this will allow your code to compile unchanged. Notice that the core Codename One code is still Java 5 compatible. To do this we need to first pick the project structure option from the menu. We then need to set the source & target compatibility to Java 8
  • 7. apply plugin: 'com.android.application' android { compileSdkVersion 26 defaultConfig { applicationId "com.codename1.demos.kitchen" minSdkVersion 15 targetSdkVersion 26 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } sourceSets { main.java.srcDirs += 'src/main' main.java.srcDirs += '../../KitchenSink/src' } compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } build.gradle The next step is to edit the build.gradle file and add support for our sources. Notice that there are two build.gradle files in the project, you only need to edit the one for the Android project itself which in my case was marked as (Module: app). After you make changes to system files Android Studio offers to sync the project again which you should accept. This is the full code but you should probably only take the lines I highlight in the modifications. Lets scroll down to look at the changes
  • 8. minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } sourceSets { main.java.srcDirs += 'src/main' main.java.srcDirs += '../../KitchenSink/src' } compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } } dependencies { implementation fileTree(include: ['*.jar'], dir: 'libs') implementation 'com.android.support:appcompat-v7:26.1.0' testImplementation 'junit:junit:4.12' androidTestImplementation 'com.android.support.test:runner:1.0.1' androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1' compile 'com.google.android.gms:play-services-identity:8.3.0' compile 'com.google.android.gms:play-services-plus:8.3.0' compile 'com.google.android.gms:play-services-location:8.3.0' compile 'com.google.android.gms:play-services-auth:8.3.0' compile 'com.facebook.android:facebook-android-sdk:4.7.0' } build.gradle I added a source set section that points at the sources of the kitchen sink project, that way they appear in the hierarchy but we don't need to copy them
  • 9. minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } sourceSets { main.java.srcDirs += 'src/main' main.java.srcDirs += '../../KitchenSink/src' } compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } } dependencies { implementation fileTree(include: ['*.jar'], dir: 'libs') implementation 'com.android.support:appcompat-v7:26.1.0' testImplementation 'junit:junit:4.12' androidTestImplementation 'com.android.support.test:runner:1.0.1' androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1' compile 'com.google.android.gms:play-services-identity:8.3.0' compile 'com.google.android.gms:play-services-plus:8.3.0' compile 'com.google.android.gms:play-services-location:8.3.0' compile 'com.google.android.gms:play-services-auth:8.3.0' compile 'com.facebook.android:facebook-android-sdk:4.7.0' } build.gradle I added all of these dependencies to the build. Notice that we don't actually need all of the dependencies. The build servers delete code that you don't need based on build hints. So if Facebook support isn't necessary it will delete the FacebookImpl class and won't place the facebook dependency. The same is true for the other dependencies mentioned.
  • 10. android.enableAapt2=false gradle.properties We also need to make a minor change to the `gradle.properties` file by adding this line. This is required for some of the style code later on.
  • 11. cp -Rf ../cn1/CodenameOne/src/* ../ KitchenSinkAndroid/app/src/main/java/ cp -Rf ../cn1/Ports/Android/src/* ../ KitchenSinkAndroid/app/src/main/java/ rm ../KitchenSinkAndroid/app/src/main/java/* Copy Sources The next step is copying the Android implementation sources into the project. Since the Android implementation sources don't include the Codename One sources we need to start with that. These commands are executed from the KitchenSink directory so they are relative to that path. Notice we copy the Codename One code first and the Android code second so files get overwritten. Also notice we delete all the files in the root of the project source (not recursively). The root of the Codename One and Android projects include resource files that should be placed in a different location. Android expects all resources that aren't in the res file to be within an assets directory. We need to create that directory in the hierarchy where the res directory resides.
  • 12. mkdir ../KitchenSinkAndroid/app/src/main/assets cp ../cn1/CodenameOne/src/* ../KitchenSinkAndroid/ app/src/main/assets/ cp ../cn1/Ports/Android/src/* ../ KitchenSinkAndroid/app/src/main/assets/ cp src/* ../KitchenSinkAndroid/app/src/main/assets Copy Assets This copies the files from the roots of all of these projects. Notice the order of commands sets the priority since a project on the way can override the parent project. Following these instructions you might be thinking “Why Copy?”. We included the source of the Kitchen Sink, why not do the same for the implementation? The main problem is overriden files. Codename One redefines the CodenameOneThread class in the Android implementation and relies on that redefinition taking the priority. We might do more of that in the future. This is also important because you might want to delete some files such as Facebook support. So copy makes more sense in this special case.
  • 13. package com.codename1.demos.kitchen; import com.codename1.impl.android.AndroidImplementation; import com.codename1.impl.android.CodenameOneActivity; import com.codename1.ui.Dialog; import com.codename1.ui.Display; import com.codename1.ui.Form; public class KitchenSinkStub extends CodenameOneActivity implements Runnable { private static KitchenSink i; private static boolean firstTime = true; private Form currentForm; private static final Object LOCK = new Object(); protected void onResume() { super.onResume(); AndroidImplementation.startContext(this); if (i == null) { i = new KitchenSink(); } Display.getInstance().callSerially(this); } public void run() { if (firstTime) { firstTime = false; i.init(this); KitchenSinkStub The next step is the activity class which is Androids lifecycle object. This is a pretty standard class in Android so I'll add the code & step over it like before. We have a CodenameOneActivity base class which is important for the main activity as we handle some nuanced events there
  • 14. package com.codename1.demos.kitchen; import com.codename1.impl.android.AndroidImplementation; import com.codename1.impl.android.CodenameOneActivity; import com.codename1.ui.Dialog; import com.codename1.ui.Display; import com.codename1.ui.Form; public class KitchenSinkStub extends CodenameOneActivity implements Runnable { private static KitchenSink i; private static boolean firstTime = true; private Form currentForm; private static final Object LOCK = new Object(); protected void onResume() { super.onResume(); AndroidImplementation.startContext(this); if (i == null) { i = new KitchenSink(); } Display.getInstance().callSerially(this); } public void run() { if (firstTime) { firstTime = false; i.init(this); KitchenSinkStub Most Android apps use onCreate to detect app launch. We use onResume which is more consistent for our needs in terms of suspend/resume behavior
  • 15. package com.codename1.demos.kitchen; import com.codename1.impl.android.AndroidImplementation; import com.codename1.impl.android.CodenameOneActivity; import com.codename1.ui.Dialog; import com.codename1.ui.Display; import com.codename1.ui.Form; public class KitchenSinkStub extends CodenameOneActivity implements Runnable { private static KitchenSink i; private static boolean firstTime = true; private Form currentForm; private static final Object LOCK = new Object(); protected void onResume() { super.onResume(); AndroidImplementation.startContext(this); if (i == null) { i = new KitchenSink(); } Display.getInstance().callSerially(this); } public void run() { if (firstTime) { firstTime = false; i.init(this); KitchenSinkStub These lines effectively initialize Codename One and start the EDT if it isn't running. We also allocate the KitchenSink main class if it isn't allocated yet
  • 16. package com.codename1.demos.kitchen; import com.codename1.impl.android.AndroidImplementation; import com.codename1.impl.android.CodenameOneActivity; import com.codename1.ui.Dialog; import com.codename1.ui.Display; import com.codename1.ui.Form; public class KitchenSinkStub extends CodenameOneActivity implements Runnable { private static KitchenSink i; private static boolean firstTime = true; private Form currentForm; private static final Object LOCK = new Object(); protected void onResume() { super.onResume(); AndroidImplementation.startContext(this); if (i == null) { i = new KitchenSink(); } Display.getInstance().callSerially(this); } public void run() { if (firstTime) { firstTime = false; i.init(this); KitchenSinkStub I did the allocation on the Android thread which isn't ideal but the callback should be invoked on the Codename One thread which is why we have this callSerially here
  • 17. public void run() { if (firstTime) { firstTime = false; i.init(this); } else { synchronized (LOCK) { if (currentForm != null) { if (currentForm instanceof Dialog) { ((Dialog) currentForm).showModeless(); } else { currentForm.show(); } fireIntentResult(); currentForm = null; setWaitingForResult(false); return; } } } i.start(); } protected void onPause() { super.onPause(); KitchenSinkStub Now on the EDT if this is the first time we need to invoke the `init(Object)` method of the main class
  • 18. public void run() { if (firstTime) { firstTime = false; i.init(this); } else { synchronized (LOCK) { if (currentForm != null) { if (currentForm instanceof Dialog) { ((Dialog) currentForm).showModeless(); } else { currentForm.show(); } fireIntentResult(); currentForm = null; setWaitingForResult(false); return; } } } i.start(); } protected void onPause() { super.onPause(); KitchenSinkStub Otherwise if we are resuming we try to be "smart" about the current Form since Android has a tendency to restart activities for everything
  • 19. public void run() { if (firstTime) { firstTime = false; i.init(this); } else { synchronized (LOCK) { if (currentForm != null) { if (currentForm instanceof Dialog) { ((Dialog) currentForm).showModeless(); } else { currentForm.show(); } fireIntentResult(); currentForm = null; setWaitingForResult(false); return; } } } i.start(); } protected void onPause() { super.onPause(); KitchenSinkStub start() is invoked with every call to resume to match the lifecycle behavior of Codename One. The same holds true to stop and destroy both of which are pretty trivial
  • 20. i.start(); } protected void onPause() { super.onPause(); synchronized (LOCK) { currentForm = Display.getInstance().getCurrent(); } } protected void onStop() { super.onStop(); if (isWaitingForResult()) { return; } synchronized (LOCK) { currentForm = null; } Display.getInstance().callSerially(() -> i.stop()); } protected void onDestroy() { super.onDestroy(); Display.getInstance().callSerially(() -> { i.destroy(); Display.deinitialize(); }); } } KitchenSinkStub The rest of the code is just boilerplate and uninteresting. We invoke stop in onStop and invoke destroy in onDestroy()
  • 21. <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.codename1.demos.kitchen"> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/CustomTheme" > <activity android:name=".KitchenSinkStub" android:configChanges="orientation|keyboardHidden|screenSize" android:launchMode="singleTop"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest> Manifest Now that all of that is out of the way we just need to configure the XML files. First we have the manifest file which represents all the activities in the application. The manifest isn't really important here. I just used the default manifest generated by the IDE and updated the activity entry. Notice that most of the entries within the activity are essential for the app.
  • 22. <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="#ff000000"> </RelativeLayout> main.xml We also need a layout for the main application so under the res/layout directory we need to add the file main.xml. That's a pretty simple layout just to give room for Codename One itself.
  • 23. <?xml version="1.0" encoding="utf-8"?> <resources> <style name="CustomTheme" parent="android:Theme.Black"> <item name="attr/cn1Style">@style/CN1.EditText.Style</item> </style> <attr name="cn1Style" format="reference" /> <style name="CN1.EditText.Style" parent="@android:style/Widget.EditText"> <item name="android:textCursorDrawable">@null</item> </style> </resources> styles.xml We need 3 style files to support all this, the first is styles.xml which resides in the directory src/main/res/values. Which just includes a theme and not much else.
  • 24. <?xml version="1.0" encoding="utf-8"?> <resources> <style name="CustomTheme" parent="@android:style/Theme.Holo.Light"> <item name="attr/cn1Style">@style/CN1.EditText.Style</item> <item name="android:windowActionBar">false</item> <item name="android:windowTitleSize">0dp</item> </style> <style name="CN1.EditText.Style" parent="@android:style/Widget.EditText"> <item name="android:textCursorDrawable">@null</item> </style> </resources> styles.xml (v11) The second bares the same name but resides in the directory src/main/res/values-v11. Again this is pretty trivial and hardcoded for all the apps
  • 25. <?xml version="1.0" encoding="utf-8"?> <resources> <style name="CustomTheme" parent="@android:style/Theme.Material.Light"> <item name="attr/cn1Style">@style/CN1.EditText.Style</item> <item name="android:windowActionBar">false</item> <item name="android:windowTitleSize">0dp</item> <item name="android:colorPrimary">@color/colorPrimary</item> <item name="android:colorPrimaryDark">@color/colorPrimaryDark</item> <item name="android:colorAccent">@color/colorAccent</item> </style> <style name="CN1.EditText.Style" parent="@android:style/Widget.EditText"> <item name="android:textCursorDrawable">@null</item> </style> </resources> styles.xml (v21) The final one also has the same name but resides in the directory src/main/res/values-v21. It includes some additional settings for newer versions of Android. Now that all this is done you can just press play in the IDE and run on an Android device! There was a bit of boilerplate but I hope it’s clear