Showing posts with label AsyncTask. Show all posts
Showing posts with label AsyncTask. Show all posts

Thursday, 14 June 2018

HB Blog 156: Secure Communication For OkHttpClient Web-service API.

In cryptography, encryption is the process of encoding messages or information in such a way that only authorized parties can read it. We have seen this in my old blog HB Blog 41: Encryption And Decryption Process Of String. In that post we saw how to encrypt a string, lets see how to do similar process with web service for secure communication.
Here, we will use  java.security package for AES - 256 encryption and decryption during webservice call with OkHttpClient,
Refer the below link for complete sample code:-

Download Sample Code

Have a look on few code snippets,

//EncryptionUtility.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
package com.harshalbenake.apiencryptionaes;

import android.util.Base64;
import android.util.Log;

import java.io.UnsupportedEncodingException;
import java.security.GeneralSecurityException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

/**
 * Encrypt and decrypt messages using AES 256 bit encryption that are compatible with AESCrypt-ObjC and AESCrypt Ruby.
 */
public final class EncryptionUtility {
    //AESCrypt-ObjC uses CBC and PKCS7Padding
    private static final String AES_MODE = "AES/CBC/ISO10126Padding";
    private static final String CHARSET = "UTF-8";

    /**
     * Encrypt and encode message using 256-bit AES with key generated from password.
     *
     * @param key     : secrete key
     * @param message the thing you want to encrypt assumed String UTF-8
     * @return Base64 encoded CipherText
     * @throws GeneralSecurityException if problems occur during encryption
     */
    public static String encrypt(final String key, String message, String IV)
            throws GeneralSecurityException {
        try {
            byte[] ivBytes = IV.getBytes();
            byte[] keyBytes = key.getBytes("UTF-8");

            final SecretKeySpec secreteKey = new SecretKeySpec(keyBytes, "AES");
            byte[] cipherText = encrypt(secreteKey, ivBytes, message.getBytes(CHARSET));
            String encoded = Base64.encodeToString(cipherText, Base64.NO_WRAP);

            return encoded;
        } catch (UnsupportedEncodingException e) {
            throw new GeneralSecurityException(e);
        }
    }


    /**
     * More flexible AES encrypt that doesn't encode
     *
     * @param key     AES key typically 128, 192 or 256 bit
     * @param iv      Initiation Vector
     * @param message in bytes (assumed it's already been decoded)
     * @return Encrypted cipher text (not encoded)
     * @throws GeneralSecurityException if something goes wrong during encryption
     */
    public static byte[] encrypt(final SecretKeySpec key, final byte[] iv, final byte[] message)
            throws GeneralSecurityException {
        byte[] cipherText = new byte[0];
        try {
            final Cipher cipher = Cipher.getInstance(AES_MODE);
            IvParameterSpec ivSpec = new IvParameterSpec(iv);
            cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec);
            cipherText = cipher.doFinal(message);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return cipherText;
    }

    /**
     * Decrypt and decode ciphertext using 256-bit AES with key generated from password
     *
     * @param key
     * @param base64EncodedCipherText the encrpyted message encoded with base64
     * @return message in Plain text (String UTF-8)
     * @throws GeneralSecurityException if there's an issue decrypting
     */
    public static String decrypt(final String key, String base64EncodedCipherText, String IV)
            throws GeneralSecurityException {

        try {
            byte[] ivBytes = IV.getBytes();
            byte[] keyBytes = key.getBytes("UTF-8");

            final SecretKeySpec secretKey = new SecretKeySpec(keyBytes, "AES");
            byte[] decodedCipherText = Base64.decode(base64EncodedCipherText, Base64.NO_WRAP);
            byte[] decryptedBytes = decrypt(secretKey, ivBytes, decodedCipherText);
            String message = new String(decryptedBytes, CHARSET);

            return message;
        } catch (UnsupportedEncodingException e) {
            throw new GeneralSecurityException(e);
        } catch (Exception e) {
            System.out.println(" Sys : " + e);
            throw new RuntimeException(e);
        }
    }


    /**
     * More flexible AES decrypt that doesn't encode
     *
     * @param key               AES key typically 128, 192 or 256 bit
     * @param iv                Initiation Vector
     * @param decodedCipherText in bytes (assumed it's already been decoded)
     * @return Decrypted message cipher text (not encoded)
     * @throws GeneralSecurityException if something goes wrong during encryption
     */
    public static byte[] decrypt(final SecretKeySpec key, final byte[] iv, final byte[] decodedCipherText)
            throws GeneralSecurityException {
        final Cipher cipher = Cipher.getInstance(AES_MODE);
        IvParameterSpec ivSpec = new IvParameterSpec(iv);
        cipher.init(Cipher.DECRYPT_MODE, key, ivSpec);
        byte[] decryptedBytes = cipher.doFinal(decodedCipherText);
        return decryptedBytes;
    }
}

//OKHTTPService.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
package com.harshalbenake.apiencryptionaes;

import android.util.ArrayMap;
import android.util.Log;

import java.util.Arrays;
import java.util.HashMap;
import java.util.concurrent.TimeUnit;

import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Protocol;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okhttp3.logging.HttpLoggingInterceptor;

/**
 * This class is used fto get and post service response to server using okhttp.
 */
public class OKHTTPService {
    public static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
    public static final String mStrUrl="Url";
    public static final String mStrRequestJson="RequestJson";
    public static final String mStrRequestEncoded="RequestEncoded";
    public static final String mStrResponseEncoded="ResponseEncoded";
    public static final String mStrResponseJson="ResponseJson";


    public OKHTTPService() {
    }

    /**
     * gets Ok Http Service
     *
     * @param strUrl
     * @param strJson
     * @return
     */
    public static HashMap<String,String> requestACallToServer(String strUrl, String strJson) {
        HashMap<String,String> hashMap=new HashMap<String, String>();
        try {
            System.out.println("OkHttp get Request: " + strJson);
            String strEncodedRequest = EncryptionUtility.encrypt("YourKey",strJson, "YourKey");            System.out.println("OkHttp get EncodedRequest: " + strEncodedRequest);
            RequestBody body = RequestBody.create(JSON, strEncodedRequest);
            Request request = new Request.Builder()
                    .url(strUrl)
                    .post(body)
                    .build();
            OkHttpClient.Builder builder = new OkHttpClient.Builder().protocols(Arrays.asList(Protocol.HTTP_1_1));
            builder.connectTimeout(3, TimeUnit.MINUTES)
                    .writeTimeout(3, TimeUnit.MINUTES)
                    .readTimeout(3, TimeUnit.MINUTES);
            HttpLoggingInterceptor logging = new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {
                @Override
                public void log(String message) {
                    Log.d("HttpLogging", message);
                }
            });
            logging.setLevel(HttpLoggingInterceptor.Level.BODY);
            OkHttpClient okHttpClient = new OkHttpClient.Builder()
                    .protocols(Arrays.asList(Protocol.HTTP_1_1))
                    .addInterceptor(logging)
                    .connectTimeout(3, TimeUnit.MINUTES)
                    .writeTimeout(3, TimeUnit.MINUTES)
                    .readTimeout(3, TimeUnit.MINUTES)
                    .build();
            Response response = okHttpClient.newCall(request).execute();
            String strEncodedResponse = response.body().string();
            System.out.println("OkHttp get EncodedResponse: " + strEncodedResponse);
            String strResponse = EncryptionUtility.decrypt("YourKey", strEncodedResponse, "YourKey");            System.out.println("OkHttp get Response: " + strResponse);
            hashMap.put(mStrUrl,strUrl);
            hashMap.put(mStrRequestJson,strJson);
            hashMap.put(mStrRequestEncoded,strEncodedRequest);
            hashMap.put(mStrResponseEncoded,strEncodedResponse);
            hashMap.put(mStrResponseJson,strResponse.replaceAll("\\r\\n", ""));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return hashMap;
    }
}

//DataService.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
package com.harshalbenake.apiencryptionaes;

import android.app.ProgressDialog;
import android.content.Context;
import android.os.AsyncTask;
import android.widget.Toast;

import java.util.HashMap;

/**
 * Data Service AsyncTask
 */
public class DataService extends AsyncTask<String, String, HashMap<String, String>> {
    MainActivity mContext;
    private ProgressDialog mProgressDialog;

    public DataService(MainActivity context) {
            this.mContext = context;
    }

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        if (NetworkUtility.isOnline(mContext)) {
            mProgressDialog = new ProgressDialog(mContext);
            mProgressDialog.setMessage("Loading...");
            mProgressDialog.setCancelable(false);
            mProgressDialog.setCanceledOnTouchOutside(false);
            mProgressDialog.show();
        } else {
            Toast.makeText(mContext, "Not connected to Internet", Toast.LENGTH_SHORT).show();
            cancel(true);
        }
    }

    @Override
    protected HashMap<String, String> doInBackground(String... params) {
        HashMap<String, String> hashMap=null;
        if (!isCancelled()) {
            try {
                String strUrl ="xxxURLxxx";
                String strJsonData="xxxJsonDataxxx";
                 hashMap = OKHTTPService.requestACallToServer(strUrl,strJsonData.toString());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return hashMap;
    }

    @Override
    protected void onPostExecute(HashMap<String, String> resultMap) {
        super.onPostExecute(resultMap);
        try {
            if (mProgressDialog != null && mProgressDialog.isShowing() == true) {
                mProgressDialog.dismiss();
            }
            if(resultMap!=null && resultMap.size()>0){
                mContext.mtv_url.setText(OKHTTPService.mStrUrl+": "+resultMap.get(OKHTTPService.mStrUrl)+"\n");
                mContext.mtv_requestjson.setText(OKHTTPService.mStrRequestJson+": "+resultMap.get(OKHTTPService.mStrRequestJson)+"\n");
                mContext.mtv_requestencoded.setText(OKHTTPService.mStrRequestEncoded+": "+resultMap.get(OKHTTPService.mStrRequestEncoded)+"\n");
                mContext.mtv_responsencoded.setText(OKHTTPService.mStrResponseEncoded+": "+resultMap.get(OKHTTPService.mStrResponseEncoded)+"\n");
                mContext.mtv_responsejson.setText(OKHTTPService.mStrResponseJson+": "+resultMap.get(OKHTTPService.mStrResponseJson)+"\n");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

Saturday, 16 July 2016

HB Blog 115: Chat Head Floating View Tutorial.

Android is an open source mobile operating system so, it can be modified it as per the needs.
Android SDK provides us with few in-built component views but, we need our own custom UI views for Android users.
Recently, Facebook came up with an attractive chat head UI view.
In this post, I will show how to create similar view that will run in background using our Android services and drag and drop events.
Refer the below link for complete sample code:-

Download Sample Code

Have a look on few code snippets,

//MainActivity.java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class MainActivity extends Activity {
    Button startService,stopService;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        startService=(Button)findViewById(R.id.startService);
        stopService=(Button)findViewById(R.id.stopService);
        startService.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                startService(new Intent(getApplication(), ChatHeadService.class));
            }
        });
        stopService.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                stopService(new Intent(getApplication(), ChatHeadService.class));
            }
        });}}

//ChatHeadService.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
import android.app.Service;
import android.content.Intent;
import android.graphics.PixelFormat;
import android.os.IBinder;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.Toast;

/**
 * Created by harshal.benake on 08-09-2015.
 */
public class ChatHeadService extends Service {

    private WindowManager windowManager;
    private ImageView chatHead;
    WindowManager.LayoutParams params;

    @Override
    public void onCreate() {
        super.onCreate();

        windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);

        chatHead = new ImageView(this);
        chatHead.setImageResource(R.drawable.ic_launcher);
        params= new WindowManager.LayoutParams(
                WindowManager.LayoutParams.WRAP_CONTENT,
                WindowManager.LayoutParams.WRAP_CONTENT,
                WindowManager.LayoutParams.TYPE_PHONE,
                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
                PixelFormat.TRANSLUCENT);

        params.gravity = Gravity.TOP | Gravity.LEFT;
        params.x = 0;
        params.y = 100;

        //this code is for dragging the chat head
        chatHead.setOnTouchListener(new View.OnTouchListener() {
            private int initialX;
            private int initialY;
            private float initialTouchX;
            private float initialTouchY;

            @Override
            public boolean onTouch(View v, MotionEvent event) {
                switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                        initialX = params.x;
                        initialY = params.y;
                        initialTouchX = event.getRawX();
                        initialTouchY = event.getRawY();
                        Toast.makeText(getApplicationContext(),"Comming soon",Toast.LENGTH_SHORT).show();
                        return true;
                    case MotionEvent.ACTION_UP:
                        return true;
                    case MotionEvent.ACTION_MOVE:
                        params.x = initialX+ (int) (event.getRawX() - initialTouchX);
                        params.y = initialY  + (int) (event.getRawY() - initialTouchY);
                        windowManager.updateViewLayout(chatHead, params);
                        return true;
                }
                return false;
            }
        });
        windowManager.addView(chatHead, params);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        if (chatHead != null)
            windowManager.removeView(chatHead);
    }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO Auto-generated method stub
        return null;
    }
}
 
//AndroidManifest.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"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.chathead_as" >
    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <service android:name=".ChatHeadService" >
        </service>
    </application>

</manifest>

Friday, 26 December 2014

HB Blog 49: Android - AsyncTask VS Handlers VS Threads.


Threads:
A Thread is a concurrent unit of execution. It has its own call stack for methods being invoked, their arguments and local variables. Each application has at least one thread running when it is started, the main thread, in the main ThreadGroup. The runtime keeps its own threads in the system thread group.
There are two ways to execute code in a new thread. You can either subclass Thread and overriding its run() method, or construct a new Thread and pass a Runnable to the constructor. In either case, the start() method must be called to actually execute the new Thread.
Each Thread has an integer priority that affect how the thread is scheduled by the OS. A new thread inherits the priority of its parent. A thread's priority can be set using the setPriority(int) method.

Handlers:
A Handler allows you to send and process Message and Runnable objects associated with a thread's MessageQueue. Each Handler instance is associated with a single thread and that thread's message queue. When you create a new Handler, it is bound to the thread / message queue of the thread that is creating it -- from that point on, it will deliver messages and runnables to that message queue and execute them as they come out of the message queue.
There are two main uses for a Handler: (1) to schedule messages and runnables to be executed as some point in the future; and (2) to enqueue an action to be performed on a different thread than your own.
Scheduling messages is accomplished with the post(Runnable), postAtTime(Runnable, long), postDelayed(Runnable, long), sendEmptyMessage(int), sendMessage(Message), sendMessageAtTime(Message, long), and sendMessageDelayed(Message, long) methods. The post versions allow you to enqueue Runnable objects to be called by the message queue when they are received; the sendMessage versions allow you to enqueue a Message object containing a bundle of data that will be processed by the Handler's handleMessage(Message) method (requiring that you implement a subclass of Handler).
When posting or sending to a Handler, you can either allow the item to be processed as soon as the message queue is ready to do so, or specify a delay before it gets processed or absolute time for it to be processed. The latter two allow you to implement timeouts, ticks, and other timing-based behavior.
When a process is created for your application, its main thread is dedicated to running a message queue that takes care of managing the top-level application objects (activities, broadcast receivers, etc) and any windows they create. You can create your own threads, and communicate back with the main application thread through a Handler. This is done by calling the same post or sendMessage methods as before, but from your new thread. The given Runnable or Message will then be scheduled in the Handler's message queue and processed when appropriate.

AsyncTask:
AsyncTask enables proper and easy use of the UI thread. This class allows to perform background operations and publish results on the UI thread without having to manipulate threads and/or handlers.
AsyncTask is designed to be a helper class around Thread and Handler and does not constitute a generic threading framework. AsyncTasks should ideally be used for short operations (a few seconds at the most.) If you need to keep threads running for long periods of time, it is highly recommended you use the various APIs provided by the java.util.concurrent package such as Executor, ThreadPoolExecutor and FutureTask.
An asynchronous task is defined by a computation that runs on a background thread and whose result is published on the UI thread. An asynchronous task is defined by 3 generic types, called Params, Progress and Result, and 4 steps, called onPreExecute, doInBackground, onProgressUpdate and onPostExecute.