Introduction: Google have updated the policy in Google Developer Blog about user privacy and security. As per the policy, we must remove ...

Verify OTP without SMS permission in Android using Kotlin Verify OTP without SMS permission in Android using Kotlin

A blog about android developement

Introduction:

Google have updated the policy in Google Developer Blog about user privacy and security. As per the policy, we must remove SMS and Call Log permissions from manifest or else our app will be removed from google play store. But our app needs SMS permission for automatically authenticate app users. What is the solution?
Google offers an API named as SMS Retriever API to allow our app to read SMS without SMS permission and we need to follow a set of rules while formatting the verification message. In this article, we will learn how to use SMS Retriever API in Kotlin to read SMS and rules need to be followed. If you are new to Kotlin, read my previous articles to read Kotlin from scratch.

Verification Message Format:

We should follow the below rules while formatting verification message.

  1. Message should have maximum of 140 bytes length.
  2. Should start with “<#>”.
  3. Followed by OTP - One Time Pass (code/word).
  4. 11 character length hash for the app (it is generated by our app).
Example:
<#> Your Example App code is: 123ABC78 
FA+9qCX9VSu

Coding Part:

I have detailed the article as in the following steps.
Step 1: Creating New Project with Empty Activity.
Step 2: Setting up the Google Auth Libraries.
Step 3: Implementation of SMS Retriever API using Kotlin.

Step 1 - Creating a new project with Kotlin

  1. Open Android Studio and select "Create new project". 
  2. Name the project as per your wish and tick the "Kotlin checkbox support". 
  3. Then, select your Activity type (For Example - Navigation Drawer Activity, Empty Activity, etc.).
  4. Click the “Finish” button to create a new project in Android Studio.

Step 2: Setting up the Google Auth Libraries:

In this part, we will see how to setup the library for the project.

  1. Then add the following lines in app level build.gradle file to apply google services to your project.
    dependencies { 
       …
        implementation 'com.google.android.gms:play-services-base:11.6.0'
        implementation 'com.google.android.gms:play-services-auth-api-phone:11.6.0'
        …
    }
    
  2. Then click “Sync Now” to setup your project.
  3. Now the project is ready and no need to add any permissions in Manifest.

Step 3: Implementation of SMS Retriever API using Kotlin:

Create user interface to display your OTP read through the API. Open or create “activity_main.xml” and paste the following code snippet.

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 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"
    tools:context="com.androidmad.smsretrieverapisample.MainActivity">

    <EditText
        android:id="@+id/editText"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginLeft="20dp"
        android:layout_marginRight="20dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:onClick="onBtnResendClick"
        android:id="@+id/btn_restart"
        android:text="Resend"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginLeft="20dp"
        android:layout_marginRight="20dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="@id/editText"
        app:layout_constraintVertical_bias="0.247" />

</android.support.constraint.ConstraintLayout>

We need to create a helper class to provide the hash value for our app to construct the verification message. Create a Kotlin class file named as “AppSignatureHelper.kt” and paste following code snippet which is helpful to create 11 character length hash for our application.

package com.androidmad.smsretrieverapisample

import android.annotation.SuppressLint
import android.content.Context
import android.content.ContextWrapper
import android.content.pm.PackageManager
import android.os.Build
import android.support.annotation.RequiresApi
import android.util.Base64
import android.util.Log
import java.nio.charset.StandardCharsets
import java.security.MessageDigest
import java.security.NoSuchAlgorithmException
import java.util.*

class AppSignatureHelper(context: Context) : ContextWrapper(context) {

    /**
     * Get all the app signatures for the current package
     *
     * @return
     */
    // Get all package signatures for the current package
    // For each signature create a compatible hash
    val appSignatures: ArrayList
        @SuppressLint("PackageManagerGetSignatures")
        @RequiresApi(api = Build.VERSION_CODES.KITKAT)
        get() {
            val appCodes = ArrayList()

            try {
                val packageName = packageName
                val packageManager = packageManager
                val signatures = packageManager.getPackageInfo(packageName,
                        PackageManager.GET_SIGNATURES).signatures
                signatures
                        .mapNotNull { hash(packageName, it.toCharsString()) }
                        .mapTo(appCodes) { String.format("%s", it) }
            } catch (e: PackageManager.NameNotFoundException) {
                Log.v(TAG, "Unable to find package to obtain hash.", e)
            }

            return appCodes
        }

    companion object {
        val TAG = AppSignatureHelper::class.java.simpleName!!
        private val HASH_TYPE = "SHA-256"
        private val NUM_HASHED_BYTES = 9
        private val NUM_BASE64_CHAR = 11

        @RequiresApi(api = Build.VERSION_CODES.KITKAT)
        private fun hash(packageName: String, signature: String): String? {
            val appInfo = packageName + " " + signature
            try {
                val messageDigest = MessageDigest.getInstance(HASH_TYPE)
                messageDigest.update(appInfo.toByteArray(StandardCharsets.UTF_8))
                var hashSignature = messageDigest.digest()

                // truncated into NUM_HASHED_BYTES
                hashSignature = Arrays.copyOfRange(hashSignature, 0, NUM_HASHED_BYTES)
                // encode into Base64
                var base64Hash = Base64.encodeToString(hashSignature, Base64.NO_PADDING or Base64.NO_WRAP)
                base64Hash = base64Hash.substring(0, NUM_BASE64_CHAR)

                Log.v(TAG + "sms_sample_test", String.format("pkg: %s -- hash: %s", packageName, base64Hash))
                return base64Hash
            } catch (e: NoSuchAlgorithmException) {
                Log.v(TAG + "sms_sample_test", "hash:NoSuchAlgorithm", e)
            }

            return null
        }
    }
}

Then we need to get the hash from the class by creating an object for the helper class and call the hash creation method which returns the value.

// This code requires one time to get Hash keys do comment and share key
val appSignature = AppSignatureHelper(this)
Log.v("AppSignature", appSignature.appSignatures.toString())

Then create a Custom BroadCastReceiver class named as “MySMSBroadcastReceiver.kt” and add the following code snippets.

class MySMSBroadcastReceiver : BroadcastReceiver() {

    private var otpReceiver: OTPReceiveListener? = null

    fun initOTPListener(receiver: OTPReceiveListener) {
        this.otpReceiver = receiver
    }

    override fun onReceive(context: Context, intent: Intent) {
        if (SmsRetriever.SMS_RETRIEVED_ACTION == intent.action) {
            val extras = intent.extras
            val status = extras!!.get(SmsRetriever.EXTRA_STATUS) as Status

            when (status.statusCode) {
                CommonStatusCodes.SUCCESS -> {
                    // Get SMS message contents
                    var otp: String = extras.get(SmsRetriever.EXTRA_SMS_MESSAGE) as String
                    Log.d("OTP_Message", otp)
                    // Extract one-time code from the message and complete verification
                    // by sending the code back to your server for SMS authenticity.
                    // But here we are just passing it to MainActivity
                    if (otpReceiver != null) {
                        otp = otp.replace("<#> ", "").split("\n".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()[0]
                        otpReceiver!!.onOTPReceived(otp)
                    }
                }

                CommonStatusCodes.TIMEOUT ->
                    // Waiting for SMS timed out (5 minutes)
                    // Handle the error ...
                    if (otpReceiver != null)
                        otpReceiver!!.onOTPTimeOut()
            }
        }
    }

    interface OTPReceiveListener {

        fun onOTPReceived(otp: String)

        fun onOTPTimeOut()
    }
}

Here, OTPReceiveListener is an interface used to call back the events from broad cast receiver. Then open your Activity and implement OTPReceiverListener.

Register the receiver in AndroidManifest.xml with SMS_RETRIEVED action.

<receiver android:name=".MySMSBroadcastReceiver" android:exported="true">
 <intent-filter>
  <action android:name="com.google.android.gms.auth.api.phone.SMS_RETRIEVED" />
 </intent-filter>
</receiver>

Then start the SmsRetriever API as shown in below. Also, register your broadcast receiver with SmsRetriever.SMS_RETRIEVED_ACTION using intent filter.

private fun startSMSListener() {
 try {
  smsReceiver = MySMSBroadcastReceiver()
  smsReceiver!!.initOTPListener(this)

  val intentFilter = IntentFilter()
  intentFilter.addAction(SmsRetriever.SMS_RETRIEVED_ACTION)
  this.registerReceiver(smsReceiver, intentFilter)

  val client = SmsRetriever.getClient(this)

  val task = client.startSmsRetriever()
  task.addOnSuccessListener {
   // API successfully started
  }

  task.addOnFailureListener {
   // Fail to start API
  }
 } catch (e: Exception) {
  e.printStackTrace()
 }

}
You will receive OTP in call back methods implemented in you Activity:
override fun onOTPReceived(otp: String) {
 //showToast("OTP Received: " + otp)
 editText.setText(otp)
 if (smsReceiver != null) {
  LocalBroadcastManager.getInstance(this).unregisterReceiver(smsReceiver)
 }
}

override fun onOTPTimeOut() {
 showToast("OTP Time out")
}

Full Code:

You can find the full code implementation of the Activity here.

class MainActivity : AppCompatActivity(), OTPReceiveListener {

    private var smsReceiver: MySMSBroadcastReceiver? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        startSMSListener()
    }


    /**
     * Starts SmsRetriever, which waits for ONE matching SMS message until timeout
     * (5 minutes). The matching SMS message will be sent via a Broadcast Intent with
     * action SmsRetriever#SMS_RETRIEVED_ACTION.
     */
    private fun startSMSListener() {
        try {
            smsReceiver = MySMSBroadcastReceiver()
            smsReceiver!!.initOTPListener(this)

            val intentFilter = IntentFilter()
            intentFilter.addAction(SmsRetriever.SMS_RETRIEVED_ACTION)
            this.registerReceiver(smsReceiver, intentFilter)

            val client = SmsRetriever.getClient(this)

            val task = client.startSmsRetriever()
            task.addOnSuccessListener {
                // API successfully started
            }

            task.addOnFailureListener {
                // Fail to start API
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }

    }

    fun onBtnResendClick(view: View){
        startSMSListener()
    }

    override fun onOTPReceived(otp: String) {
        //showToast("OTP Received: " + otp)
        editText.setText(otp)
        if (smsReceiver != null) {
            LocalBroadcastManager.getInstance(this).unregisterReceiver(smsReceiver)
        }
    }

    override fun onOTPTimeOut() {
        showToast("OTP Time out")
    }


    override fun onDestroy() {
        super.onDestroy()
        if (smsReceiver != null) {
            LocalBroadcastManager.getInstance(this).unregisterReceiver(smsReceiver)
        }
    }


    private fun showToast(msg: String) {
        Toast.makeText(this, msg, Toast.LENGTH_SHORT).show()
    }
}

Reference:

SMS Retriever API for Android https://developers.google.com/identity/sms-retriever/overview
Google Announcement on Security Policy https://android-developers.googleblog.com/2019/01/reminder-smscall-log-policy-changes.html

If you have any doubt or need any help, contact me.

Download Code:

You can download the full source code of the article in GitHub. If you like this article, do star the repo in GitHub. Hit like the article.

Introduction: In this article, we will learn how to create & use extensions for Android development using Kotlin. We have read abou...

How to use Extensions method in Kotlin How to use Extensions method in Kotlin

A blog about android developement


Introduction:

In this article, we will learn how to create & use extensions for Android development using Kotlin. We have read about Kotlin for Android development. If you are new to Kotlin, read my previous article on Kotlin.

Hello World Android Application Using Kotlin

Extensions:

Kotlin, similar to C# and Gosu, provides the ability to extend a class with new functionality without having to inherit from the class or use any type of design pattern such as Decorator. This is done via special declarations called extensions.

Coding Part:

I have detailed the article as in the following steps.

  1. Creating New Project with Kotlin
  2. Creating Extensions in Kotlin
  3. Implementation of Extension in Kotlin

Step 1 - Creating a new project with Kotlin

  1. Open Android Studio and select "Create new project". 
  2. Name the project as per your wish and tick the "Kotlin checkbox support". 
  3. Then, select your Activity type (For Example - Navigation Drawer Activity, Empty Activity, etc.).
  4. Click the “Finish” button to create a new project in Android Studio.

Step 2: Creating Extensions in Kotlin

In this part, we will see how to create an extensions for Kotlin.

  1. To declare an extensions function, we need to prefix its name with a receiver type, i.e. the type being extended. The following adds a swap function to MutableList
    fun MutableList<Int>.swap(index1: Int, index2: Int) {
        val tmp = this[index1] // 'this' corresponds to the list
        this[index1] = this[index2]
        this[index2] = tmp
    }
  2. We will take an example to show Toast with Short duration. Traditionally, the Toast is shown like below
    Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
  3. We can simplifies this by the using extensions in Kotlin.
  4. Create a Kotlin file named as “Extensions.kt”. Then add the following code part.
    fun Context.showShortToast(message: CharSequence) {
        Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
    }
    Here, the base or receiver type of toast is “Context”. So, we have created a function prefixed with “Context”.
  5. In the same way, I have created an extensions to show “Toast with Long duration” and “Alert Dialog with single option”. You can find the full code below.
    package com.androidmad.ktextensions
    
    import android.content.Context
    import android.support.v7.app.AlertDialog
    import android.support.v7.app.AppCompatActivity
    import android.view.View
    import android.widget.Toast
    
    fun Context.showShortToast(message: CharSequence) {
        Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
    }
    
    fun Context.showLongToast(message: CharSequence) {
        Toast.makeText(this, message, Toast.LENGTH_LONG).show()
    }
    
    fun AppCompatActivity.showAlert(title: CharSequence, message: CharSequence) {
        val builder = AlertDialog.Builder(this)
                .setTitle(title)
                .setMessage(message)
                .setPositiveButton("Ok", { dialog, which ->
                })
    
        val dialog: AlertDialog = builder.create()
        dialog.show()
    }

Step 3: Implementation of Extension in Kotlin

In this section, we will see how to call the above created extensions method in android.

  1. Create a layout file named as “activity_main.xml” and add the following code snippets.
    <?xml version="1.0" encoding="utf-8"?>
    <android.support.constraint.ConstraintLayout 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"
        tools:context="com.androidmad.ktextensions.MainActivity"
        tools:layout_editor_absoluteY="81dp">
    
        <Button
            android:id="@+id/btn_short"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="128dp"
            android:text="Show Short Toast"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
    
        <Button
            android:id="@+id/btn_long"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginBottom="208dp"
            android:text="Show Long Toast"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent" />
    
        <Button
            android:id="@+id/btn_alert"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginBottom="92dp"
            android:text="Show Alert Dialog"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent" />
    
    </android.support.constraint.ConstraintLayout>
  2. The output of the layout file looks like below
  3. We have three buttons in our screen to show Toast with Short duration, Long duration and Alert dialog with single option. Open your MainActivity.kt add click listeners for the buttons.
    // Toast with Short Duration
    showShortToast("Show Short Toast using extensions method")
    // Toast with Long Duration
    showLongToast("Show Long Toast using extensions method")
    // Alert Dialog with Single Option
    showAlert("Android Extensions method", "Show Alert Dialog")
  4. Full code of the MainActivity.kt below.
    package com.androidmad.ktextensions
    
    import android.support.v7.app.AppCompatActivity
    import android.os.Bundle
    import kotlinx.android.synthetic.main.activity_main.*
    
    class MainActivity : AppCompatActivity() {
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
    
            btn_short.setOnClickListener({
                showShortToast("Show Short Toast using extensions method")
            })
    
            btn_long.setOnClickListener({
                showLongToast("Show Long Toast using extensions method")
            })
    
            btn_alert.setOnClickListener({
                showAlert("Android Extensions method", "Show Alert Dialog")
            })
    
        }
    
    }

Reference:

Extensions in Kotlin https://kotlinlang.org/docs/reference/extensions.html

Download Code:

You can download the full source code of the article in GitHub. If you like this article, do star the repo in GitHub. Hit like the article.

Introduction In this article, we will learn how to create Dropdown in Xamarin.Forms. By default, Android Platform has dropdown called as...

Dropdown Control In Xamarin.Forms - Part One Dropdown Control In Xamarin.Forms - Part One

A blog about android developement



Introduction

In this article, we will learn how to create Dropdown in Xamarin.Forms. By default, Android Platform has dropdown called as “Spinner”, but iOS Platform has no dropdown like Android Spinner. In Xamarin.Forms, we have control called as Picker and we all heard about this. We are going to create a custom to achieve, the control like Android Spinner in Xamarin.Forms.

Dropdown in Xamarin.Forms

As per the introduction, we already having a dropdown control called as “Spinner” in Android Platform. Basically Xamarin.Forms control is a wrapper platform specific controls. For Example, Xamarin.Forms Entry is wrapper of EditText in Android and UITextField in iOS. We will go for View Renderer approach to have a new control to wrap a Platform specific control. Click the below link, to know more about view renderer.

Reference

https://docs.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/custom-renderer/view

Without much introduction, we will skip into the coding part of this article.

Coding Part:

Steps:

I have split this part into 3 steps as in the following.

  1. Creating new Xamarin.Forms Projects.
  2. Creating a Dropdown view in Xamarin.Forms .NetStandard Project.
  3. Wrapping Spinner for Dropdown control in Android Project.
  4. Implementation of Dropdown & It’s Demo for Android Platform.

Step 1: Creating new Xamarin.Forms Projects

Create New Project by Selecting New -> Project -> Select Xamarin Cross Platform App and Click OK.
Then Select Android and iOS Platforms as shown below with Code Sharing Strategy as PCL or .Net Standard and Click OK.

Step 2: Creating a Dropdown view in Xamarin.Forms .NetStandard Project

In this step, we will see how to create a dropdown view with required properties.

  1. Create a class named as “Dropdown” and inherit the Dropdown with “View”. That is Dropdown is child of View.
    public class Dropdown : View
    {
     //...
    }
  2. Then we will create a required bindable properties. First we will see, what are all the properties & events required for dropdown.
    1. ItemsSource – To assign the list of data to be populated in the dropdown.
    2. SelectedIndex – To identify the index of selected values from the ItemsSource.
    3. ItemSelected – Event for performing action when the item selected in the dropdown.
  3. Create a bindable property for the ItemsSource as shown in below.
    public static readonly BindableProperty ItemsSourceProperty = BindableProperty.Create(
     propertyName: nameof(ItemsSource),
     returnType: typeof(List<string>),
     declaringType: typeof(List<string>),
     defaultValue: null);
    
    public List<string> ItemsSource
    {
     get { return (List<string>)GetValue(ItemsSourceProperty); }
     set { SetValue(ItemsSourceProperty, value); }
    }
  4. Create a bindable property for the SelectedIndex as shown in below.
    public static readonly BindableProperty SelectedIndexProperty = BindableProperty.Create(
     propertyName: nameof(SelectedIndex),
     returnType: typeof(int),
     declaringType: typeof(int),
     defaultValue: -1);
    
    public int SelectedIndex
    {
     get { return (int)GetValue(SelectedIndexProperty); }
     set { SetValue(SelectedIndexProperty, value); }
    }
  5. Create a custom event ItemSelected for dropdown control and invoke the event as shown in below.
    public event EventHandler ItemSelected;
    
    public void OnItemSelected(int pos)
    {
     ItemSelected?.Invoke(this, new ItemSelectedEventArgs() { SelectedIndex = pos });
    }
  6. Here, ItemSelectedEventArgs is a child of EventArgs as shown in below.
    public class ItemSelectedEventArgs : EventArgs
    {
     public int SelectedIndex { get; set; }
    }
Full Code of Dropdown View

Here, we will see the full code for dropdown view.

namespace XF.Ctrls
{
    public class Dropdown : View
    {
        public static readonly BindableProperty ItemsSourceProperty = BindableProperty.Create(
            propertyName: nameof(ItemsSource),
            returnType: typeof(List<string>),
            declaringType: typeof(List<string>),
            defaultValue: null);

        public List<string> ItemsSource
        {
            get { return (List<string>)GetValue(ItemsSourceProperty); }
            set { SetValue(ItemsSourceProperty, value); }
        }

        public static readonly BindableProperty SelectedIndexProperty = BindableProperty.Create(
            propertyName: nameof(SelectedIndex),
            returnType: typeof(int),
            declaringType: typeof(int),
            defaultValue: -1);

        public int SelectedIndex
        {
            get { return (int)GetValue(SelectedIndexProperty); }
            set { SetValue(SelectedIndexProperty, value); }
        }

        public event EventHandler<ItemSelectedEventArgs> ItemSelected;

        public void OnItemSelected(int pos)
        {
            ItemSelected?.Invoke(this, new ItemSelectedEventArgs() { SelectedIndex = pos });
        }
    }

    public class ItemSelectedEventArgs : EventArgs
    {
        public int SelectedIndex { get; set; }
    }
}

Step 3: Wrapping Spinner for Dropdown control in Android Project.

In this step, we will see “How to wrap the Android Spinner Control for Dropdown View”.

  1. Create a class file named as “DropdownRenderer” in your android client project and add View Renderer as shown in below.
    public class DropdownRenderer : ViewRenderer<Dropdown, Spinner>
    {
     Spinner spinner;
     public DropdownRenderer(Context context) : base(context)
     {
    
     } 
     // ...
    }
  2. Then Override the methods “OnElementChanged” and “OnElementPropertyChanged”. OnElementChanged method is triggered on element/control initiation. OnElementPropertyChanged method is called when the element property changes.
  3. Set Native Control to ViewRenderer using SetNativeControl() method in OnElementChanged override method as shown in below.
    protected override void OnElementChanged(ElementChangedEventArgs<Dropdown> e)
    {
     base.OnElementChanged(e);
    
     if (Control == null)
     {
      spinner = new Spinner(Context);
      SetNativeControl(spinner);
     }
     //...
    }
  4. Set Items Source from Xamarin.Forms Dropdown to Android Spinner control using array adapter as shown in below.
    var view = e.NewElement;
    
    ArrayAdapter adapter = new ArrayAdapter(Context, Android.Resource.Layout.SimpleListItem1, view.ItemsSource);
    Control.Adapter = adapter;
    
  5. Set default selection of item from selected index as shown in below.
    if (view.SelectedIndex != -1)
    {
     Control.SetSelection(view.SelectedIndex);
    }
  6. Create an item selected event for spinner and invoke the dropdown event created as shown below
    // ...
    Control.ItemSelected += OnItemSelected;
    // ...
    private void OnItemSelected(object sender, AdapterView.ItemSelectedEventArgs e)
    {
     var view = Element;
     if (view != null)
     {
      view.SelectedIndex = e.Position;
      view.OnItemSelected(e.Position);
     }
    }
  7. In the same way, we will assign ItemsSource & SelectedIndex to Android Spinner when the property changes using OnElementPropertyChanged as shown below.
    protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
     var view = Element;
     if (e.PropertyName == Dropdown.ItemsSourceProperty.PropertyName)
     {
      ArrayAdapter adapter = new ArrayAdapter(Context, Android.Resource.Layout.SimpleListItem1, view.ItemsSource);
      Control.Adapter = adapter;
     }
     if (e.PropertyName == Dropdown.SelectedIndexProperty.PropertyName)
     {
      Control.SetSelection(view.SelectedIndex);
     }
     base.OnElementPropertyChanged(sender, e);
    }
  8. Add Export Renderer above the namespace to link dropdown view in .NetStandard project to Android Client Project. This is very important step for any custom renderer approach.
    [assembly: ExportRenderer(typeof(Dropdown), typeof(DropdownRenderer))]
    namespace XF.Ctrls.Droid
Full Code of Dropdown Renderer

Here, we will see the full code for Dropdown Renderer.

[assembly: ExportRenderer(typeof(Dropdown), typeof(DropdownRenderer))]
namespace XF.Ctrls.Droid
{
    public class DropdownRenderer : ViewRenderer<Dropdown, Spinner>
    {
        Spinner spinner;
        public DropdownRenderer(Context context) : base(context)
        {

        }

        protected override void OnElementChanged(ElementChangedEventArgs<Dropdown> e)
        {
            base.OnElementChanged(e);

            if (Control == null)
            {
                spinner = new Spinner(Context);
                SetNativeControl(spinner);
            }

            if (e.OldElement != null)
            {
                Control.ItemSelected -= OnItemSelected;
            }
            if (e.NewElement != null)
            {
                var view = e.NewElement;

                ArrayAdapter adapter = new ArrayAdapter(Context, Android.Resource.Layout.SimpleListItem1, view.ItemsSource);
                Control.Adapter = adapter;

                if (view.SelectedIndex != -1)
                {
                    Control.SetSelection(view.SelectedIndex);
                }

                Control.ItemSelected += OnItemSelected;
            }
        }

        protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            var view = Element;
            if (e.PropertyName == Dropdown.ItemsSourceProperty.PropertyName)
            {
                ArrayAdapter adapter = new ArrayAdapter(Context, Android.Resource.Layout.SimpleListItem1, view.ItemsSource);
                Control.Adapter = adapter;
            }
            if (e.PropertyName == Dropdown.SelectedIndexProperty.PropertyName)
            {
                Control.SetSelection(view.SelectedIndex);
            }
            base.OnElementPropertyChanged(sender, e);
        }

        private void OnItemSelected(object sender, AdapterView.ItemSelectedEventArgs e)
        {
            var view = Element;
            if (view != null)
            {
                view.SelectedIndex = e.Position;
                view.OnItemSelected(e.Position);
            }
        }
    }
}

Step 4: Implementation of Dropdown & It’s Demo for Android Platform

In this step, we will see how to use the view in Xamarin.Forms.

  1. Open your designer file and in my case MainPage.xaml and add the control as shown below.
    <local:Dropdown HorizontalOptions="FillAndExpand"
          VerticalOptions="Center"
          BackgroundColor="LawnGreen"
          x:Name="dropdown"/>
  2. Set ItemsSource and SelectedIndex as shown in below.
    dropdown.ItemsSource = Items1;
    dropdown.SelectedIndex = 1;
  3. Add item selection event to dropdown as shown in below.
    public MainPage()
    {
     //...
     dropdown.ItemSelected += OnDropdownSelected;
    }
    
    private void OnDropdownSelected(object sender, ItemSelectedEventArgs e)
    {
     label.Text = Items1[e.SelectedIndex];
    }
Full Code implementation of Dropdown in MainPage

Here, we will see the full code for Main Page.

namespace XF.Ctrls
{
    public partial class MainPage : ContentPage
    {
        List<string> Items1 = new List<string>();
        List<string> Items2 = new List<string>();
        bool IsItem1 = true;

        public MainPage()
        {
            InitializeComponent();

            for (int i = 0; i < 4; i++)
            {
                Items1.Add(i.ToString());
            }

            for (int i = 0; i < 10; i++)
            {
                Items2.Add(i.ToString());
            }

            dropdown.ItemsSource = Items1;
            dropdown.SelectedIndex = 1;
            dropdown.ItemSelected += OnDropdownSelected;
        }

        private void OnDropdownSelected(object sender, ItemSelectedEventArgs e)
        {
            label.Text = IsItem1 ? Items1[e.SelectedIndex] : Items2[e.SelectedIndex];
        }

        private void btn_Clicked(object sender, EventArgs e)
        {
            dropdown.ItemsSource = IsItem1 ? Items2 : Items1;
            dropdown.SelectedIndex = IsItem1 ? 5 : 1;
            IsItem1 = !IsItem1;
        }
    }
}

Demo

The following screens shows the output this tutorial and it is awesome to have this dropdown in Xamarin.Forms.

This article covers the implementation of new dropdown control in Android Platform alone. Currently, I am working on creating spinner like dropdown control in iOS Platform and will post the article about the implementation of the dropdown in iOS Platform soon.

My plan is to create a dropdown control for supporting all platforms and offering this control as a standard plugin.

Download Code

You can download the code from GitHub. If you have doubt, feel free to post comment. If you like this article and is useful to you, do like, share the article & star the repository on GitHub.


Introduction: In this tutorial, we will learn how to use FlowListView in Xamarin.Forms to create GridView. FlowListView is an awesome p...

Grid View in Xamarin.Forms using FlowListView Grid View in Xamarin.Forms using FlowListView

A blog about android developement


Introduction:

In this tutorial, we will learn how to use FlowListView in Xamarin.Forms to create GridView. FlowListView is an awesome plugin facilitates developer to achieve features like infinite loading, Item Tapped Command, Item appearing event, item disappearing event and more.

Coding Part:

Steps:

I have split this part into 3 steps as in the following.

  1. Creating new Xamarin.Forms Projects.
  2. Setting up the plugin for Xamarin.Forms Application.
  3. Implementing GridView with FlowListView.

Step 1: Creating new Xamarin.Forms Projects

Create New Project by Selecting New -> Project -> Select Xamarin Cross Platform App and Click OK.
Then Select Android and iOS Platforms as shown below with Code Sharing Strategy as PCL or .Net Standard and Click OK.

Step 2: Setting up the plugin for Xamarin.Forms Application

Open Nuget Package Manager against the solution and do search for FlowListView Plugin or Paste the following Nuget package.
Install-Package DLToolkit.Forms.Controls.FlowListView -Version 2.0.11

Click Install to install this Plugin against your PCL Project or .NET standard Project.

We need to install this application in all client projects.

Step 3: Implementing GridView with FlowListView

  1. Open “App.xaml.cs” or “App.cs” and add the following line after InitializeComponent function.
    public App()
    {
       InitializeComponent();
       FlowListView.Init();
       MainPage = new MainPage();
    }
  2. Open your Page for example “MainPage” and add the flowlistview reference in designer as like below.
    …
    xmlns:flv="clr-namespace:DLToolkit.Forms.Controls;assembly=DLToolkit.Forms.Controls.FlowListView"
    …
  3. Implement the flowlistview like below.
    <flv:FlowListView FlowColumnCount="3" 
                    SeparatorVisibility="Default" 
                    HasUnevenRows="True"
                    FlowItemTappedCommand="{Binding ItemTappedCommand}" 
                    FlowItemsSource="{Binding Items}">
    
        <flv:FlowListView.FlowColumnTemplate>
            <DataTemplate>
                <Frame BackgroundColor="Purple"
                    Margin="5">
                    <Label HorizontalOptions="Fill" 
                        VerticalOptions="Fill" 
                        TextColor="White"
                        XAlign="Center"
                        YAlign="Center" 
                        Text="{Binding }"/>
                </Frame>
            </DataTemplate>
        </flv:FlowListView.FlowColumnTemplate>
    </flv:FlowListView>
  4. Then create a ViewModel for your Page and in my case I have created a class named as “MainPageModel.cs” and inherits the class with BindableObject.
    public class MainPageModel : BindableObject
    {
     …
    }
  5. Then add the view model to your page like below
    public partial class MainPage : ContentPage
    {
        MainPageModel pageModel;
        public MainPage()
        {
            InitializeComponent();
            pageModel = new MainPageModel(this);
            BindingContext = pageModel;
        }
    }

Full Code:

MainPage.xaml
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:flv="clr-namespace:DLToolkit.Forms.Controls;assembly=DLToolkit.Forms.Controls.FlowListView"
             x:Class="FlowListViewSample.MainPage">

    <StackLayout Padding="10">
        <flv:FlowListView FlowColumnCount="3" 
                SeparatorVisibility="Default" 
                HasUnevenRows="True"
                FlowItemTappedCommand="{Binding ItemTappedCommand}" 
                FlowItemsSource="{Binding Items}">

            <flv:FlowListView.FlowColumnTemplate>
                <DataTemplate>
                    <Frame BackgroundColor="Purple"
                Margin="5">
                        <Label HorizontalOptions="Fill" 
                    VerticalOptions="Fill" 
                    TextColor="White"
                    XAlign="Center"
                    YAlign="Center" 
                    Text="{Binding }"/>
                    </Frame>
                </DataTemplate>
            </flv:FlowListView.FlowColumnTemplate>
        </flv:FlowListView>
    </StackLayout>

</ContentPage>
MainPage.xaml.cs
using Xamarin.Forms;

namespace FlowListViewSample
{
    public partial class MainPage : ContentPage
    {
        MainPageModel pageModel;
        public MainPage()
        {
            InitializeComponent();
            pageModel = new MainPageModel(this);
            BindingContext = pageModel;
        }
    }
}
MainPageModel.cs
using System.Collections.ObjectModel;
using Xamarin.Forms;

namespace FlowListViewSample
{
    public class MainPageModel : BindableObject
    {
        private MainPage mainPage;

        public MainPageModel(MainPage mainPage)
        {
            this.mainPage = mainPage;
            AddItems();
        }

        private void AddItems()
        {
            for (int i = 0; i < 20; i++)
                Items.Add(string.Format("List Item at {0}", i));
        }

        private ObservableCollection _items = new ObservableCollection();
        public ObservableCollection Items
        {
            get
            {
                return _items;
            }
            set
            {
                if (_items != value)
                {
                    _items = value;
                    OnPropertyChanged(nameof(Items));
                }
            }
        }

        public Command ItemTappedCommand
        {
            get
            {
                return new Command((data) =>
                {
                    mainPage.DisplayAlert("FlowListView", data + "", "Ok");
                });
            }
        }
    }
}

Demo:

Reference

FlowListView for Xamarin.Forms https://github.com/daniel-luberda/DLToolkit.Forms.Controls/tree/master/FlowListView/

Download Code

You can download the code from GitHub. If you have doubt, feel free to post comment. If you like this article and is useful to you, do like, share the article & star the repository on GitHub.

Introduction: In this tutorial, we will learn how to use extension methods with Linq in C# to simplify the coding. Extension Methods are...

How to use Extensions for Linq – C# How to use Extensions for Linq – C#

A blog about android developement


Introduction:

In this tutorial, we will learn how to use extension methods with Linq in C# to simplify the coding. Extension Methods are a new feature in C# 3.0 and is nothing but a user made pre-defined functions. An Extension Method enables us to add methods to existing types without creating a new derived type, recompiling, or modify the original types.

Extension Methods:

  1. It enable us to add methods to existing types without creating a new derived type.
  2. It is a static method.
  3. It is defined in a static class.
  4. It uses “this” keyword to apply the extension to the particular type.
  5. We don’t want to compile the application. Visual Studio intelli-sense will find the extension method immediately.

Coding Part:

  1. I have created a Console application by selecting File->New Project->Console Application.
  2. Then created a Model class “Employee.cs” with member variables like below.
    public class Employee
    {
     public string Name { get; set; }
     public string MobileNo { get; set; }
     public string Salary { get; set; }
    
     public string String()
     {
      return string.Format("Name:{0} MobileNo:{1} Salary:{2}", Name, MobileNo, Salary);
     }
    }
  3. Then added values to employee list as like below
    static void AddEmployees()
    {
     employees.Add(new Employee() { Name = "Mushtaq", MobileNo = "9876543210", Salary = "20K" });
     employees.Add(new Employee() { Name = "Mohammed Mushtaq", MobileNo = "9876543211", Salary = "30K" });
     employees.Add(new Employee() { Name = "Mushtaq Ahmed", MobileNo = "9876543212", Salary = "20K" });
     employees.Add(new Employee() { Name = "Raj", MobileNo = "9876543213", Salary = "25K" });
    }
  4. Now we will get results from list using Linq for “FirstOrDefault”, “LastOrDefault” or “IndexOf”.
    Console.WriteLine(employees.Where(x => x.Name.Contains("Mushtaq")).FirstOrDefault().String());
    Console.WriteLine(employees.Where(x => x.Name.Contains("Mushtaq")).LastOrDefault().String());
    Console.WriteLine(employees.IndexOf(employees.Where(x => x.Name.Contains("Mushtaq")).FirstOrDefault()));
    Result:
  5. Now I have created a static class named as “LinqExtension.cs” and created extension methods for selecting “FirstOrDefault”, “LastOrDefault” and getting index of the object from list using Linq.
    public static class LinqExtension
    {
     public static T WhereFirstOrDefault(this List list, Func predicate)
     {
      return list.Where(predicate).FirstOrDefault();
     }
     public static T WhereLastOrDefault(this List list, Func predicate)
     {
      return list.Where(predicate).LastOrDefault();
     }
     public static int IndexOf(this List list, Func predicate)
     {
      return list.IndexOf(list.WhereFirstOrDefault(predicate));
     }
    }
  6. The extension methods can be implemented as like the below
    Console.WriteLine(employees.WhereFirstOrDefault(x => x.Name.Contains("Mushtaq")).String());
    Console.WriteLine(employees.WhereLastOrDefault(x => x.Name.Contains("Mushtaq")).String());
    Console.WriteLine(employees.IndexOf(x => x.Name.Contains("Mushtaq")));
    Result:
  7. The extension will return the same result. But the line of code will be less comparatively.

Full Code:

Full code implementations of extension methods.

namespace ExtensionsWithLinq
{
    class Program
    {
        static List employees = new List();
        static void Main(string[] args)
        {
            AddEmployees();

            Console.WriteLine("...Extension with Linq...");
            Console.WriteLine();
            Console.WriteLine();
            Console.WriteLine("Linq to get details of Mushtaq with Linq-FirstOrDefault");
            Console.WriteLine();
            Console.WriteLine(employees.Where(x => x.Name.Contains("Mushtaq")).FirstOrDefault().String());

            Console.WriteLine();
            Console.WriteLine();
            Console.WriteLine("Linq to get details of Mushtaq with Linq-LastOrDefault");
            Console.WriteLine();
            Console.WriteLine(employees.Where(x => x.Name.Contains("Mushtaq")).LastOrDefault().String());

            Console.WriteLine();
            Console.WriteLine();
            Console.WriteLine("Linq to get index of Mushtaq with Linq-IndexOf");
            Console.WriteLine();
            Console.WriteLine(employees.IndexOf(employees.Where(x => x.Name.Contains("Mushtaq")).FirstOrDefault()));

            Console.WriteLine();
            Console.WriteLine();
            Console.WriteLine("Linq to get details of Mushtaq with Linq-FirstOrDefault Extension");
            Console.WriteLine();
            Console.WriteLine(employees.WhereFirstOrDefault(x => x.Name.Contains("Mushtaq")).String());

            Console.WriteLine();
            Console.WriteLine();
            Console.WriteLine("Linq to get details of Mushtaq with Linq-LastOrDefault Extension");
            Console.WriteLine();
            Console.WriteLine(employees.WhereLastOrDefault(x => x.Name.Contains("Mushtaq")).String());

            Console.WriteLine();
            Console.WriteLine();
            Console.WriteLine("Linq to get index of Mushtaq with Linq-IndexOf Extension");
            Console.WriteLine();
            Console.WriteLine(employees.IndexOf(x => x.Name.Contains("Mushtaq")));

            Console.ReadLine();
        }

        static void AddEmployees()
        {
            employees.Add(new Employee() { Name = "Mushtaq", MobileNo = "9876543210", Salary = "20K" });
            employees.Add(new Employee() { Name = "Mohammed Mushtaq", MobileNo = "9876543211", Salary = "30K" });
            employees.Add(new Employee() { Name = "Mushtaq Ahmed", MobileNo = "9876543212", Salary = "20K" });
            employees.Add(new Employee() { Name = "Raj", MobileNo = "9876543213", Salary = "25K" });
        }
    }
}

Reference:

Linqhttps://docs.microsoft.com/en-us/dotnet/csharp/linq/
Extensionshttps://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/extension-methods

Download Code

You can download the code from GitHub. If you have doubt, feel free to post comment. If you like this article and is useful to you, do like, share the article & star the repository on GitHub.

Introduction: In this tutorial, we will learn how to use Rg.Plugin.Popup in Xamarin.Forms using Fresh MMVM. In my previous articles, we h...

Rg Popup in Xamarin.Forms using Fresh MVVM Rg Popup in Xamarin.Forms using Fresh MVVM

A blog about android developement

Introduction:

In this tutorial, we will learn how to use Rg.Plugin.Popup in Xamarin.Forms using Fresh MMVM. In my previous articles, we have learned how to use Fresh MVVM with Navigation Page, Master Detail Page and Tabbed Page. If you are new to Fresh MVVM, kindly read my previous articles on Fresh MVVM to know the basics & rules of Fresh MVVM.

Coding Part:

Steps:

I have split this part into 3 steps as in the following.

  1. Creating new Xamarin.Forms Projects.
  2. Setting up the plugin for Xamarin.Forms Application.
  3. Implementing Fresh MVVM.

Step 1: Creating new Xamarin.Forms Projects

Create New Project by Selecting New -> Project -> Select Xamarin Cross Platform App and Click OK.
Then Select Android and iOS Platforms as shown below with Code Sharing Strategy as PCL or .Net Standard and Click OK.

Step 2: Setting up the plugin for Xamarin.Forms Application

We will start coding for Fresh MVVM. Create New Xamarin Forms Project. Open Nuget Package Manager against the solution and do search for Fresh MVVM Plugin or Paste the following Nuget Installation.
Install-Package FreshMvvm -Version 2.2.3

Click Install to install this Plugin against your PCL Project or .NET standard Project. Then download the Rg.Plugin.Popup by using the following Nuget package.

Install-Package Rg.Plugins.Popup -Version 1.1.5.188

Click Install to install this Plugin against your PCL Project or .NET standard Project and all dependent platform projects.

Step 3: Implementing Fresh MVVM Page & Page Models

  1. Create your XAML page (view) with name ended up with “Page”.
  2. Create PageModel by create Class name ended with “PageModel” and inherited with “FreshBasePageModel” as shown below screenshot.
  3. I have created a Page & PageModel named as “MainPage” & “MainPageModel” and set this page as Main Page/Root Page of the application as shown in the following.

    Set MainPage:

    We need to set the MainPageModel as MainPage using FreshNavigationConatiner. Open App.xaml.cs or App.cs and set MainPage.

    // To set MainPage for the Application
    var page = FreshPageModelResolver.ResolvePageModel();
    var basicNavContainer = new FreshNavigationContainer(page);
    MainPage = basicNavContainer;

  4. 4. Then create a Popup Page using Rg.Plugins.Popup by adding “”. The following code snippet shows how to create popup using Rg.Plugin. I have created a Xamarin.Forms Page and named as “MyPopupPage.xaml”.
    <?xml version="1.0" encoding="utf-8" ?>
    <popup:PopupPage xmlns="http://xamarin.com/schemas/2014/forms"
                     xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                     xmlns:popup="clr-namespace:Rg.Plugins.Popup.Pages;assembly=Rg.Plugins.Popup"
                     CloseWhenBackgroundIsClicked="True"
                     x:Class="Popup.MyPopupPage">
        <popup:PopupPage.Content>
            <StackLayout Padding="10"
                         BackgroundColor="White"
                         HorizontalOptions="Center"
                         VerticalOptions="Center">
                <Label Text="Fresh MVVM Rg.Plugin.Popup"
                    VerticalOptions="CenterAndExpand" 
                    HorizontalOptions="CenterAndExpand" />
                <Button Command="{Binding ClosePopupCommand}"
                        Text="Close Popup"/>
            </StackLayout>
        </popup:PopupPage.Content>
    </popup:PopupPage>
  5. The code behind has “PopupPage” as parent page like shown in the following code part.
    public partial class MyPopupPage : PopupPage
    {
     public MyPopupPage ()
     {
      InitializeComponent ();
     }
    }
  6. Then create a Page Model for the created Popup Page with Fresh MVVM rules. If you have not remember the rules or new to Fresh MVVM, Kindly refer my previous articles on fresh MVVM.
    public class MyPopupPageModel : FreshBasePageModel
    {
    
    }
  7. Rg Popup Page has a separate Navigation Stack. So, open and close the popup, we need to have separate Navigation Stack. To know more about Rg.Plugin.Popup, refer the GitHub Link.
    Rg.Plugin.Popup Link: https://github.com/rotorgames/Rg.Plugins.Popup
  8. Then include Fresh MVVM extension/Utility class to your Xamarin Shared Project. This extension file is created & open sourced by the author “Libin Joseph”. You can download this file from the following GitHub Link.
    Fresh MVVM Extension Link: https://github.com/libin85/FreshMvvm.Popup
  9. To open popup page like navigating to normal Fresh MVVM page, use the following code snippet.
    return new Command(async () =>
    {
            await CoreMethods.PushPopupPageModel();
    });
  10. To close the popup page like closing normal Fresh MVVM page, use the following code snippet.
    return new Command(async () =>
    {
            await CoreMethods.PopPopupPageModel();
    });

Demo:

The below screenshots for your reference.

Main PageRg Popup Page

Reference:

Fresh MVVMhttps://github.com/rid00z/FreshMvvm
Rg.Plugin.Popuphttps://github.com/rotorgames/Rg.Plugins.Popup
Fresh MVVM Popup Extensionhttps://github.com/libin85/FreshMvvm.Popup/

Download Code

You can download the code from GitHub. If you have doubt, feel free to post comment. If you like this article and is useful to you, do like, share the article & star the repository on GitHub.

Introduction: In this tutorial, we will learn how to use master detail page using Fresh MVVM with FreshNavigationContainer. It has some w...

Custom Master Detail Page in Xamarin.Forms using Fresh MVVM Custom Master Detail Page in Xamarin.Forms using Fresh MVVM

A blog about android developement

Introduction:

In this tutorial, we will learn how to use master detail page using Fresh MVVM with FreshNavigationContainer. It has some work around for creating master detail page more than creating master detail page using FreshMasterContainer. In my previous tutorials, we have learned the method to create master detail page using Fresh Master Container. To know more, visit my previous article.

Kindly refer my previous article on Fresh MVVM to know the basics & rules of Fresh MVVM.

Coding Part:

Steps:

I have split this part into 3 steps as in the following.

  1. Creating new Xamarin.Forms Projects.
  2. Setting up the plugin for Xamarin.Forms Application.
  3. Implementing Fresh MVVM.

Step 1: Creating new Xamarin.Forms Projects

Create New Project by Selecting New -> Project -> Select Xamarin Cross Platform App and Click OK.
Then Select Android and iOS Platforms as shown below with Code Sharing Strategy as PCL or .Net Standard and Click OK.

Step 2: Setting up the plugin for Xamarin.Forms Application

We will start coding for Fresh MVVM. Create New Xamarin Forms Project. Open Nuget Package Manager against the solution and do search for Fresh MVVM Plugin or Paste the following Nuget Installation.
Install-Package FreshMvvm -Version 2.2.3
Click Install to install this Plugin against your PCL Project or .NET standard Project.

Step 3: Implementing Fresh MVVM.

  1. Create your XAML page (view) with name ended up with “Page”.
  2. Create PageModel by create Class name ended with “PageModel” and inherited with “FreshBasePageModel” as shown below screenshot.

In the same way, I have created pages “MyMasterDetailPage”, “MasterPage”, “Detail1Page” and “Detail2Page” with two respective models “MyMasterDetailPageModel”, “MasterPageModel”, “Detail1PageModel” and “Detail2PageModel”.

Here,
MyMasterDetailPagecontainer to have both Master & Detail page
MasterPageMaster or Menu Page
Detail1Page, Detail2PageDetail pages of the Master detail page

Set MainPage:

We need to set the MainPageModel as MainPage using FreshNavigationConatiner.

  1. Open App.xaml.cs or App.cs and set MainPage.
    // To set MainPage for the Application
    var page = FreshPageModelResolver.ResolvePageModel();
    var basicNavContainer = new FreshNavigationContainer(page);
    MainPage = basicNavContainer;
  2. Then add button with command for opening the MasterDetailPage from MainPage.
    public Command GotoSecondPageCommand
    {
        get
        {
            return new Command(async () =>
            {
                await CoreMethods.PushPageModel();
            });
        }
    }
  3. Open MyMasterDetailPage and add Master, Detail page to the constructor of the page like below.
    public MyMasterDetailPage()
    {
        InitializeComponent();
    
        NavigationPage.SetHasNavigationBar(this, false);
    
        Master = FreshPageModelResolver.ResolvePageModel();
        Detail = new NavigationPage(FreshPageModelResolver.ResolvePageModel());
    }
  4. Then click “Run” to see your Custom Master Detail Page using FreshMVVM with FreshNavigationContainer.

By this way, we can have Navigation Service & Stack for all type of Pages. Kindly find the screenshot for your reference.

MainPageMaster Page(Detail)Master Page(Master)

Download Code

You can download the code from GitHub. If you have doubt, feel free to post comment. If you like this article and is useful to you, do like, share the article & star the repository on GitHub.

Introduction: In this article, we will learn how to convert any web url to pdf file in Android. To create PDF in Android, we will use i...

How to convert web link to PDF without using iText Library in Android How to convert web link to PDF without using iText Library in Android

A blog about android developement


Introduction:

In this article, we will learn how to convert any web url to pdf file in Android. To create PDF in Android, we will use iText Library. But here, we will not use any third party libraries like iText Library.

iText Library:

This library is awesome and very useful. But the iText Community licensed this library with AGPL license. So, we need to license our own application under AGPL license.

Reference Link: http://developers.itextpdf.com/

But google provided print API for Android to print any content directly from mobile app. We can use same Print API for generating and saving the pdf file. Without any introduction, we will skip into the coding part.

Reference Link: https://developer.android.com/training/printing/

Coding Part 

I have detailed the article in the following sections. 
  1. Creating a new project with Empty activity. 
  2. Setting up the project with Print Adapter Extension.
  3. Implementation of URL to PDF file generation.

Step 1: Creating New Project with Empty Activity.

  1. Creating New Project with Android Studio Open Android Studio and Select Create new project. 
  2. Name the project as your wish and select your activity template.

  3. Click “finish” button to create new project in Android Studio.

Step 2: Setting up the project with Print Adapter Extension

  1. To create pdf file, we need to use “PrintDocumentAdapter.LayoutResultCallback” and it cannot be used by any class.
  2. So, we need to create a class with package name as “android.print” and we will named the class as “PdfPrint.java”
  3. Then paste the following code with callback interface.
    @SuppressWarnings("ALL")
    public class PdfPrint {
        private static final String TAG = PdfPrint.class.getSimpleName();
        private final PrintAttributes printAttributes;
    
        public PdfPrint(PrintAttributes printAttributes) {
            this.printAttributes = printAttributes;
        }
    
        @RequiresApi(api = Build.VERSION_CODES.KITKAT)
        public void print(final PrintDocumentAdapter printAdapter, final File path, final String fileName,
                          final CallbackPrint callback) {
            printAdapter.onLayout(null, printAttributes, null,
                    new PrintDocumentAdapter.LayoutResultCallback() {
                        @Override
                        public void onLayoutFinished(PrintDocumentInfo info, boolean changed) {
                            printAdapter.onWrite(new PageRange[]{PageRange.ALL_PAGES}, getOutputFile(path, fileName),
                                    new CancellationSignal(), new PrintDocumentAdapter.WriteResultCallback() {
                                        @Override
                                        public void onWriteFinished(PageRange[] pages) {
                                            super.onWriteFinished(pages);
                                            if (pages.length > 0) {
                                                File file = new File(path, fileName);
                                                String path = file.getAbsolutePath();
                                                callback.onSuccess(path);
                                            } else {
                                                callback.onFailure(new Exception("Pages length not found"));
                                            }
    
                                        }
                                    });
                        }
                    }, null);
        }
    
        private ParcelFileDescriptor getOutputFile(File path, String fileName) {
            if (!path.exists()) {
                path.mkdirs();
            }
            File file = new File(path, fileName);
            try {
                file.createNewFile();
                return ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_WRITE);
            } catch (Exception e) {
                Log.e(TAG, "Failed to open ParcelFileDescriptor", e);
            }
            return null;
        }
        public interface CallbackPrint {
            void onSuccess(String path);
            void onFailure(Exception ex);
        }
    }

Step 3: Implementation of URL to PDF file generation

In this part, we will learn how to use the Printer Extension created in the last step and How to create a PDF file.

  1. Open your activity_main.xml file and Paste the following code.
    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context="com.androimads.androidpdfmaker.MainActivity">
    
        <WebView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:id="@+id/webView"
            android:layout_above="@id/textView"/>
    
        <TextView
            android:visibility="gone"
            android:background="@color/colorBackground"
            android:padding="2dp"
            android:text="Saving..."
            android:gravity="center"
            android:textColor="#FFFFFF"
            android:layout_alignParentBottom="true"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:id="@+id/textView"/>
    
    </RelativeLayout>
  2. Then open your Activity file, in my case “MainActivity.java” and initialize “WebView” as shown below
    webView = findViewById(R.id.webView);
    webView.loadUrl("https://www.androidmads.info/");
    webView.setWebViewClient(new WebViewClient());
  3. Then create a pdf print adapter with print attributes what we need
    String fileName = String.format("%s.pdf", new SimpleDateFormat("dd_MM_yyyyHH_mm_ss", Locale.US).format(new Date()));
    final PrintDocumentAdapter printAdapter = webView.createPrintDocumentAdapter(fileName);
    PrintAttributes printAttributes = new PrintAttributes.Builder()
      .setMediaSize(PrintAttributes.MediaSize.ISO_A4)
      .setResolution(new PrintAttributes.Resolution("pdf", "pdf", 600, 600))
      .setMinMargins(PrintAttributes.Margins.NO_MARGINS)
      .build();
    Here, I have used default page size as “A4”. You can change as per your need.
  4. Then call your extension method with Callback as shown below
    new PdfPrint(printAttributes).print(
     printAdapter,
     file,
     fileName,
     new PdfPrint.CallbackPrint() {
      @Override
      public void onSuccess(String path) {
    
      }
    
      @Override
      public void onFailure(Exception ex) {
      }
     });
    The PdfPrint.Callback will return success or failure based on the extension method we created.

Full code of MainActivity:

Here you can find the full code of the MainActivity.java for generating pdf file.
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public class MainActivity extends AppCompatActivity {

    private WebView webView;
    private TextView textView;
    private int PERMISSION_REQUEST = 0;
    private boolean allowSave = true;

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

        textView = findViewById(R.id.textView);
        webView = findViewById(R.id.webView);
        webView.loadUrl("https://www.androidmads.info/");
        webView.setWebViewClient(new WebViewClient());
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        if (item.getItemId() == R.id.save) {
            savePdf();
            return true;
        }
        return super.onOptionsItemSelected(item);
    }

    private void savePdf() {
        if(!allowSave)
            return;
        allowSave = false;
        textView.setVisibility(View.VISIBLE);
        if (ActivityCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE)
                == PERMISSION_GRANTED) {
            String fileName = String.format("%s.pdf", new SimpleDateFormat("dd_MM_yyyyHH_mm_ss", Locale.US).format(new Date()));
            final PrintDocumentAdapter printAdapter = webView.createPrintDocumentAdapter(fileName);
            PrintAttributes printAttributes = new PrintAttributes.Builder()
                    .setMediaSize(PrintAttributes.MediaSize.ISO_A4)
                    .setResolution(new PrintAttributes.Resolution("pdf", "pdf", 600, 600))
                    .setMinMargins(PrintAttributes.Margins.NO_MARGINS)
                    .build();
            final File file = Environment.getExternalStorageDirectory();
            new PdfPrint(printAttributes).print(
                    printAdapter,
                    file,
                    fileName,
                    new PdfPrint.CallbackPrint() {
                        @Override
                        public void onSuccess(String path) {
                            textView.setVisibility(View.GONE);
                            allowSave = true;
                            Toast.makeText(getApplicationContext(),
                                    String.format("Your file is saved in %s", path),
                                    Toast.LENGTH_LONG).show();
                        }

                        @Override
                        public void onFailure(Exception ex) {
                            textView.setVisibility(View.GONE);
                            allowSave = true;
                            Toast.makeText(getApplicationContext(),
                                    String.format("Exception while saving the file and the exception is %s", ex.getMessage()),
                                    Toast.LENGTH_LONG).show();
                        }
                    });
        } else {
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, PERMISSION_REQUEST);
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        if (requestCode == PERMISSION_REQUEST) {
            if (grantResults[Arrays.asList(permissions).indexOf(Manifest.permission.WRITE_EXTERNAL_STORAGE)] == PERMISSION_GRANTED) {
                savePdf();
            }
        }
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    }
}

Download Code

You can download the full source code of the article in GitHub. If you like this article, do star the repo in GitHub. Hit like the article.