Friday 15 September 2017

HB Blog 144: Basics Of Java Utils Classes Date, Calendar And SimpleDateFormat.

           I have been posting about various libraries and concepts that Android and other mobile technologies are using for applications. But, I have learn that we should never forget the basics and always understand it perfectly.
In this post, I will show how to work with java.util.Date, java.util.Calendar and
java.text.SimpleDateFormat.
The Calendar class is an abstract class that provides methods for converting between a specific instant in time and a set of calendar fields such as YEAR, MONTH, DAY_OF_MONTH, HOUR, and so on, and for manipulating the calendar fields, such as getting the date of the next week. An instant in time can be represented by a millisecond value that is an offset from the Epoch, January 1, 1970 00:00:00.000 GMT (Gregorian).
SimpleDateFormat is a concrete class for formatting and parsing dates in a locale-sensitive manner. It allows for formatting (date -> text), parsing (text -> date), and normalization. 
Refer the below link for complete sample code:-

Download Sample Code

Have a look on few code snippets,

//activity_main.xml
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ListView
        android:id="@+id/listview"
        android:layout_width="match_parent"
        android:scrollbars="none"
        android:divider="@android:color/white"
        android:layout_height="match_parent" />

</LinearLayout>

//rowitem_calender.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
25
26
27
28
29
30
31
32
33
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <TextView
        android:id="@+id/tv_date"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#ff9933"
        android:gravity="center"
        android:padding="5dp"
        android:textColor="@android:color/black"
        android:textStyle="bold" />
    <TextView
        android:id="@+id/tv_day"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@android:color/white"
        android:gravity="center"
        android:padding="5dp"
        android:textColor="@android:color/black"
        android:textStyle="bold" />
    <TextView
        android:id="@+id/tv_year"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#138808"
        android:gravity="center"
        android:padding="5dp"
        android:textColor="@android:color/black"
        android:textStyle="bold" />
</LinearLayout>

//CalenderListAdapter.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
import android.content.Context;
import android.graphics.Color;
import android.support.v4.util.ArrayMap;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
import com.harshalbenake.calenderdates.R;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;

public class CalenderListAdapter extends BaseAdapter {
        private Context mContext;
        private String[] mDateArray,mDayArray,mYearArray;

        public CalenderListAdapter(Context context) {
            this.mContext = context;


            Calendar calendar = Calendar.getInstance();
            SimpleDateFormat simpleDateFormatDate = new SimpleDateFormat("dd");
            String[] dateArray = new String[365];

            for (int i = 0; i < 365; i++) {
                Date date = calendar.getTime ();
                // now format it using SimpleDateFormat
                String format = simpleDateFormatDate.format (date);
                dateArray[i] = format;
                calendar.add (Calendar.DAY_OF_WEEK, 1);
            }

            SimpleDateFormat simpleDateFormatDay = new SimpleDateFormat("MMM");
            String[] dayArray = new String[365];

            for (int i = 0; i < 365; i++) {
                Date date = calendar.getTime ();
                // now format it using SimpleDateFormat
                String format = simpleDateFormatDay.format (date);
                dayArray[i] = format;
                calendar.add (Calendar.DAY_OF_WEEK, 1);
            }

            SimpleDateFormat simpleDateFormatYear = new SimpleDateFormat("yyyy");
            String[] yearArray = new String[365];

            for (int i = 0; i < 365; i++) {
                Date date = calendar.getTime ();
                // now format it using SimpleDateFormat
                String format = simpleDateFormatYear.format (date);
                yearArray[i] = format;
                calendar.add (Calendar.DAY_OF_WEEK, 1);
            }


            this.mDateArray = dateArray;
            this.mDayArray = dayArray;
            this.mYearArray = yearArray;
        }

        @Override
        public int getCount() {
            return mDateArray.length;
        }

        @Override
        public Object getItem(int position) {
            return null;
        }

        @Override
        public long getItemId(int position) {
            return 0;
        }

        @Override
        public View getView(final int position, View convertView, ViewGroup parent) {
            final ViewHolderItem viewHolder;
            if (convertView == null) {
                // inflate the layout
                LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                convertView = inflater.inflate(R.layout.rowitem_calender, parent, false);
                viewHolder = new ViewHolderItem();
                viewHolder.tv_date = (TextView) convertView.findViewById(R.id.tv_date);
                viewHolder.tv_day = (TextView) convertView.findViewById(R.id.tv_day);
                viewHolder.tv_year = (TextView) convertView.findViewById(R.id.tv_year);
                convertView.setTag(viewHolder);
            } else {
                viewHolder = (ViewHolderItem) convertView.getTag();
            }

            viewHolder.tv_date.setText(mDateArray[position]);
            viewHolder.tv_day.setText(mDayArray[position]);
            viewHolder.tv_year.setText(mYearArray[position]);
            return convertView;
        }

        private static class ViewHolderItem {
            TextView tv_date,tv_day,tv_year;
        }
}

//MainActivity.java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
package com.harshalbenake.calenderdates;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.ListView;

import com.harshalbenake.calenderdates.adapter.CalenderListAdapter;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ListView listview=(ListView)findViewById(R.id.listview);
        CalenderListAdapter arrayAdapter = new CalenderListAdapter(MainActivity.this);
        listview.setAdapter(arrayAdapter);
    }
}

Friday 1 September 2017

HB Blog 143: Implementing Video Call using Sinch Android SDK.

Introduction

The Sinch SDK is a product that makes adding voice calling and/or instant messaging to mobile apps easy. It handles all the complexity of signalling and audio management while providing you the freedom to create a stunning user interface.
Refer the below link for complete sample code:-

Download Sample Code

First time setup

Below is a step-by-step guide on setting up the Sinch SDK for the first time.

Register an Application
1.    Register a Sinch Developer account at http://www.sinch.com/signup.
2.    Setup a new Application using the Dashboard where you can then obtain an Application Key and an Application Secret.

Download
The Sinch SDK can be downloaded at www.sinch.com/download/. It contains: the library aar, this user guide, reference documentation, and sample apps for calling and instant messaging.

Add the Sinch library
The Sinch SDK library is distributed in AAR format. To use it in your project choose File -> New -> New Module -> Import .JAR/.AAR Package option

Permissions
A minimum set of permissions are needed for the app to use the Sinch SDK. These are specified in the AndroidManifest.xml file. If the calling functionality will be used, all five permissions listed here are needed. However, if the calling functionality isn’t used, the last three (RECORD_AUDIO, MODIFY_AUDIO_SETTINGS and READ_PHONE_STATE) can be omitted.
1
2
3
4
5
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
Note: By default, the Sinch SDK hangs up any Sinch call if the regular phone app has an active call. This functionality requires the permission READ_PHONE_STATE. However, if this default functionality isn’t wanted, turn it off by calling sinchClient.getCallClient().setRespectNativeCalls(false); and the permission READ_PHONE_STATE is not needed.

Sinch client

The SinchClient is the Sinch SDK entry point. It is used to configure the user’s and device’s capabilities, as well as to provide access to feature classes such as the CallClient, MessageClient and AudioController.

Create a SinchClient
1
2
3
4
5
6
7
8
// Instantiate a SinchClient using the SinchClientBuilder.
android.content.Context context = this.getApplicationContext();
SinchClient sinchClient = Sinch.getSinchClientBuilder().context(context)
.applicationKey("<application key>")
.applicationSecret("<application secret>")
.environmentHost("sandbox.sinch.com")
.userId("<user id>")
.build();
The Application Key and Application Secret are obtained from the Sinch Developer Dashboard. The User ID should uniquely identify the user on the particular device.
Note: All listener callbacks emitted from the Sinch SDK are invoked on the same thread that the call to SinchClientBuilder.build is made on. If the invoking thread is not the main-thread, it needs to have an associated Looper.

Start the Sinch client
Before starting the client, add a client listener
1
2
3
4
5
6
7
8
sinchClient.addSinchClientListener(new SinchClientListener() {
public void onClientStarted(SinchClient client) { }
public void onClientStopped(SinchClient client) { }
public void onClientFailed(SinchClient client, SinchError error) { }
public void onRegistrationCredentialsRequired(SinchClient client, ClientRegistration registrationCallback) { }
public void onLogMessage(int level, String area, String message) { }
});
sinchClient.start();
Terminate the Sinch client
When the app is done using the SinchClient, it should be stopped. If the client is currently listening for incoming events, it needs to stop listening as well. After terminate is called, any object retrieved directly from the client object (that is, CallClient, MessageClient, and AudioController) is considered invalid.
Terminating the client:
1.    sinchClient.stopListeningOnActiveConnection();
2.    sinchClient.terminate();

Setting up a video call
Just like audio calls, video calls are placed through the CallClient and events are received using the CallClientListener. The call client is owned by the SinchClient and accessed using sinchClient.getCallClient(). Calling is not enabled by default. 

Showing the video streams
Once you have created a VideoCallListener and added it to a call, the onVideoTrackAdded() method will be called.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
@Override
public void onVideoTrackAdded(Call call) {
// Get a reference to your SinchClient, in the samples this is done through the service interface:
VideoController vc = getSinchServiceInterface().getVideoController();
View myPreview = vc.getLocalView();
View remoteView = vc.getRemoteView();
// Add the views to your view hierarchy
}

After the call has ended, dont forget to remove the views from your view hierarchy again.
@Override
public void onCallEnded(Call call) {
// Remove Sinch video views from your view hierarchy
}
Pausing video stream
To pause the local video stream, use the pauseVideo() method on the call.
1.        // User pause the video stream
2.        call.pauseVideo();

Resuming video stream
To resume the local video stream, use the resumeVideo() method on the call.
1.       // User resumes the video stream
2.       call.resumeVideo();

Pausing video stream delegates
Once you have created a VideoCallListener and added it to a call, the onVideoTrackPaused() method will be called when the remote user pause the video stream.
1.       @Override
2.       public void onVideoTrackPaused(Call call) {
3.            // Implement what to be done when remote user pause video stream.
4.       }

Resuming video stream delegates
Once you have created a VideoCallListener and added it to a call, the onVideoTrackResumed() method will be called when the remote user resumes the video stream..
1.       @Override
2.       public void onVideoTrackResumed(Call call) {
3.            // Implement what to be done when remote user resumes video stream.
4.       }

Video content fitting and aspect ratio
How the remote video stream is fitted into a view can be controller by the setResizeBehaviour() method with possible arguments VideoScalingType.ASPECT_FIT, VideoScalingType.ASPECT_FILL and VideoScalingType.ASPECT_BALANCED. The local preview will always use VideoScalingType.ASPECT_FIT.

Switching capturing device
The capturing device can be switched using videoController.setCaptureDevicePosition(int facing) with possible values Camera.CameraInfo.CAMERA_FACING_FRONT and Camera.CameraInfo.CAMERA_FACING_BACK. Use videoController.toggleCaptureDevicePosition() to alternate the two.

Accessing video frames of the remote streams
The Sinch SDK can provide access to raw video frames via a callback function. This callback can be used to achieve rich functionality such as applying filters, adding stickers to the video frames, or saving the video frame as an image.
Your video frame handler needs to implement VideoFrameListener interface by implementing the onFrame() callback. Note that it is important to explicitly release the video frame by calling release().
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
Example:
import com.sinch.android.rtc.video.VideoFrame;
import com.sinch.android.rtc.video.VideoFrameListener;
public class YourVideoFrameHandler implements VideoFrameListener {
public synchronized void onFrame(String callId, VideoFrame videoFrame) {
// Process videoFrame
videoFrame.release(); // Release videoFrame}}

Use setVideoFrameListener() to register your video frame handler as the callback to receive video frames.

Example:
YourVideoFrameHandler videoFrameHandler = new YourVideoFrameHandler();
VideoController vc = getSinchServiceInterface().getVideoController();
vc.setVideoFrameListener(videoFrameHandler);