Tuesday, April 21, 2026

Installing Docker CLI on Ubuntu (Step-by-Step Guide)

If you're working with containers, Docker is one of the most essential tools you’ll need. In this guide, I’ll walk you through installing the Docker CLI (along with the Docker Engine) on an Ubuntu system in a simple and practical way.

Prerequisites

Before you start, make sure:

  • You’re using an Ubuntu system (18.04 or later recommended)
  • You have a user account with sudo privileges
  • Your system is connected to the internet

Steps

Step 1: Update Package Index

Start by updating your system’s package list:

sudo apt update

Install required dependencies:

sudo apt install -y apt-transport-https ca-certificates curl software-properties-common

Step 2: Add Docker’s Official GPG Key

This ensures packages are verified and trusted:

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg

Step 3: Add Docker Repository

echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

Step 4: Install Docker Engine & CLI

Update package list again:

sudo apt update

Now install Docker:

sudo apt install -y docker-ce docker-ce-cli containerd.io

Step 5: Start and Enable Docker

Start Docker service:

sudo systemctl start docker

Enable Docker to start on boot:

sudo systemctl enable docker

Step 6: Run Docker Without sudo (Optional but Recommended)

By default, Docker requires sudo. To avoid that, add your user to the Docker group:

sudo usermod -aG docker $USER

Apply the changes immediately:

newgrp docker

Step 7: Verify Installation

Check Docker system info:

docker info

List running containers:

docker ps

Quick Note

  • docker-ce → Docker Engine
  • docker-ce-cli → Docker CLI
  • containerd.io → Container runtime

Conclusion

You now have Docker CLI installed and ready to use on Ubuntu. This setup is ideal for development, testing, and learning containerization.

From here, you can start running containers, pulling images, or even building your own.

Saturday, February 18, 2017

Singleton Design Pattern In C++

Singleton Design Pattern is used to keep one instance of a class in the system. To implement this pattern in C++, language features like access modifiers (public, protected, private), class functions and variables by using static, pointer and dynamic memory is used.

To keep single instance of particular class, developers must be prevented from creating new objects. In order to achieve that constructors of that particular class must be private. Doing so, new object of that class cannot be created. Object creating is facilitated well control manner to keep one instance of that class in the system by a public class method. The created single instance also is kept in the class variable. So when program request an instance, if that variable has the instance that instance is returned. Otherwise new instance is created and returned. All subsequent calls to object creation method returns the single instance that is kept in the class variable. 

Below implementation use static ThreadPool *getInstance() method to create or get single instance.

Implementation

#include <iostream>

using std::cout;
using std::endl;

class ThreadPool {
   private:
      static ThreadPool *tPSingleton;
      ThreadPool ();

   public:
      static ThreadPool *getInstance();
      bool startThreadPool();
      bool stopThreadPool();

      ~ThreadPool ();

};

ThreadPool* ThreadPool::tPSingleton = NULL;


ThreadPool::ThreadPool (){
   cout<<"Thread Pool is created"<<endl;
}

ThreadPool::~ThreadPool (){
   cout<<"Thread Pool is destroyed"<<endl;
}

ThreadPool *ThreadPool::getInstance(){
   if(ThreadPool::tPSingleton == NULL){
      ThreadPool::tPSingleton = new ThreadPool;
   }

   return ThreadPool::tPSingleton;
}

bool ThreadPool::startThreadPool(){
   cout<<"Thread pool is being started"<<endl;
   return true;
}

bool ThreadPool::stopThreadPool(){
   cout<<"Thread pool is being stoped"<<endl;
   return true;
}

int main() {
   ThreadPool *threadPool1;
   ThreadPool *threadPool2;
   
   /*
       threadPool1 = new ThreadPool;

       Produce below error with Error No 1
   */

   threadPool1 = ThreadPool::getInstance();
   threadPool1->startThreadPool();
   threadPool1->stopThreadPool();

   threadPool2 = ThreadPool::getInstance();
   threadPool2->startThreadPool();
   threadPool2->stopThreadPool();

   return 0;
}

/*

Error No 1

singleton.cpp: In function ‘int main()’:
singleton.cpp:23:1: error: ‘ThreadPool::ThreadPool()’ is private
 ThreadPool::ThreadPool (){
 ^
singleton.cpp:52:22: error: within this context
    threadPool1 = new ThreadPool;   
                      ^

*/

Output

Thread Pool is created
Thread pool is being started
Thread pool is being stoped
Thread pool is being started
Thread pool is being stoped

Sunday, October 30, 2016

Android App To Understand Sticky Broadcasts

This blog post is about an application that can be used to understand what is the difference between sticky broadcasts and ordinary broadcasts of Android system. App name is StickyBCast. App has below package name.
com.blogspot.nipunswritings.stickybcast.

UI of the app is shown below.
Above UI shows what sticky broadcast and ordinary broadcast sent. This app send broadcast at two events. One is when onStop() is called and other one is when user touch on send button. Content that is sent with sticky broadcast is displayed below "Sticky Broadcast Content" and Content that is sent with ordinary broadcast is displayed below "Ordinary Broadcast Content". The content that is sent with broadcast are shown in TextViews. 

To show content that is sent with sticky broadcast TextView with Id "sticky_content_tv" is used. TextView with id ordinary_content_tv is used to show the content that is sent with normal broadcast.

Class (MainActivity) below is used to show difference between two types of broadcasts. 

public class MainActivity extends AppCompatActivity {

    private TextView oContentTv;
    private TextView sContentTv;

    private String oContent;
    private String sContent;

    private IntentFilter oContentFilter;
    private IntentFilter sContentFilter;

    private BroadcastReceiver oReceiver = new BroadcastReceiver() {
        @Override        public void onReceive(Context context, Intent intent) {
            oContent = intent.getStringExtra(Constants.ORDINARY_EXTRA);
            setTextViews();
        }
    };

    private BroadcastReceiver sReceiver = new BroadcastReceiver() {
        @Override        public void onReceive(Context context, Intent intent) {
            sContent = intent.getStringExtra(Constants.STICKY_EXTRA);
            setTextViews();
        }
    };


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

        oContentTv = (TextView) findViewById(R.id.ordinary_content_tv);
        sContentTv = (TextView) findViewById(R.id.sticky_content_tv);

        oContentFilter = new IntentFilter(Constants.ORDINARY_ACTION);
        sContentFilter = new IntentFilter(Constants.STICKY_ACTION);
    }

    @Override    protected void onStart() {
        super.onStart();

        oContent = "";
        sContent = "";

        Intent oIntent = registerReceiver(oReceiver, oContentFilter);
        Intent sIntent = registerReceiver(sReceiver, sContentFilter);

        if (oIntent != null) {
            oContent = oIntent.getStringExtra(Constants.ORDINARY_EXTRA);
        }

        if (sIntent != null) {
            sContent = sIntent.getStringExtra(Constants.STICKY_EXTRA);
        }

        setTextViews();
    }


    @Override    protected void onStop() {
        super.onStop();
        sendBroadcasts("Ordinay Value 2", "Sticky Value 2");
    }

    private void setTextViews() {
        oContentTv.setText(this.oContent);
        sContentTv.setText(this.sContent);
    }

    public void sendBroadcasts(String oExtrVal, String sExtrVal) {
        Intent oIntent = new Intent(Constants.ORDINARY_ACTION);
        Intent sIntent = new Intent(Constants.STICKY_ACTION);

        oIntent.putExtra(Constants.ORDINARY_EXTRA, oExtrVal);
        sIntent.putExtra(Constants.STICKY_EXTRA, sExtrVal);


        sendBroadcast(oIntent);
        sendStickyBroadcast(sIntent);
    }

    public void sendBCastWithClick(View view) {
        sendBroadcasts("Ordinay Value 1", "Sticky Value 1");
    }
}

Some of the constants that are needed for this application has been defined in a class called Constants. This is the definition of that class.

public class Constants {
    public static String STICKY_ACTION = "com.blogspot.nipunswritings.s_action";
    public static String ORDINARY_ACTION = "com.blogspot.nipunswritings.o_action";

    public static String STICKY_EXTRA = "com.blogspot.nipunswritings.s_extra";
    public static String ORDINARY_EXTRA = "com.blogspot.nipunswritings.o_extra";
}

In MainActivitypublic void sendBroadcasts(String oExtrVal, String sExtrVal) method is called at two event. One event is in the onStop() method of the activity and other one is in the button click listener of send button with the method public void sendBCastWithClick(View view). The arguments that are passed to method sendBroadcasts(String, String) are different in two events. 

Code segment that is useful to understand difference between sticky broadcasts and normal broadcasts is this.

        Intent oIntent = registerReceiver(oReceiver, oContentFilter);
        Intent sIntent = registerReceiver(sReceiver, sContentFilter);

here when registration is done if sticky broadcast has been sent earlier that is returned by the function registerReceiver(Intent) for sticky broadcasts. But for normal broadcasts it returns null. If you run the app and click send button both text boxes will display text values that have been sent by broadcasts. In that case there is no difference between those two types of broadcast.  

Then do something that cause to call onStop() and come back to app. The TextView for sticky broadcast text has been set with the "Sticky Value 2" but other one is empty. Because system doesn't provide normal broadcast intents that was sent before registration. So for below code oIntent  is null.
        if (oIntent != null) {
            oContent = oIntent.getStringExtra(Constants.ORDINARY_EXTRA);
        }

        if (sIntent != null) {
            sContent = sIntent.getStringExtra(Constants.STICKY_EXTRA);
        }

To send broadcasts below function is used. Method sendStickyBroadcast(sIntent) is deprecated even though that is used for this example. 

    public void sendBroadcasts(String oExtrVal, String sExtrVal) {
        Intent oIntent = new Intent(Constants.ORDINARY_ACTION);
        Intent sIntent = new Intent(Constants.STICKY_ACTION);

        oIntent.putExtra(Constants.ORDINARY_EXTRA, oExtrVal);
        sIntent.putExtra(Constants.STICKY_EXTRA, sExtrVal);


        sendBroadcast(oIntent);
        sendStickyBroadcast(sIntent);
    }

Reference:
  • https://developer.android.com/reference/android/content/Context.html#sendStickyBroadcast(android.content.Intent)





Sunday, August 14, 2016

sendBroadcast Android Example

This is an example of using method sendBroadcast() to send broadcasts in Android. App has one BroadcastReceiver. It display broadcast action if there is one else display nothing. It also display the addition of two numbers that were sent to it. 

BroadcastReceiver has been implemented with the class NumberReceiver. So it must be registered by using the manifest file.

<receiver
    android:name=".NumberReceiver"
    android:enabled="true"
    android:exported="true">
    <intent-filter>
       <action android:name="com.blogspot.nipunswritings.demosendbcast.add" />
    </intent-filter>
</receiver>

It can receive intents with the below action

com.blogspot.nipunswritings.demosendbcast.add

Project has class Constants that has been defined key for intent actions and extras.

public class Constants { 
    public static String ACTION_ADD = "com.blogspot.nipunswritings.demosendbcast.add"; 
    public static String EXTRA_X = "com.blogspot.nipunswritings.demosendbcast.x"; 
    public static String EXTRA_Y = "com.blogspot.nipunswritings.demosendbcast.y";
}

In the activity that invoke sendBroadcast() has Two EditTexts and a Button. When user click the button numbers in two EditTexts are send to BroadcastReceiver after converting them to integers. This is the button onClick method.

public void sendToAddition (View view) {

    boolean withAction = false;

    int x = Integer.parseInt(xEt.getText().toString());
    int y = Integer.parseInt(yEt.getText().toString());

    Intent intent;

    if (withAction) {
        intent = new Intent(Constants.ACTION_ADD);
    } else {
        intent = new Intent(MainActivity.this, NumberReceiver.class);
    }
    intent.putExtra(Constants.EXTRA_X, x);
    intent.putExtra(Constants.EXTRA_Y, y);

    sendBroadcast(intent);
}

Important code snippet of above method is this.

    Intent intent;

    if (withAction) {
        intent = new Intent(Constants.ACTION_ADD);
    } else {
        intent = new Intent(MainActivity.this, NumberReceiver.class);
    }
    intent.putExtra(Constants.EXTRA_X, x);
    intent.putExtra(Constants.EXTRA_Y, y);
 
    sendBroadcast(intent); 

If Boolean variable withAction is true Intent instance is created with the ACTION_ADD in constants file. If it is not true since both Receiver and Activity in the same class Intent instance is created with the class. Then integer values which are got by casting String that are provided by EditTexts are put into Intent instance. Finally sendBroadcast() is called.

Method onReceive(Context, Intent) of NumberReceiver. has been written below.
 
@Overridepublic void onReceive(Context context, Intent intent) {
    int x = intent.getIntExtra(Constants.EXTRA_X, 0);
    int y = intent.getIntExtra(Constants.EXTRA_Y, 0);

    String action = intent.getAction();
    if (action != null) {
        Toast.makeText(context, "Action = "+action, Toast.LENGTH_LONG).
                show();
    } else {
        Toast.makeText(context, "Action isn't available", Toast.LENGTH_LONG).
                show();
    }


    Toast.makeText(context, "x + y = "+Calculator.performAddition(x,y), Toast.LENGTH_LONG).
            show();
}

It get extras and actions then display them with a Toast.

Calculations is done by using the Calculator class. Calculator class implementation is this.

public class Calculator {
    public static int performAddition (int x, int y) {
        return x+y;
    }
}


Sunday, July 17, 2016

Android LocalBroadcastManager Example

Using broadcasts in Android applications sometimes introduce problems as broadcasts can be received by the other applications too. To prevent these problems Android system has LocalBroadcastManager that can be used to implement secure communication mechanism within app components.

This example shows how to use LocalBroadcastManager to send and receive broadcasts. Though this application has only one activity it can LocalBroadcastManager is capable doing more than that. For example It can be used to send broadcasts from service to another activity, from One BroadcastReceiver to activity like use cases.

The app which is developed for demonstration has one EditText and Button. When user type something on EditText and click the Button typed content send to BroadcastReceiver that has been registered by using LocalBroadcastManager. After it received that Text it shows as a Toast.


Above image shows what this application does. Implementation of this application is on MainActivity class which is shown below.

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

    private final String TEXT_SENT_ACTION =  
       "com.blogspot.nipunswritings.bcsender.action.TEXT_SENT";
    private final String TEXT_EXTRA 
       "com.blogspot.nipunswritings.bcsender.extra.TEXT";

    private BroadcastReceiver textSentReceier = new BroadcastReceiver() {
        @Override        public void onReceive(Context context, Intent intent) {
            String textExtra = intent.getStringExtra(TEXT_EXTRA);
            Toast.makeText(context, textExtra, Toast.LENGTH_LONG).show();
        }
    };

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

    @Override    protected void onResume() {
        super.onResume();

        IntentFilter textSentIntentFilter = new IntentFilter(TEXT_SENT_ACTION);
        LocalBroadcastManager
                .getInstance(MainActivity.this)
                .registerReceiver(textSentReceier, textSentIntentFilter);
    }

    @Override    protected void onPause() {
        LocalBroadcastManager.getInstance(MainActivity.this)
            .unregisterReceiver(textSentReceier);

        super.onPause();

    }

    public void sendLocalTestBc(View view) {
        EditText sendingTextEt = (EditText) findViewById(R.id.activity_main_sent_text_et);
        String sendingText = sendingTextEt.getText().toString();

        Intent textSentIntent = new Intent(TEXT_SENT_ACTION);
        textSentIntent.putExtra(TEXT_EXTRA, sendingText);
        LocalBroadcastManager.getInstance(MainActivity.this).sendBroadcast(textSentIntent);
    }
}


As Broadcasts and associated data are needed to be identified at the beginning of above class unique identifiers for above class has been defined like this.

    private final String TEXT_SENT_ACTION =  
       "com.blogspot.nipunswritings.bcsender.action.TEXT_SENT";
    private final String TEXT_EXTRA 
       "com.blogspot.nipunswritings.bcsender.extra.TEXT";

Receive Local Broadcasts 
To receive broadcasts this activity must have a BroadcastReceiver implementation, that is shown below.

    private BroadcastReceiver textSentReceier = new BroadcastReceiver() {
        @Override        public void onReceive(Context context, Intent intent) {
            String textExtra = intent.getStringExtra(TEXT_EXTRA);
            Toast.makeText(context, textExtra, Toast.LENGTH_LONG).show();
        }
    };

Register Receiver with LocalBroadcastManager
In the onResume() IntentFilter is created to register receiver for designated action. IntentFilter constructor take that action as the parameter so it can receive broadcasts with this action.  
Next line is about registering receiver for the IntentFilter by using LocalBroadcastManager and registerReceiver(). After that receiver has ability to get broadcasts with TEXT_SENT_ACTION.
    @Override    protected void onResume() {
        super.onResume();

        IntentFilter textSentIntentFilter = new IntentFilter(TEXT_SENT_ACTION);
        LocalBroadcastManager
                .getInstance(MainActivity.this)
                .registerReceiver(textSentReceier, textSentIntentFilter);
    }

Unregister Receiver with LocalBroadcastManager
    @Override    protected void onPause() {
        LocalBroadcastManager.getInstance(MainActivity.this)
            .unregisterReceiver(textSentReceier);

        super.onPause();

    }

All registered BroadcastReceivers must be unregistered so it has done in onPause() by using unregisterReceiver() and LocalBroadcastManager.

Sending LocalBroadCasts

    public void sendLocalTestBc(View view) {
        EditText sendingTextEt = (EditText) findViewById(R.id.activity_main_sent_text_et);
        String sendingText = sendingTextEt.getText().toString();

        Intent textSentIntent = new Intent(TEXT_SENT_ACTION);
        textSentIntent.putExtra(TEXT_EXTRA, sendingText);
        LocalBroadcastManager.getInstance(MainActivity.this).sendBroadcast(textSentIntent);
    }

Above method is onClick method of the button. When user touch that button a Intent is crated with previously defined action and data key. After that it is sent with sendBroadcast() and LocalBroadcastManager.

References:
  • https://developer.android.com/reference/android/support/v4/content/LocalBroadcastManager.html

Sunday, June 26, 2016

registerReceiver (BroadcastReceiver, IntentFilter) Android Example

This example is about using registerReceiver and unregisterReceiver methods to use BroadcastReceiver programmatically. When BroadcastReceiver is registered in this way it's not declared in the AndroidManifest.xml file.

This application project has one Activity file and it register BroadcastReceiver to obtain battery level change information. Broadcast action ACTION_BATTERY_CHANGED is used by Android system to broadcast battery level changing information. Therefore that is used in this project.

Below source code is about implementation of the class BatteryChangedReceiver that extends from BroadcastReceiver. It receive battery change information and extra data on that intent are got by using the class BatteryManager. BatteryManager class has definitions of extra data that are sent with aforementioned broadcast action. Once onReceive(Context, Intent) method receives that data they are shown as Toast.

BatteryChangedReceiver Implementation

import android.content.BroadcastReceiver; 
import android.content.Context; 
import android.content.Intent; 
import android.os.BatteryManager; 
import android.widget.Toast; 
 
public class BatteryChangedReceiver extends BroadcastReceiver { 
   public BatteryChangedReceiver() {
   } 
 
   @Override
   public void onReceive(Context context, Intent intent) { 
      if (intent.getAction().equals(Intent.ACTION_BATTERY_CHANGED)) { 
         int level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1); 
         int scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
         Toast.makeText(context, "Level = "+level+", 
                        Scale = "+scale, Toast.LENGTH_LONG).show();
      }
   }
}

Above BroadcastReceiver is registered in the class MainActivity. That source code is this.

MainActivity Implementation

public class MainActivity extends AppCompatActivity { 
 
   private BatteryChangedReceiver batteryChangedReceiver; 
   private IntentFilter intentFilter; 
 
   @Override
   protected void onCreate(Bundle savedInstanceState) { 
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main); 
 
      batteryChangedReceiver = new BatteryChangedReceiver(); 
      intentFilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
   } 
 
   @Override
   protected void onResume() { 
      super.onResume();
      registerReceiver(batteryChangedReceiver, intentFilter);
   } 
 
   @Override
   protected void onPause() {
      unregisterReceiver(batteryChangedReceiver);
      super.onPause();
   }
}

An instance of the BatteryChangedReceiver is created to be used as first argument to registerReceiver() method. This method needs IntentFilter object for second argument to register BroadcastReceiver provided with first argument for a specific Intent. So both objects for first and second arguments are created in onCreate() method.
 
   batteryChangedReceiver = new BatteryChangedReceiver(); 
   intentFilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);

The method registerReceiver() is called in onResume() to register BroadcastReceiver. 
 
protected void onResume() { 
   super.onResume();
   registerReceiver(batteryChangedReceiver, intentFilter);
} 

As the BroadcastReceiver is registered in the onResume() it must be unregistered onPause(). Otherwise error will be occurred for leaking BroadcastReceiver. A BroadcastReceiver must be unregistered as many as it is registered.
 
@Override 
protected void onPause() {
   unregisterReceiver(batteryChangedReceiver); 
   super.onPause();
}

If onStop() is used to register BroadcastReceiver it must be unregistered in onStop().

Reference
  • https://developer.android.com/reference/android/content/Context.html#registerReceiver(android.content.BroadcastReceiver,%20android.content.IntentFilter)
  • https://developer.android.com/reference/android/content/Context.html#unregisterReceiver(android.content.BroadcastReceiver)
  • https://developer.android.com/reference/android/content/Intent.html#ACTION_BATTERY_CHANGED
  • https://developer.android.com/reference/android/os/BatteryManager.html

Sunday, June 19, 2016

Android BroadcastReceiver

Android applications need some mechanism to know when some event is occurred. For example some applications need to perform tasks when Android OS booting is completed. Android SDK provide BroadcastReceiver class for that purpose. This blog post content is about using BroadcastReceiver to get notification about connecting and disconnecting Android OS running device from external power source.
Name of this application is ConDisConInfo. So it has the main package with name com.blogspot.nipunswritings.ConDisConInfo. To create a BroadcastReceiver follow these steps.
  • Right Click on Main package
  • New
  • Other
  • Broadcast Receiver
  • Give name and click Finish
Once Finish is clicked a new java file can be seen in main package with the name PowerConnInfoReceiver.java. It has a PowerConnInfoReceiver class which extends from super class BroadcastReceiver. PowerConnInfoReceiver has below method which receive power connection/disconnection information which is sent by system.

@Overridepublic void onReceive(Context context, Intent intent) {
    
}

After  PowerConnInfoReceiver is created AndroidManifest.xml file has been updated with receiver element. That is registering a Broadcast Receiver. The receiver element in AndroidManifest.xml file is this.

<receiver 
     android:name=".PowerConnInfoReceiver" 
     android:enabled="true"
     android:exported="true">
</receiver>

Though that element is in the AndroidManifest.xml file PowerConnInfoReceiver will not receive any broadcast. A BroadcastReceiver to receive broadcasts it must be specified what broadcasts it must be received through the intent-filter element. Therefore receiver element is updated like below to receive broadcasts as mentioned above.

<receiver 
    android:name=".PowerConnInfoReceiver" 
    android:enabled="true"
    android:exported="true">
    <intent-filter>
        <action android:name="android.intent.action.ACTION_POWER_CONNECTED" />
        <action android:name="android.intent.action.ACTION_POWER_DISCONNECTED" />
    </intent-filter>
</receiver>

Notice the actions inside intent-filter. Without those actions this application doesn't work as expected. 

Method onReceive(Context, Intent) is updated to filter received information via Intent object and to display information to user as a Toast. So updated onReceive(Context, Intent) method is this.

@Overridepublic void onReceive(Context context, Intent intent) {
    if (intent.getAction().equals(Intent.ACTION_POWER_CONNECTED)){
        Toast.makeText(context, "Power Connected", Toast.LENGTH_LONG).show();
    } else if (intent.getAction().equals(Intent.ACTION_POWER_DISCONNECTED)) {
        Toast.makeText(context, "Power Disconnected", Toast.LENGTH_LONG).show();
    }
}

Run this app on a emulator. This application can be tested with battery section in extended controls of emulator. When charger connection is toggled between AC Charger and None corresponding Toast is displayed.



Reference:
  • https://developer.android.com/reference/android/content/BroadcastReceiver.html
  • https://developer.android.com/reference/android/content/Intent.html#ACTION_POWER_CONNECTED
  • https://developer.android.com/reference/android/content/Intent.html#ACTION_POWER_DISCONNECTED

Sunday, June 12, 2016

HelloCharts for Android Example

This example is using HelloCharts for Android to plot line chart for function |sin(x)|. The value range for x axis is from 0 to 360 degrees. The x values are given like 0, 15, 30, 45 ... 360. So there is difference of 15 degrees between  two points. But X axis is drawn with 30 degree scale. Therefore it goes like 0, 30, 60, 90, ..., 180, ...360. Y axis is drawn with scale of 0.25 from 0 to 1.0 to make Y axis range 0, 0.25, 0.5, 1.

At the end of this example developed application creates the below chart.

Add hello-charts library to app by adding below line to dependencies block of build.gradle file of app module. Then sync the project by using Android Studio.

compile 'com.github.lecho:hellocharts-library:1.5.8@aar'


Project has one Activity file with the name MainActivity.java. It's layout resource file is activity_main.xml.

This is the content of activity_main.xml. It has RelativeLayout as root element and RelativeLayout contain TextView and chart definition.

<TextView 
 android:id="@+id/chartLbl" 
 android:gravity="center" 
 android:layout_width="match_parent" 
 android:layout_height="wrap_content" 
 android:text="|sin(x)|" 
 android:layout_alignParentTop="true"     
 android:layout_alignParentStart="true"     
 android:layout_alignParentLeft="true"     
 android:layout_margin="5dp" 
 android:textStyle="bold" />

<lecho.lib.hellocharts.view.LineChartView 
 android:id="@+id/chart"     
 android:layout_width="match_parent" 
 android:layout_height="match_parent" 
 android:padding="10dp" 
 android:layout_below="@+id/chartLbl"/>

The element lecho.lib.hellocharts.view.LineChartView is xml definition of the line chart.

Now reference to this LineChartView can be made with findViewById(int) method. To hold reference to that view, field of type LineChartView has been defined in the MainActivity.java like this.
 
private LineChartView lineChartView;

Line chart has been created with below method. That is called in onCreate(Bundle) method.
 
public void drawSinAbsChart()

Method definition of  drawSinAbsChart()

public void drawSinAbsChart() {
    String decimalPattern = "#.##";
    DecimalFormat decimalFormat = new DecimalFormat(decimalPattern);

    lineChartView = (LineChartView) findViewById(R.id.chart);

    List<PointValue> values = new ArrayList<PointValue>();

    PointValue tempPointValue;
    for (float i = 0; i <= 360.0; i+= 15.0f) {
        tempPointValue = new PointValue(i, Math.abs((float)Math.sin(Math.toRadians(i))));
        tempPointValue.setLabel(decimalFormat
                   .format(Math.abs((float)Math.sin(Math.toRadians(i)))));
        values.add(tempPointValue);
    }

    Line line = new Line(values)
                   .setColor(Color.BLUE)
                   .setCubic(false)
                   .setHasPoints(true).setHasLabels(true);
    List<Line> lines = new ArrayList<Line>();
    lines.add(line);

    LineChartData data = new LineChartData();
    data.setLines(lines);

    List<AxisValue> axisValuesForX = new ArrayList<>();
    List<AxisValue> axisValuesForY = new ArrayList<>();
    AxisValue tempAxisValue;
    for (float i = 0; i <= 360.0f; i += 30.0f){
        tempAxisValue = new AxisValue(i);
        tempAxisValue.setLabel(i+"\u00b0");
        axisValuesForX.add(tempAxisValue);
    }

    for (float i = 0.0f; i <= 1.00f; i += 0.25f){
        tempAxisValue = new AxisValue(i);
        tempAxisValue.setLabel(""+i);
        axisValuesForY.add(tempAxisValue);
    }

    Axis xAxis = new Axis(axisValuesForX);
    Axis yAxis = new Axis(axisValuesForY);
    data.setAxisXBottom(xAxis);
    data.setAxisYLeft(yAxis);


    lineChartView.setLineChartData(data);


}

Code Explanation

    String decimalPattern = "#.##";
    DecimalFormat decimalFormat = new DecimalFormat(decimalPattern);

Values that are obtained must be shown only up to two decimal places in chart point labels. Object decimalFormat is created for that purpose.

    lineChartView = (LineChartView) findViewById(R.id.chart);

Above jave statement is to obtain the LineChartView object that is declared in the layout xml resource.

    List<PointValue> values = new ArrayList<PointValue>();

    PointValue tempPointValue;
    for (float i = 0; i <= 360.0; i+= 15.0f) {
        tempPointValue = new PointValue(i, Math.abs((float)Math.sin(Math.toRadians(i))));
        tempPointValue.setLabel(decimalFormat
                   .format(Math.abs((float)Math.sin(Math.toRadians(i)))));
        values.add(tempPointValue);
    }

Tha values that must be displayed in the line chart must be in the List of type List<PointValue>. That is doing here. That list contains points which are drawn in the chart. Point is represented with PointValue Class. for loop create those points and set it label that are shown at the points.

    Line line = new Line(values)
                   .setColor(Color.BLUE)
                   .setCubic(false)
                   .setHasPoints(true).setHasLabels(true);
    List<Line> lines = new ArrayList<Line>();
    lines.add(line);

    LineChartData data = new LineChartData();
    data.setLines(lines);

Line chart can  contain many lines, Above code shows how to create new line with the values which was generated function |sin(x)|. Method setColor() is used to define color of the line. This chart has straight line as setCubic() has been provided false value. If setHasPoints() called with argument false value points wouldn't be displayed.When setHasLabels() is provided with argument true value labels that was set during PointValue object are created is shown. The lines variable of type List<Line> holds all the lines that is drawn in the chart. This example chart has only one line so it has been added. Finally that lines object is added to LineChartData object with setLines().

    List<AxisValue> axisValuesForX = new ArrayList<>();
    List<AxisValue> axisValuesForY = new ArrayList<>();
    AxisValue tempAxisValue;
    for (float i = 0; i <= 360.0f; i += 30.0f){
        tempAxisValue = new AxisValue(i);
        tempAxisValue.setLabel(i+"\u00b0");
        axisValuesForX.add(tempAxisValue);
    }

    for (float i = 0.0f; i <= 1.00f; i += 0.25f){
        tempAxisValue = new AxisValue(i);
        tempAxisValue.setLabel(""+i);
        axisValuesForY.add(tempAxisValue);
    }

    Axis xAxis = new Axis(axisValuesForX);
    Axis yAxis = new Axis(axisValuesForY);
    data.setAxisXBottom(xAxis);
    data.setAxisYLeft(yAxis);

Java statements that are shown creating X and Y axis of the chart. First loop creates X axis which is started from 0 and goes upto 360 with increment 15.0 from previous x value. Values of axis is represented with object of type List<AxisValue> and AxisValue objects are used represent a location in the axis. AxisValue has setLabel() to display developer preferred label in the chart. In same way Y axis also has been created. After thata x & y axis is created as Axis objects. X axis is set to bottom with setAxisXBottom() and Y Axis is set to left with setAxisYLeft().

Chart data is provided to LineChartView with below statement.

    lineChartView.setLineChartData(data);

If axis values is cut off this link might be helpful. I had similar problem but I could resolve it without that link by adding 5dp padding around LineChartView.

Reference:
  • https://github.com/lecho/hellocharts-android