Sign in Join
Wiki copytemporary

Android Programming: what changed

Revision 2 to 3. Removed lines have a minus sign; added lines have a plus sign.

OldNewLine
11*(Android only)*
22
33See also [[Custom Drawn Interface/Android]]
44
55Knowing general Android programming can be very useful to help develop the Lazarus Android Interface.
66
77## Platform Tips
88
99## How to...
1010
1111### Build the NDK OpenGL example
1212
1313Just follow these steps:
1414
1515**Step 1** - Download and install the Android NDK, Android SDK and Ant. More information here: [[Android Interface/Using the Android SDK, Emulator and Phones|Android_Interface/Using_the_Android_SDK%2C_Emulator_and_Phones]]
1616
1717**Step 2** - Install the pre-compiled FPC cross-compiler. Instructions here: [[Android Interface|Android_Interface#Using_the_pre-compiled_compiler]]
1818
1919**Step 3** - Download the latest lazarus-ccr sourceforge code:
2020
2121``` bash
2222svn co https://lazarus-ccr.svn.sourceforge.net/svnroot/lazarus-ccr lazarus-ccr
2323```
2424
2525or if you think it is too big you can download just the folder lazarus-ccr/bindings/android-ndk
2626
2727**Step 4** - Building the Pascal Library
2828
2929> **Note:** In the steps below, the directory /home/felipe/Programas or ~/Programas is used. Please adjust if your paths are different.
3030
3131Open the project lazarus-ccr/bindings/android-ndk/examples/opengltest/opengltest.lpi
3232
3333Go to Project-\>Project Options-\>Paths and where is written "Libraries -Fl" you should see a value like this:
3434
35-`/home/felipe/Programas/android-ndk-r5/platforms/android-9/arch-arm/usr/lib`
35+```
36+/home/felipe/Programas/android-ndk-r5/platforms/android-9/arch-arm/usr/lib
37+```
3638
3739Change it to the correct path in your system which points to the NDK and to the library folder for your minimal required Android API Level
3840
3941Now build the project using Lazarus.
4042
4143**Step 5** - Configuring the build environment
4244
4345Open the file opengltest/local.properties. Change this line to point to your SDK location:
4446
45-`sdk.dir=/home/felipe/Programas/android-sdk-linux`
47+```
48+sdk.dir=/home/felipe/Programas/android-sdk-linux
49+```
4650
4751**Step 6** - Buildings the APK
4852
4953Open a terminal and type these commands:
5054
5155``` bash
5256cd lazarus-ccr/bindings/ndk/examples/opengltest/android
5357ant debug
5458```
5559
5660The APK file will be placed in opengltest/android/bin/
5761
5862**Step 7** - Install the APK
5963
6064In this step, if you get error messages about permissions read: [[Android Interface/Using the Android SDK, Emulator and Phones|Android_Interface/Using_the_Android_SDK%2C_Emulator_and_Phones#Recognition_of_devices_under_Linux]]
6165
6266The command to install our APK in the phone is:
6367
6468``` bash
6569cd opengltest/android
6670~/Programas/android-sdk-linux/platform-tools/adb install bin/OpenGLNDKTest-debug.apk
6771```
6872
6973You should see something like:
7074
71-`2395 KB/s (107299 bytes in 0.043s)`\
72-`       pkg: /data/local/tmp/OpenGLNDKTest-debug.apk`\
73-`Success`
75+```
76+2395 KB/s (107299 bytes in 0.043s)
77+ pkg: /data/local/tmp/OpenGLNDKTest-debug.apk
78+Success
79+```
7480
7581If you get an error message that it is already installed you can install with this command:
7682
7783``` bash
7884~/Programas/android-sdk-linux/platform-tools/adb uninstall com.pascal.opengltest
7985```
8086
8187And then you can run adb logcat to see what the log says while you start it in the phone via its newly added icon:
8288
8389``` bash
8490~/Programas/android-sdk-linux/platform-tools/adb logcat
8591```
8692
8793### Read the screen metrics
8894
8995First fill a TDisplayMetrics with the correct info:
9096
9197``` pascal
9298uses androidutil;
9399
94100var
95101 MyDisplayMetrics: TDisplayMetrics;
96102 Str: string;
97103 //
98104 lHeight, lWidth: Integer;
99105 xdpi, ydpi, lScreenSize: Single;
100106begin
101107 // ..
102108 // Objects
103109
104110 MyDisplayMetrics := TDisplayMetrics.Create;
105111 Activity.getWindowManager().getDefaultDisplay().getMetrics(MyDisplayMetrics);
106112```
107113
108114And then you can read it from the TDisplayMetrics:
109115
110116``` pascal
111117 lHeight := MyDisplayMetrics.heightPixels();
112118 lWidth := MyDisplayMetrics.widthPixels();
113119 xdpi := MyDisplayMetrics.xdpi();
114120 ydpi := MyDisplayMetrics.ydpi();
115121 lScreenSize := sqrt(sqr(lHeight / ydpi) + sqr(lWidth / xdpi));
116122 ldensity := MyDisplayMetrics.density();
117123 ldensityDpi := MyDisplayMetrics.densityDpi();
118124 scaledDensity := MyDisplayMetrics.scaledDensity();
119125```
120126
121127Note that lots of devices lie about the xdpi and ydpi, so don't trust the lScreenSize calculated above. Smartphones might report even 10 inches of screen size, while the correct is around 4.
122128
123129## Details about Android devices
124130
125131Since there are so many Android devices, it can be useful to keep track of some information about them. See also in the wikipedia Comparison of Android Devices [1](http://en.wikipedia.org/wiki/Comparison_of_Android_devices) and details about the processors in [2](https://wiki.mozilla.org/Mobile/Platforms/Android#System_Requirements).
126132
127133### Smartphones
128134
129135| Manufacturer | Model | Android API Name (Build.Model) | Processor | Android version | Multi-touch | Comments |
130136|----|----|----|----|----|----|----|
131137| HTC | Wildfire | HTC Wildfire | armv6 | 2.1=\>2.2 | Yes\|\|- | |
132138| Sony Erricson | Xperia X10 | X10i | armv7 | 1.6=\>2.1 | No\|\|- | |
133139
134140### Tablets
135141
136142| Manufacturer | Model | Android API Name (Build.Model) | Processor | Android version | Multi-touch | Comments |
137143|----|----|----|----|----|----|----|
138144| Toshiba | Folio 100 Tablet | TOSHIBA_FOLIO_AND_A | armv7 | 2.2 | Yes\|\|- | |
139145
140146### List of devices ordered by processor compatibility (ARMv6 vs ARMv7)
141147
142148<caption>List of ARMv7 devices</caption>
143149<tbody>
144150
145151Fascinate, Vibrant, Epic 4G)</td>
146152
147153</tbody>
148154
149155| | | | |
150156|----|----|----|----|
151157| Android SDK emulator | Asus Garmin nuvifone A50 (T-Mobile Garminfone) | Augen GENTouch 78 Tablet | Coby Kyros Internet Tablet (MID7015) |
152158| Geeksphone One, Geeksphone Zero | HTC Aria | HTC ChaCha | HTC Dream (T-Mobile G1, Android Dev Phone 1) |
153159| HTC Droid Eris | HTC Espresso (T-Mobile myTouch 3G Slide) | HTC Hero (T-Mobile G2 Touch) | \|HTC Legend |
154160| HTC Magic (T-Mobile myTouch 3G, T-Mobile G1 Touch) | HTC Salsa | HTC Tattoo | HTC Wildfire |
155161| Huawei Ascend | Huawei Ideos U8150-B (T-Mobile Comet) | Huawei U8110 (T-Mobile Pulse Mini) | \|Huawei U8230 |
156162| LG Ally (Apex) (LG VS740) | LG GW620 (Eve, InTouch Max, LinkMe) | LG Optimus, Optimus M, Optimus T, Optimus S, Optimus V | LG Vortex |
157163| LG P500 | MAG iMiTO iM7 | vMAG iMiTO iM7S | Motorola Backflip |
158164| Motorola Citrus | Motorola Cliq (MB200) | Motorola Dext | Motorola Devour |
159165| Motorola i1 | Motorola Spice XT300 | Motorola Quench XT5 XT502 | Pandigital Novel |
160166| Samsung GT-S5570 Galaxy Mini | Samsung i5500 Galaxy 5 (Corby) | Samsung i5700 Galaxy Portal (Spica) | Samsung i5800 Galaxy 3 |
161167| Samsung i7500 Galaxy | Samsung Intercept | Samsung M900 Moment | Samsung S5830 Galaxy Ace |
162168| Samsung Transform | Sanyo ZIO M6000 | Sony Ericsson Xperia X8 | Sony Ericsson Xperia X10 Mini |
163169| Sony Ericsson Xperia X10 Mini Pro | Superpad 10.2" Tablet PC | Viewsonic ViewPad 7 Tablet | Velocity Micro T103 Cruz tablet |
164170| Vodafone 845 | ZTE Blade | | |
165171
166172List of ARMv6 processors:'''
167173
168174### Playing sounds and videos on the phones
169175
170176Each phone comes with different codecs installed, which means that the native Media Player will be able to play different formats in different phones. Below is a table showing which formats play in the native Media Player of each phone:
171177
172178| Telephone | Android | webm - VP8 | m4v - H.264 | ogv - Theora | mp4 - H.264 | mov - H.264 | avi - RLE | mpg - MPEG-1 | wmv - WM9 | 3gp - MPEG-4 |
173179|----|----|----|----|----|----|----|----|----|----|----|
174180| Emulator | 1.6 | x | x | x | x | x | x | x | x | OK |
175181| Emulator | 2.1 | x | x | x | x | x | x | x | x | OK |
176182| Nexus One | 2.2 | x | OK | x | OK | x | x | x | x | OK |
177183| HTC Desire | 1.6 | x | OK | x | OK | x | x | x | OK | OK |
178184| Toshiba Folio 100 | 2.2 | x | OK | x | OK | x | x | x | OK | OK |
179185| Xperia X10 | 2.1 | x | OK | x | x | x | x | x | OK | OK |
180186| Xperia X8 | 2.2 | x | OK | x | x | x | x | x | x | OK |
181187| HTC Wildfire | 2.1 | x | OK | x | x | x | x | x | x | OK |
182188| HTC Desire HD | 2.2 | x | OK | x | OK | x | x | x | x | OK |
183189| Galaxy Tab | 2.2 | x | OK | x | x | x | x | x | x | OK |
184190| myPhone A210 | 1.6 | x | OK | x | x | x | x | x | x | OK |
185191| Motorola Milestone | 2.1 | x | OK | x | x | x | x | x | OK | ? |
186192| Milestone 2 | 2.2 | x | OK | x | x | x | x | x | sound-only | OK |
187193
188194## Android file system
189195
190196Android recommends to use getApplicationContext().getFilesDir() to obtain the data directory for the application and this routine in my HTC Wildfire returns /data/data/\<package name\>
191197
192198The native libraries of the application are placed in /data/data/\<package\>/lib
193199
194200A good place where we have read and write access and we can create new files and even run files is /data/data/\<package name\>
195201
196202## Creating a new Java Android application
197203
198204This info can be useful for helping implement LCL-CustomDrawn-Android
199205
200206Generic instructions here: <http://developer.android.com/guide/developing/other-ide.html>
201207
202208### Showing/hiding the virtual keyboard
203209
204210See here: <http://android-codes-examples.blogspot.com/2011/11/show-or-hide-soft-keyboard-on-opening.html>
205211
206212To show it:
207213
208214``` java
209215InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
210216imm.toggleSoftInput(InputMethodManager.SHOW_FORCED,0);
211217```
212218
213219and for hiding the keyboard:
214220
215221``` java
216222InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
217223imm.hideSoftInputFromWindow(singleedittext.getWindowToken(),0);
218224```
219225
220226## Android JNI
221227
222228Using JNI (Java Native Interface) you can call most Android SDK APIs and also other Java libraries.
223229
224230### Table of Java types and Pascal JNI types
225231
226232All of the Java types except interfaces can be represented in JNI without problems. For each Java type there is a corresponding VM Type Signature which is utilized in routines such as javaEnvRef^^.GetMethodID. There is also the JNI native type, which is the type declared in the unit lazarus/lcl/interfaces/customdrawn/android/jni.pas and should be the type utilized in JNI code written in Pascal. The Pascal equivalent is provided just for comparison, as one should use the types from jni.pas when writing JNI code.
227233
228234| Java type | VM signature | Type in jni.pas | Pascal equivalent | Description |
229235|----|----|----|----|----|
230236| boolean | Z | jboolean | Boolean | |
231237| byte | B | jbyte | Byte | |
232238| char | C | jchar | Word | |
233239| short | S | jshort | Shortint | |
234240| int | I | jint | Integer | |
235241| long | J | jlong | Int64 | |
236242| float | F | jfloat | Single | |
237243| double | D | jdouble | Double | |
238244| a class, ie: String or InputStream | L\<full class name\> ie: Ljava/lang/String; | jobject | N/A | |
239245| Array, ie: int\[\] | \[\<type-name\> ie: \[I | N/A | | |
240246| A method type | (arg-types)ref-type | JMethodID | N/A | |
241247| void | V | N/A | procedure | |
242248
243249### Example 1: Creating a Java object and calling a Java method
244250
245251Let's say that you want to make Pascal JNI code equivalent to the following Java code:
246252
247253``` java
248254 HttpGet javaRequest = new HttpGet();
249255 URI myURI = new URI("http://magnifier.sourceforge.net/");
250256 javaRequest.setURI(myURI);
251257```
252258
253259First you need to get all Class IDs involved in the process, then get all method IDs which we will use and then make the calls. If the call has parameters, then pass it in an array. The following Pascal native code is equivalent to that Java code above:
254260
255261``` pascal
256262uses jni, customdrawnint;
257263
258264var
259265 javaClass_HttpGet, javaClass_URI: jclass;
260266 javaMethod_HttpGet_new, javaMethod_HttpGet_setURI,
261267 javaMethod_URI_new: jmethodid;
262268 javaRequest, javaURI: jobject;
263269 javaString: jstring;
264270 lParams: array[0..2] of JValue;
265271 lNativeString: PChar;
266272begin
267273 DebugLn(':>LoadHTMLPageViaJNI');
268274 // First call FindClass for all required classes
269275 javaClass_HttpGet := javaEnvRef^^.FindClass(javaEnvRef,
270276 'org/apache/http/client/methods/HttpGet');
271277 javaClass_URI := javaEnvRef^^.FindClass(javaEnvRef,
272278 'java/net/URI');
273279
274280 // Now all Method IDs
275281 DebugLn(':LoadHTMLPageViaJNI 1');
276282 javaMethod_HttpGet_new := javaEnvRef^^.GetMethodID(javaEnvRef, javaClass_HttpGet, '<init>', '()V');
277283 javaMethod_HttpGet_setURI := javaEnvRef^^.GetMethodID(javaEnvRef, javaClass_HttpGet, 'setURI', '(Ljava/net/URI;)V');
278284 javaMethod_URI_new := javaEnvRef^^.GetMethodID(javaEnvRef, javaClass_URI, '<init>', '(Ljava/lang/String;)V');
279285
280286 // Create a new instance for the HTTP request object
281287 // HttpGet javaRequest = new HttpGet();
282288 javaRequest := javaEnvRef^^.NewObject(javaEnvRef,
283289 javaClass_HttpGet,
284290 javaMethod_HttpGet_new);
285291
286292 DebugLn(':LoadHTMLPageViaJNI 4 javaRequest='+IntToHex(PtrInt(javaRequest), 8));
287293 // Add a URI for the request object
288294 // URI javaURI = new URI("http://magnifier.sourceforge.net/");
289295 lParams[0].l := javaEnvRef^^.NewStringUTF(javaEnvRef, 'http://magnifier.sourceforge.net');
290296 javaURI := javaEnvRef^^.NewObjectA(javaEnvRef,
291297 javaClass_URI, javaMethod_URI_new, @lParams[0]);
292298 javaEnvRef^^.DeleteLocalRef(javaEnvRef, lParams[0].l);
293299 // javaRequest.setURI(javaURI);
294300 lParams[0].l := javaURI;
295301 javaEnvRef^^.CallVoidMethodA(javaEnvRef, javaRequest,
296302 javaMethod_HttpGet_setURI, @lParams[0]);
297303```
298304
299305### Example 2: Calling a static method
300306
301307Let's say that you want to call the following static method located in the Bass class: <http://jerome.jouvie.free.fr/nativebass/javadoc/org/jouvieje/bass/Bass.html>
302308
303309``` java
304310 public static native int BASS_StreamCreateFile(String file, long offset, long length, int flags);
305311```
306312
307313First you need to get all Class IDs involved in the process, then get the static method ID and then make the call with the parameter in the array:
308314
309315``` pascal
310316uses jni, customdrawnint;
311317
312318var
313319 javaClass_Bass: jclass;
314320 javaMethod_Bass_BASS_StreamCreateFile: jmethodid;
315321 javaString: jstring;
316322 lParams: array[0..3] of JValue;
317323 lRetInt: jint;
318324begin
319325 // First call FindClass for all required classes
320326 javaClass_Bass := javaEnvRef^^.FindClass(javaEnvRef, 'org/jouvieje/bass/Bass');
321327
322328 // Now all Method IDs
323329 javaMethod_Bass_BASS_StreamCreateFile := javaEnvRef^^.GetStaticMethodID(javaEnvRef, javaClass_Bass, 'BASS_StreamCreateFile', '(Ljava/lang/String;JJI)I');
324330
325331 // Make the call
326332 lParams[0].l := javaEnvRef^^.NewStringUTF(javaEnvRef, '/path/to/file');
327333 lParams[1].j := 0; // offset
328334 lParams[2].j := 200; // length
329335 lParams[3].i := 0; // flags
330336 lRetInt := javaEnvRef^^.CallStaticIntMethodA(javaEnvRef, javaClass_Bass, javaMethod_Bass_BASS_StreamCreateFile, @lParams[0]);
331337 javaEnvRef^^.DeleteLocalRef(javaEnvRef, lParams[0].l);
332338```
333339
334340## References
335341
336342- <http://developer.android.com/guide/developing/other-ide.html>
337343- [Tutorial "Lazarus and Android"](https://dl.dropboxusercontent.com/u/3753548/Lazarus%20and%20Android.pdf) (PDF file)
338344
339345---
340346*From the Free Pascal wiki, page "Android Programming", as it stood on 2019-12-16 after a change by Trev, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*

Back to history