Friday 20 May 2016

HB Blog 111: NDK - Hello World Tutorial.

The Native Development Kit (NDK) is a set of tools that allow you to leverage C and C++ code in your Android apps. You can use it either to build from your own source code, or to take advantage of existing prebuilt libraries. However, it can be useful in cases in which you need to,
  • Squeeze extra performance out of a device for computationally intensive applications like games or physics simulations.
  • Reuse your own or other developers' C or C++ libraries.
In this post, I will explain how to setup NDK as well as run a Hello World program. It's pretty simple.
Basically, installing and setting up the NDK is similar to our normal Android SDK. 
To install and configure the NDK, follow these steps,
  1. Get and install the Android SDK.
  2. Download and extract the NDK, making sure to download the correct version for your development platform. You may place the unzipped directory anywhere on your local drive.
  3. Update your PATH environment variable with the location of the directory that contains the NDK.
  4. Set ndk.dir path in local.properties.
  5. Finally, run normal gradle sync to check it all files are installed clearly. 
There are 2 important files that plays a role in building our NDK application namely, Android.mk and Application.mk. They are actually the make files. Android.mk files defines properties specific to individual modules, or libraries. Whereas, Application.mk defines properties for all the modules that you use in your app.

Android.mk: - The Android.mk file resides in a subdirectory of your project's jni/ directory, and describes your sources and shared libraries to the build system. The syntax of the Android.mk allows you to group your sources into modules. A module is either a static library, a shared library, or a standalone executable. Below is a sample file,

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# Defines the root to all other relative paths
# The macro function my-dir, provided by the build system,
# specifies the path of the current directory (i.e. the
# directory containing the Android.mk file itself)
LOCAL_PATH := $(call my-dir)

# Clear all LOCAL_XXX variables with the exception of
# LOCAL_PATH (this is needed because all variables are global)
include $(CLEAR_VARS)

# List all of our C/C++ files to be compiled (header file
# dependencies are automatically computed)
LOCAL_SRC_FILES := HelloWorldC.c

# The name of our shared module (this name will be prepended
# by lib and postfixed by .so)
LOCAL_MODULE := helloworld

# We need to tell the linker about our use of the liblog.so
LOCAL_LDLIBS += -llog

# Collects all LOCAL_XXX variables since "include $(CLEAR_VARS)"
#  and determines what to build (in this case a shared library)
include $(BUILD_SHARED_LIBRARY)

Application.mk: - The Application.mk file is really a tiny GNU Makefile fragment that defines several variables for compilation. It usually resides under $PROJECT/jni/, where $PROJECT points to your application's project directory. Below is a sample file,
1
2
3
4
5
6
7
8
ANDROID_JPEG_NO_ASSEMBLER := true
APP_PLATFORM := android-9
APP_STL := gnustl_static #gnustl_shared
# ARMv7 is significanly faster due to the use of the hardware FPU
APP_ABI := armeabi armeabi-v7a x86 
APP_OPTIM := release
#APP_CPPFLAGS += -frtti
APP_BUILD_SCRIPT := Android.mk

Now, for creating our Hello World application we need to add this Android.mk and Application.mk make files in jni folder under main folder.We need C or C++ files to be added into the same jni folder. We need header and C main file as per our program functionality. I will show a sample code to display HelloWorld message from C program into java textview. Then, run "javah" utility for compiling this C files, which produces shared output(.so) files in libs folder based on CPUs and Architectures defined in our make files.

Refer the below link for complete sample code:-

Download Sample Code

Have a look on few code snippets,

//HelloWorldC.h
1
2
3
4
5
6
7
8
//
// Created by harshal.benake on 27-04-2016.
//

#ifndef NDKHELLOWORLD_HELLOWORLDC_H
#define NDKHELLOWORLD_HELLOWORLDC_H
JNIEXPORT jstring JNICALL Java_com_example_harshalbenake_ndkhelloworld_MainActivity_getMessage(JNIEnv *, jobject);
#endif //NDKHELLOWORLD_HELLOWORLDC_H

//HelloWorldC.c
1
2
3
4
5
6
7
#include <jni.h>
#include <string.h>
#include "HelloWorldC.h"

JNIEXPORT jstring Java_com_example_harshalbenake_ndkhelloworld_MainActivity_getMessage(JNIEnv *env, jobject thisObj) {
   return (*env)->NewStringUTF(env, "Hello World from native code running successfully");
}

//MainActivity.java 
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package com.example.harshalbenake.ndkhelloworld;

import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;

public class MainActivity extends Activity {
    static {
        System.loadLibrary("helloworld"); // "helloworldjni.dll" in Windows, "libhelloworldjni.so" in Unixes
    }

    // A native method that returns a Java String to be displayed on the
    // TextView
    public native String getMessage();

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // Create a TextView.
        TextView textView = new TextView(this);
        // Retrieve the text from native method getMessage()
        textView.setText(getMessage());
        setContentView(textView);
    }
}

Sunday 15 May 2016

HB Blog 110: Custom File Explorer In Android Programmatically.

In Android development we always look for more simple and user-friendly user inputs. We have many custm keyboards, material design ad various other ways. Similarly, when we want user to choose an image from the gallery that’ll be displayed by the application we have various intents and actions such as ACTION_PICK. But, in case of the file formats that may not be an image, we cannot open gallery as only images are the part of the gallery application.

In such situation we invoke a single interface from which the user is able to select images across all his apps (like Gallery, Photos, ES File Explorer, etc.) and folders (Google Drive, Recent, Downloads, etc.) using Intents. But, this will take user away from your application as well as there will be 3rd party application dependence. So, we need to create our own custom file browser that will access ur sd-card files and folders.
Refer the below link for complete sample code:-

Download Sample Code

Have a look on few code snippets,

//FileBrowserActivity.java 
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
package com.example.harshalbenake.filebrowser;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

import android.app.AlertDialog;
import android.app.ListActivity;
import android.content.DialogInterface;
import android.os.Bundle;
import android.os.Environment;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

public class FileBrowserActivity extends ListActivity {
    private List<String> item = null;
    private List<String> path = null;

    private String root = "/sdcard";
    private TextView myPath;

    /**
     * Called when the activity is first created.
     */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_filebrowser);
        myPath = (TextView) findViewById(R.id.path);
        getDir(root);
    }

    private void getDir(String dirPath) {
        myPath.setText("Location: " + dirPath);
        item = new ArrayList<String>();
        path = new ArrayList<String>();
        File f = new File(dirPath);
        File[] files = f.listFiles();
        if (!dirPath.equals(root)) {
            item.add(root);
            path.add(root);
            item.add("../");
            path.add(f.getParent());
        }
        for (int i = 0; i < files.length; i++) {
            File file = files[i];
            path.add(file.getPath());
            if (file.isDirectory())
                item.add(file.getName() + "/");
            else
                item.add(file.getName());
        }
        ArrayAdapter<String> fileList = new ArrayAdapter<String>(this,
                R.layout.row_item_filebrowser, item);
        setListAdapter(fileList);
    }

    File file;

    @Override
    protected void onListItemClick(ListView l, View v, int position, long id) {
        file = new File(path.get(position));
        if (file.isDirectory()) {
            if (file.canRead())
                getDir(path.get(position));
            else {
                new AlertDialog.Builder(this)
                        .setIcon(R.drawable.ic_launcher)
                        .setTitle("[" + file.getName() + "] folder can't be read!")
                        .setPositiveButton("OK", new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                            }
                        }).show();
            }
        } else {
            new AlertDialog.Builder(this)
                    .setIcon(R.drawable.ic_launcher)
                    .setTitle("Select")
            .setMessage("Select " + file.getName() + "to server ?")
                    .setPositiveButton("Select", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            Toast.makeText(
                                    FileBrowserActivity.this, "" + file.getAbsolutePath() + " iss selected ", Toast.LENGTH_SHORT)
                                    .show();
                        }
                    })
                    .setNegativeButton("No", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            dialog.dismiss();
                        }
                    }).show();
        }
    }


    public class Option implements Comparable<Option>{
        private String name;
        private String data;
        private String path;

        public Option(String n,String d,String p)
        {
            name = n;
            data = d;
            path = p;
        }
        public String getName()
        {
            return name;
        }
        public String getData()
        {
            return data;
        }
        public String getPath()
        {
            return path;
        }
        @Override
        public int compareTo(Option o) {
            if(this.name != null)
                return this.name.toLowerCase().compareTo(o.getName().toLowerCase());
            else
                throw new IllegalArgumentException();
        }
    }

}

//activity_filebrowser.xml
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical">

    <TextView
        android:id="@+id/path"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content" />

    <ListView
        android:id="@android:id/list"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:cacheColorHint="#B26B00"
        android:fadingEdge="none" />

    <TextView
        android:id="@android:id/empty"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="No Data" />
</LinearLayout>

//row_item_filebrowser.xml
1
2
3
4
5
6
7
8
<?xml version="1.0" encoding="utf-8"?>
<TextView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/rowtext" android:padding="10dp"
    android:background="#C0C0C0" android:textColor="#000"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:textSize="23sp" />
 

Sunday 1 May 2016

HB Blog 109: Content Assist - The Developer's Friend.

Android Studio and similar other IDE's provide various features to developers which make a comfort environment for them. Hence, it is called as Integrated Development Environment (IDE). More technical, an integrated development environment is a software application that provides comprehensive facilities to computer programmers for software development. One of the most helpful feature is the content assist.

Content/Code assist helps the developer to write code faster and more efficiently. This is achieved by simplifying the task of coding to allow it to focus on the business task being coded. Based on the context of the code, content assist provides the developer with a list of accessible keywords according to a programming language specification, variable, methods, data types.
Autocomplete: - Autocomplete, or word completion, is a feature in which an IDE predicts the rest of a word a user is typing.

For example, in an XML context, when the developer types an opening tag "<" he is offered a list of tags via autocomplete, contextualized following the DTD or XML schema of the document. As the developer types more letters, the offered choices are filtered to only retain the relevant completions. When the developer finally completes the tag, the editor automatically generates the closing tag.

Another example, a developer can just type in the first letter if lowercase and the uppercase letters from a type/variable name then press Ctrl+space to be offered all the choices that match the entered letters that are valid for the current context (class name, interface name, variable or field names).

Code snippet/templates: - Code snippets allow the developer to add a complex coding structure by typing a minimal amount of text. Code snippets can only be used in a valid context (statements snippets are only offered when you can insert statements).

Specifically, in Android Studio ctrl+space (content assist) does 50% work of the developer's work.
Android studio has few more interesting features as well which makes development pretty simple.

Refer below link to meet Android studio,
https://developer.android.com/studio/intro/index.html