#038a52#89ffce#03ff97 IT Hangout

This is default featured slide 1 title

You can completely customize the featured slides from the theme theme options page. You can also easily hide the slider from certain part of your site like: categories, tags, archives etc. More »

This is default featured slide 2 title

You can completely customize the featured slides from the theme theme options page. You can also easily hide the slider from certain part of your site like: categories, tags, archives etc. More »

This is default featured slide 3 title

You can completely customize the featured slides from the theme theme options page. You can also easily hide the slider from certain part of your site like: categories, tags, archives etc. More »

This is default featured slide 4 title

You can completely customize the featured slides from the theme theme options page. You can also easily hide the slider from certain part of your site like: categories, tags, archives etc. More »

This is default featured slide 5 title

You can completely customize the featured slides from the theme theme options page. You can also easily hide the slider from certain part of your site like: categories, tags, archives etc. More »

 

Android Advanced Concepts Tutorial

Android Drag and Drop

Android drag/drop framework allows your users to move data from one View to another View in the current layout using a graphical drag and drop gesture. The framework includes following three important components to support drag & drop functionality:

  • Drag event class:
  • Drag listeners:
  • Helper methods and classes:

The Drag/Drop Process

There are basically four steps or states in the drag and drop process:

  • Started: This event occurs when you start dragging an item in a layout, your application callsstartDrag() method to tell the system to start a drag. The arguments inside startDrag() method provide the data to be dragged, metadata for this data, and a callback for drawing the drag shadow.

    The system first responds by calling back to your application to get a drag shadow. It then displays the drag shadow on the device.

    Next, the system sends a drag event with action type ACTION_DRAG_STARTED to the registered drag event listeners for all the View objects in the current layout.

    To continue to receive drag events, including a possible drop event, a drag event listener must return true, If the drag event listener returns false, then it will not receive drag events for the current operation until the system sends a drag event with action type ACTION_DRAG_ENDED.

  • Continuing: The user continues the drag. System sends ACTION_DRAG_ENTERED action followed by ACTION_DRAG_LOCATION action to the registered drag event listener for the View where dragging point enters. The listener may choose to alter its View object’s appearance in response to the event or can react by highlighting its View.

    The drag event listener receives a ACTION_DRAG_EXITED action after the user has moved the drag shadow outside the bounding box of the View.

  • Dropped: The user releases the dragged item within the bounding box of a View. The system sends the View object’s listener a drag event with action type ACTION_DROP.
  • Ended: Just after the action type ACTION_DROP, the system sends out a drag event with action type ACTION_DRAG_ENDED to indicate that the drag operation is over.

The DragEvent Class

The DragEvent represents an event that is sent out by the system at various times during a drag and drop operation. This class provides few Constants and important methods which we use during Drag/Drop process.

CONSTANTS

Following are all constants integers available as a part of DragEvent class.

S.N. Constants & Description
1 ACTION_DRAG_STARTED
Signals the start of a drag and drop operation.
2 ACTION_DRAG_ENTERED
Signals to a View that the drag point has entered the bounding box of the View.
3 ACTION_DRAG_LOCATION
Sent to a View after ACTION_DRAG_ENTERED if the drag shadow is still within the View object’s bounding box.
4 ACTION_DRAG_EXITED
Signals that the user has moved the drag shadow outside the bounding box of the View.
5 ACTION_DROP
Signals to a View that the user has released the drag shadow, and the drag point is within the bounding box of the View.
6 ACTION_DRAG_ENDED
Signals to a View that the drag and drop operation has concluded.

METHODS

Following are few important and most frequently used methods available as a part of DragEvent class.

S.N. Constants & Description
1 int getAction()
Inspect the action value of this event..
2 ClipData getClipData()
Returns the ClipData object sent to the system as part of the call to startDrag().
3 ClipDescription getClipDescription()
Returns the ClipDescription object contained in the ClipData.
4 boolean getResult()
Returns an indication of the result of the drag and drop operation.
5 float getX()
Gets the X coordinate of the drag point.
6 float getY()
Gets the Y coordinate of the drag point.
7 String toString()
Returns a string representation of this DragEvent object.

Listening for Drag Event

If you want any of your views within a Layout should respond Drag event then your view either implements View.OnDragListener or setup onDragEvent(DragEvent) callback method. When the system calls the method or listener, it passes to them a DragEvent object explained above. You can have both a listener and a callback method for View object. If this occurs, the system first calls the listener and then defined callback as long as listener returns true.

The combination of the onDragEvent(DragEvent) method and View.OnDragListener is analogous to the combination of the onTouchEvent() and View.OnTouchListener used with touch events in old versions of Android.

Starting a Drag Event

You start with creating a ClipData and ClipData.Item for the data being moved. As part of the ClipDataobject, supply metadata that is stored in a ClipDescription object within the ClipData. For a drag and drop operation that does not represent data movement, you may want to use null instead of an actual object.

Next either you can extend extend View.DragShadowBuilder to create a drag shadow for dragging the view or simply you can use View.DragShadowBuilder(View) to create a default drag shadow that’s the same size as the View argument passed to it, with the touch point centered in the drag shadow.

Example

Following example shows the functionality of a simple Drag & Drop using aView.setOnLongClickListener() event listener along with View.OnDragEventListener().

Step Description
1 You will use Eclipse IDE to create an Android application and name it as DragNDropDemo under a package com.example.dragndropdemo. While creating this project, make sure you Target SDKand Compile With at the latest version of Android SDK to use higher levels of APIs.
2 Modify src/MainActivity.java file and add the code to define event listeners as well as a call back methods for the logo image used in the example.
3 Copy image logo.png in res/drawable-* folders. You can use images with different resolution in case you want to provide them for different devices.
4 Modify layout XML file res/layout/activity_main.xml to define default view of the logo images.
5 Run the application to launch Android emulator and verify the result of the changes done in the aplication.

Following is the content of the modified main activity filesrc/com.example.dragndropdemo/MainActivity.java. This file can include each of the fundamental lifecycle methods.

package com.example.dragndropdemo;

import android.os.Bundle;
import android.app.Activity;
import android.content.ClipData;
import android.content.ClipDescription;
import android.util.Log;
import android.view.DragEvent;
import android.view.View;
import android.view.View.DragShadowBuilder;
import android.view.View.OnDragListener;
import android.widget.*;

public class MainActivity extends Activity{
   ImageView ima;
   private static final String IMAGEVIEW_TAG = "Android Logo";
   String msg;

   private android.widget.RelativeLayout.LayoutParams layoutParams;

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

      ima = (ImageView)findViewById(R.id.iv_logo);
      // Sets the tag
      ima.setTag(IMAGEVIEW_TAG);

      ima.setOnLongClickListener(new View.OnLongClickListener() {
         @Override
         public boolean onLongClick(View v) {
            ClipData.Item item = new ClipData.Item((CharSequence)v.getTag());

            String[] mimeTypes = {ClipDescription.MIMETYPE_TEXT_PLAIN};
            ClipData dragData = new ClipData(v.getTag().toString(), 
            mimeTypes, item);

            // Instantiates the drag shadow builder.
            View.DragShadowBuilder myShadow = new DragShadowBuilder(ima);

            // Starts the drag
            v.startDrag(dragData,  // the data to be dragged
            myShadow,  // the drag shadow builder
            null,      // no need to use local data
            0          // flags (not currently used, set to 0)
            );
            return true;
         }
      });

      // Create and set the drag event listener for the View
      ima.setOnDragListener( new OnDragListener(){
         @Override
         public boolean onDrag(View v,  DragEvent event){
         switch(event.getAction())                   
         {
            case DragEvent.ACTION_DRAG_STARTED:
               layoutParams = (RelativeLayout.LayoutParams) 
               v.getLayoutParams();
               Log.d(msg, "Action is DragEvent.ACTION_DRAG_STARTED");
               // Do nothing
               break;
            case DragEvent.ACTION_DRAG_ENTERED:
               Log.d(msg, "Action is DragEvent.ACTION_DRAG_ENTERED");
               int x_cord = (int) event.getX();
               int y_cord = (int) event.getY();  
               break;
            case DragEvent.ACTION_DRAG_EXITED :
               Log.d(msg, "Action is DragEvent.ACTION_DRAG_EXITED");
               x_cord = (int) event.getX();
               y_cord = (int) event.getY();
               layoutParams.leftMargin = x_cord;
               layoutParams.topMargin = y_cord;
               v.setLayoutParams(layoutParams);
               break;
            case DragEvent.ACTION_DRAG_LOCATION  :
               Log.d(msg, "Action is DragEvent.ACTION_DRAG_LOCATION");
               x_cord = (int) event.getX();
               y_cord = (int) event.getY();
               break;
            case DragEvent.ACTION_DRAG_ENDED   :
               Log.d(msg, "Action is DragEvent.ACTION_DRAG_ENDED");
               // Do nothing
               break;
            case DragEvent.ACTION_DROP:
               Log.d(msg, "ACTION_DROP event");
               // Do nothing
               break;
            default: break;
            }
            return true;
         }
      });
   }
}

Following will be the content of res/layout/activity_main.xml file:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/container"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >
	
    <ImageView
		android:id="@+id/iv_logo" 
    	android:layout_width="wrap_content" 
    	android:layout_height="wrap_content"
    	android:src="@drawable/logo"
    	android:contentDescription="@string/drag_drop"  />
	   
</RelativeLayout>

Following will be the content of res/values/strings.xml to define two new constants:

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <string name="app_name">DragNDropDemo</string>
    <string name="action_settings">Settings</string>
    <string name="hello_world">Hello world!</string>
    <string name="drag_drop">Click on the image to drag and drop</string>
   
</resources>

Following is the default content of AndroidManifest.xml:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.guidemo"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="16"
        android:targetSdkVersion="17" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.example.guidemo.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

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

</manifest>

Let’s try to run your DragNDropDemo application. I assume you had created your AVD while doing environment setup. To run the app from Eclipse, open one of your project’s activity files and click Run Eclipse Run Icon icon from the toolbar. Eclipse installs the app on your AVD and starts it and if everything is fine with your setup and application, it will display following Emulator window:

Android Drag and Drop

Now do long click on the displayed android logo and you will see that logo image moves a little after 1 seconds long click from its place, its the time when you should start dragging the image. You can drag it around the screen and drop it at a new location.

Android Drop to New Location

Android Notifications

 

Android Toast class provides a handy way to show users alerts but problem is that these alerts are not persistent which means alert flashes on the screen for a few seconds and then disappears.

For important messages to be given to the user, it is required to have more persistent method. Anotification is a message you can display as an icon at the top of the device which we call notification bar or status bar.

Android Notification Bar

To see the details of the notification, you will have to select the icon which will display notification drawer having detail about the notification. While working with emulator with virtual device, you will have to click and drag down the status bar to expand it which will give you detail as follows. This will be just 64 dp tall and called normal view.

Android Notification Detail

Above expanded form can have a Big View which will have additional detail about the notification. You can add upto six additional lines in the notifciation. The following screenshot shows such notification.

Android Notification Big View

Create and Send Notifications

You have simple way to create a notification. Follow the following steps in your application to create a notification:

STEP 1 – CREATE NOTIFICATION BUILDER

As a first step is to create a notification builder using NotificationCompat.Builder.build(). You will use Notification Builder to set various Notification properties like its small and large icons, title, priority etc.

NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this)

STEP 2 – SETTING NOTIFICATION PROPERTIES

Once you have Builder object, you can set its Notification properties using Builder object as per your requirement. But this is mandatory to set at least following:

  • A small icon, set by setSmallIcon()
  • A title, set by setContentTitle()
  • Detail text, set by setContentText()
mBuilder.setSmallIcon(R.drawable.notification_icon);
mBuilder.setContentTitle("Notification Alert, Click Me!");
mBuilder.setContentText("Hi, This is Android Notification Detail!");

You have plenty of optional properties which you can set for your notification. To learn more about them, see the reference documentation for NotificationCompat.Builder.

STEP 3 – ATTACH ACTIONS

This is an optional part and required if you want to attach an action with the notification. An action allows users to go directly from the notification to an Activity in your application, where they can look at one or more events or do further work.

The action is defined by a PendingIntent containing an Intent that starts an Activity in your application. To associate the PendingIntent with a gesture, call the appropriate method of NotificationCompat.Builder. For example, if you want to start Activity when the user clicks the notification text in the notification drawer, you add the PendingIntent by calling setContentIntent().

A PendingIntent object helps you to perform an action on your application’s behalf, often at a later time, without caring of whether or not your application is running.

We take help of stack builder object which will contain an artificial back stack for the started Activity. This ensures that navigating backward from the Activity leads out of your application to the Home screen.

Intent resultIntent = new Intent(this, ResultActivity.class);
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
stackBuilder.addParentStack(ResultActivity.class);

// Adds the Intent that starts the Activity to the top of the stack
stackBuilder.addNextIntent(resultIntent);
PendingIntent resultPendingIntent =
        stackBuilder.getPendingIntent(
            0,
            PendingIntent.FLAG_UPDATE_CURRENT
        );
mBuilder.setContentIntent(resultPendingIntent);

STEP 4 – ISSUE THE NOTIFICATION

Finally, you pass the Notification object to the system by calling NotificationManager.notify() to send your notification. Make sure you call NotificationCompat.Builder.build() method on builder object before notifying it. This method combines all of the options that have been set and return a new Notificationobject.

NotificationManager mNotificationManager =
    (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
    
// notificationID allows you to update the notification later on.
mNotificationManager.notify(notificationID, mBuilder.build());

The NotificationCompat.Builder Class

The NotificationCompat.Builder class allows easier control over all the flags, as well as help constructing the typical notification layouts. Following are few important and most frequently used methods available as a part of NotificationCompat.Builder class.

S.N. Constants & Description
1 Notification build()
Combine all of the options that have been set and return a new Notification object.
2 NotificationCompat.Builder setAutoCancel (boolean autoCancel)
Setting this flag will make it so the notification is automatically canceled when the user clicks it in the panel.
3 NotificationCompat.Builder setContent (RemoteViews views)
Supply a custom RemoteViews to use instead of the standard one.
4 NotificationCompat.Builder setContentInfo (CharSequence info)
Set the large text at the right-hand side of the notification.
5 NotificationCompat.Builder setContentIntent (PendingIntent intent)
Supply a PendingIntent to send when the notification is clicked.
6 NotificationCompat.Builder setContentText (CharSequence text)
Set the text (second row) of the notification, in a standard notification.
7 NotificationCompat.Builder setContentTitle (CharSequence title)
Set the text (first row) of the notification, in a standard notification.
8 NotificationCompat.Builder setDefaults (int defaults)
Set the default notification options that will be used.
9 NotificationCompat.Builder setLargeIcon (Bitmap icon)
Set the large icon that is shown in the ticker and notification.
10 NotificationCompat.Builder setNumber (int number)
Set the large number at the right-hand side of the notification.
11 NotificationCompat.Builder setOngoing (boolean ongoing)
Set whether this is an ongoing notification.
12 NotificationCompat.Builder setSmallIcon (int icon)
Set the small icon to use in the notification layouts.
13 NotificationCompat.Builder setStyle (NotificationCompat.Style style)
Add a rich notification style to be applied at build time.
14 NotificationCompat.Builder setTicker (CharSequence tickerText)
Set the text that is displayed in the status bar when the notification first arrives.
15 NotificationCompat.Builder setVibrate (long[] pattern)
Set the vibration pattern to use.
16 NotificationCompat.Builder setWhen (long when)
Set the time that the event occurred. Notifications in the panel are sorted by this time.

Example

Following example shows the functionality of a Android notification using a NotificationCompat.BuilderClass which has been introduced in Android 4.1.

Step Description
1 You will use Eclipse IDE to create an Android application and name it as NotificationDemo under a package com.example.notificationdemo. While creating this project, make sure you Target SDK and Compile With at the latest version of Android SDK to use higher levels of APIs.
2 Modify src/MainActivity.java file and add the code to define three methods startNotification(), cancelNotification() and updateNotification() to cover maximum functionality related to Android notifications.
3 Create a new Java file src/NotificationView.java, which will be used to display new layout as a part of new activity which will be started when user will click any of the notifications
4 Copy image woman.png in res/drawable-* folders and this image will be used as Notification icons. You can use images with different resolution in case you want to provide them for different devices.
5 Modify layout XML file res/layout/activity_main.xml to add three buttons in linear layout.
6 Create a new layout XML file res/layout/notification.xml. This will be used as layout file for new activity which will start when user will click any of the notifications.
7 Modify res/values/strings.xml to define required constant values
8 Run the application to launch Android emulator and verify the result of the changes done in the aplication.

Following is the content of the modified main activity filesrc/com.example.notificationdemo/MainActivity.java. This file can include each of the fundamental lifecycle methods.

package com.example.notificationdemo;

import android.os.Bundle;
import android.app.Activity;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.TaskStackBuilder;
import android.content.Context;
import android.content.Intent;
import android.support.v4.app.NotificationCompat;
import android.util.Log;
import android.view.View;
import android.widget.Button;

public class MainActivity extends Activity {
   private NotificationManager mNotificationManager;
   private int notificationID = 100;
   private int numMessages = 0;

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

      Button startBtn = (Button) findViewById(R.id.start);
      startBtn.setOnClickListener(new View.OnClickListener() {
         public void onClick(View view) {
            displayNotification();
         }
      });

      Button cancelBtn = (Button) findViewById(R.id.cancel);
      cancelBtn.setOnClickListener(new View.OnClickListener() {
         public void onClick(View view) {
            cancelNotification();
         }
      });
   
      Button updateBtn = (Button) findViewById(R.id.update);
      updateBtn.setOnClickListener(new View.OnClickListener() {
         public void onClick(View view) {
            updateNotification();
         }
      });
   }
   protected void displayNotification() {
      Log.i("Start", "notification");

      /* Invoking the default notification service */
      NotificationCompat.Builder  mBuilder = 
      new NotificationCompat.Builder(this);	

      mBuilder.setContentTitle("New Message");
      mBuilder.setContentText("You've received new message.");
      mBuilder.setTicker("New Message Alert!");
      mBuilder.setSmallIcon(R.drawable.woman);

      /* Increase notification number every time a new notification arrives */
      mBuilder.setNumber(++numMessages);
      
      /* Creates an explicit intent for an Activity in your app */
      Intent resultIntent = new Intent(this, NotificationView.class);

      TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
      stackBuilder.addParentStack(NotificationView.class);

      /* Adds the Intent that starts the Activity to the top of the stack */
      stackBuilder.addNextIntent(resultIntent);
      PendingIntent resultPendingIntent =
         stackBuilder.getPendingIntent(
            0,
            PendingIntent.FLAG_UPDATE_CURRENT
         );

      mBuilder.setContentIntent(resultPendingIntent);

      mNotificationManager =
      (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

      /* notificationID allows you to update the notification later on. */
      mNotificationManager.notify(notificationID, mBuilder.build());
   }

   protected void cancelNotification() {
      Log.i("Cancel", "notification");
      mNotificationManager.cancel(notificationID);
   }

   protected void updateNotification() {
      Log.i("Update", "notification");

      /* Invoking the default notification service */
      NotificationCompat.Builder  mBuilder = 
      new NotificationCompat.Builder(this);	

      mBuilder.setContentTitle("Updated Message");
      mBuilder.setContentText("You've got updated message.");
      mBuilder.setTicker("Updated Message Alert!");
      mBuilder.setSmallIcon(R.drawable.woman);

     /* Increase notification number every time a new notification arrives */
      mBuilder.setNumber(++numMessages);
      
      /* Creates an explicit intent for an Activity in your app */
      Intent resultIntent = new Intent(this, NotificationView.class);

      TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
      stackBuilder.addParentStack(NotificationView.class);

      /* Adds the Intent that starts the Activity to the top of the stack */
      stackBuilder.addNextIntent(resultIntent);
      PendingIntent resultPendingIntent =
         stackBuilder.getPendingIntent(
            0,
            PendingIntent.FLAG_UPDATE_CURRENT
         );

      mBuilder.setContentIntent(resultPendingIntent);

      mNotificationManager =
      (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

      /* Update the existing notification using same notification ID */
      mNotificationManager.notify(notificationID, mBuilder.build());
   }
}

Following is the content of the modified main activity filesrc/com.example.notificationdemo/NotificationView.java.

package com.example.notificationdemo;

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

public class NotificationView extends Activity{
   @Override
   public void onCreate(Bundle savedInstanceState)
   {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.notification);
   }

}

Following will be the content of res/layout/activity_main.xml file:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
   android:layout_width="fill_parent"
   android:layout_height="fill_parent"
   android:orientation="vertical" >

   <Button android:id="@+id/start"
   android:layout_width="fill_parent"
   android:layout_height="wrap_content"
   android:text="@string/start_note"/>


   <Button android:id="@+id/cancel"
   android:layout_width="fill_parent"
   android:layout_height="wrap_content"
   android:text="@string/cancel_note" />
   
   <Button android:id="@+id/update"
   android:layout_width="fill_parent"
   android:layout_height="wrap_content"
   android:text="@string/update_note" />

</LinearLayout>

Following will be the content of res/layout/notification.xml file:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"    >
   <TextView
   android:layout_width="fill_parent"
   android:layout_height="400dp"
   android:text="Hi, Your Detailed notification view goes here...." />
</LinearLayout>

Following will be the content of res/values/strings.xml to define two new constants:

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <string name="app_name">NotificationDemo</string>
    <string name="action_settings">Settings</string>
    <string name="hello_world">Hello world!</string>
    <string name="start_note">Start Notification</string>
    <string name="cancel_note">Cancel Notification</string>
    <string name="update_note">Update Notification</string>

</resources>

Following is the default content of AndroidManifest.xml:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.notificationdemo"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="17"
        android:targetSdkVersion="17" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.example.notificationdemo.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity android:name=".NotificationView"
             android:label="Details of notification"
             android:parentActivityName=".MainActivity">
       <meta-data
        android:name="android.support.PARENT_ACTIVITY"
        android:value=".MainActivity"/>
        </activity>
    </application>

</manifest>

Let’s try to run your NotificationDemo application. I assume you had created your AVD while doing environment setup. To run the app from Eclipse, open one of your project’s activity files and click Run Eclipse Run Icon icon from the toolbar. Eclipse installs the app on your AVD and starts it and if everything is fine with your setup and application, it will display following Emulator window:

Android Notification Start

Now click Start Notification button, you will see at the top a message “New Message Alert!” will display momentarily and after that you will have following screen having a small icon at the top left corner.

Android Notification Start Icon

Now lets expand the view, long click on the small icon, after a second it will display date information and this is the time when you should drag status bar down without releasing mouse. You will see status bar will expand and you will get following screen:

Android Notification Expanded

Now let’s try to click on the image icon, this will launch your new activity which you have set using intent and you will have following screen:

Android Notification New Activity

Next, you can click on “Detail of notification” and it will take you back to the main screen where you can try using Update Notification button which will update existing notification and number will increase by 1 but if you will send notification with new notification ID then it will keep adding in the stack and you see them separately listed on the screen.

Big View Notification

The following code snippet demonstrates how to alter the notification created in the previous snippet to use the Inbox big view style. I’m going to update displayNotification() modification method to show this functionality:

   protected void displayNotification() {
      Log.i("Start", "notification");

      /* Invoking the default notification service */
      NotificationCompat.Builder  mBuilder = 
      new NotificationCompat.Builder(this);	

      mBuilder.setContentTitle("New Message");
      mBuilder.setContentText("You've received new message.");
      mBuilder.setTicker("New Message Alert!");
      mBuilder.setSmallIcon(R.drawable.woman);

      /* Increase notification number every time a new notification arrives */
      mBuilder.setNumber(++numMessages);


      /* Add Big View Specific Configuration */
      NotificationCompat.InboxStyle inboxStyle =
             new NotificationCompat.InboxStyle();

      String[] events = new String[6];
      events[0] = new String("This is first line....");
      events[1] = new String("This is second line...");
      events[2] = new String("This is third line...");
      events[3] = new String("This is 4th line...");
      events[4] = new String("This is 5th line...");
      events[5] = new String("This is 6th line...");

      // Sets a title for the Inbox style big view
      inboxStyle.setBigContentTitle("Big Title Details:");
      // Moves events into the big view
      for (int i=0; i < events.length; i++) {

         inboxStyle.addLine(events[i]);
      }
      mBuilder.setStyle(inboxStyle);
       
      
      /* Creates an explicit intent for an Activity in your app */
      Intent resultIntent = new Intent(this, NotificationView.class);

      TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
      stackBuilder.addParentStack(NotificationView.class);

      /* Adds the Intent that starts the Activity to the top of the stack */
      stackBuilder.addNextIntent(resultIntent);
      PendingIntent resultPendingIntent =
         stackBuilder.getPendingIntent(
            0,
            PendingIntent.FLAG_UPDATE_CURRENT
         );

      mBuilder.setContentIntent(resultPendingIntent);

      mNotificationManager =
      (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

      /* notificationID allows you to update the notification later on. */
      mNotificationManager.notify(notificationID, mBuilder.build());
   }

Now if you will try to run your application then you will find following result in expanded form of the view:

Android Notification Big View

 

Android Location Based Services

Android location APIs make it easy for you to build location-aware applications, without needing to focus on the details of the underlying location technology. This becomes possible with the help of Google Play services, which facilitates adding location awareness to your app with automated location tracking, geofencing, and activity recognition.

This tutorial shows you how to use Location Services in your app to get the current location, get periodic location updates, look up addresses etc.

The Location Object

The Location object represents a geographic location which can consist of a latitude, longitude, timestamp, and other information such as bearing, altitude and velocity. There are following important methods which you can use with Location object to get location specific information:

S.N. Method & Description
1 float distanceTo(Location dest)
Returns the approximate distance in meters between this location and the given location.
2 float getAccuracy()
Get the estimated accuracy of this location, in meters.
3 double getAltitude()
Get the altitude if available, in meters above sea level.
4 float getBearing()
Get the bearing, in degrees.
5 double getLatitude()
Get the latitude, in degrees.
6 double getLongitude()
Get the longitude, in degrees.
7 float getSpeed()
Get the speed if it is available, in meters/second over ground.
8 boolean hasAccuracy()
True if this location has an accuracy.
9 boolean hasAltitude()
True if this location has an altitude.
10 boolean hasBearing()
True if this location has a bearing.
11 boolean hasSpeed()
True if this location has a speed.
12 void reset()
Clears the contents of the location.
13 void setAccuracy(float accuracy)
Set the estimated accuracy of this location, meters.
14 void setAltitude(double altitude)
Set the altitude, in meters above sea level.
15 void setBearing(float bearing)
Set the bearing, in degrees.
16 void setLatitude(double latitude)
Set the latitude, in degrees.
17 void setLongitude(double longitude)
Set the longitude, in degrees.
18 void setSpeed(float speed)
Set the speed, in meters/second over ground.
19 String toString()
Returns a string containing a concise, human-readable description of this object.

Get the Current Location

To get the current location, create a location client which is LocationClient object, connect it to Location Services using connect() method, and then call its getLastLocation() method. This method returns the most recent location in the form of Location object that contains latitude and longitude coordinates and other information as explained above. To have location based functionality in your activity, you will have to implement two interfaces:

  • GooglePlayServicesClient.ConnectionCallbacks
  • GooglePlayServicesClient.OnConnectionFailedListener

These interfaces provide following important callback methods, which you need to implement in your activity class:

S.N. Callback Methods & Description
1 abstract void onConnected(Bundle connectionHint)
This callback method is called when location service is connected to the location client successfully. You will use connect() method to connect to the location client.
2 abstract void onDisconnected()
This callback method is called when the client is disconnected. You will use disconnect()method to disconnect from the location client.
3 abstract void onConnectionFailed(ConnectionResult result)
This callback method is called when there was an error connecting the client to the service.

You should create the location client in onCreate() method of your activity class, then connect it inonStart(), so that Location Services maintains the current location while your activity is fully visible. You should disconnect the client in onStop() method, so that when your app is not visible, Location Services is not maintaining the current location. This helps in saving battery power up-to a large extent.

Get the Updated Location

If you are willing to have location updates, then apart from above mentioned interfaces, you will need to implement LocationListener interface as well. This interface provide following callback method, which you need to implement in your activity class:

S.N. Callback Method & Description
1 abstract void onLocationChanged(Location location)
This callback method is used for receiving notifications from the LocationClient when the location has changed.

Location Quality of Service

The LocationRequest object is used to request a quality of service (QoS) for location updates from theLocationClient. There are following useful setter methods which you can use to handle QoS. There are equivalent getter methods available which you can check in Android official documentation.

S.N. Method & Description
1 setExpirationDuration(long millis)
Set the duration of this request, in milliseconds.
2 setExpirationTime(long millis)
Set the request expiration time, in millisecond since boot.
3 setFastestInterval(long millis)
Explicitly set the fastest interval for location updates, in milliseconds.
4 setInterval(long millis)
Set the desired interval for active location updates, in milliseconds.
5 setNumUpdates(int numUpdates)
Set the number of location updates.
6 setPriority(int priority)
Set the priority of the request.

Now for example, if your application wants high accuracy location it should create a location request withsetPriority(int) set to PRIORITY_HIGH_ACCURACY and setInterval(long) to 5 seconds. You can also use bigger interval and/or other priorities like PRIORITY_LOW_POWER for to request “city” level accuracy or PRIORITY_BALANCED_POWER_ACCURACY for “block” level accuracy.

Activities should strongly consider removing all location request when entering the background (for example at onPause()), or at least swap the request to a larger interval and lower quality to save power consumption.

Displaying a Location Address

Once you have Location object, you can use Geocoder.getFromLocation() method to get an address for a given latitude and longitude. This method is synchronous, and may take a long time to do its work, so you should call the method from the doInBackground() method of an AsyncTask class.

The AsyncTask must be subclassed to be used and the subclass will overridedoInBackground(Params…) method to perform a task in the background and onPostExecute(Result)method is invoked on the UI thread after the background computation finishes and at the time to display the result. There is one more important method available in AyncTask which is execute(Params… params), this method executes the task with the specified parameters.

Check following example to have better understanding on how we use AynchTask in any Android application to get work done in the background without interfering main task.

Example

Following example shows you in practical how to to use Location Services in your app to get the current location and its equivalent addresses etc.

To experiment with this example, you will need actual Mobile device equipped with latest Android OS, otherwise you will have to struggle with emulator which may not work.

INSTALL THE GOOGLE PLAY SERVICES SDK

Before you proceed to have location support in your Android Applications, you neet to setup Google Play Services SDK using following simple steps:

Steps Description
1 Launch the SDK Manager.

  • From Eclipse (with ADT), select Window > Android SDK Manager.
  • On Windows, double-click the SDK Manager.exe file at the root of the Android SDK directory.
  • On Mac or Linux, open a terminal and navigate to the tools/ directory in the Android SDK directory, then execute android sdk.
2 Search for Google Play services option from the given package list under Extra and if its not installed, then install it. The Google Play services SDK is saved in your Android SDK environment at <android-sdk>/extras/google/google_play_services/.
3 Copy the library project at <android-sdk>/extras/google/google_play_services/libproject/google-play-services_lib/ to the location where you maintain your Android app projects. If you are using Eclipse, import the library project into your workspace. Click File > Import, select Android > Existing Android Code into Workspace, and browse to <android-sdk>/extras/google/google_play_services/libproject/, library project to import it.

CREATE ANDROID APPLICATION

Step Description
1 You will use Eclipse IDE to create an Android application and name it as LBSDemo/i> under a package com.example.lbsdemo. While creating this project, make sure you Target SDK andCompile With at the latest version of Android SDK to use higher levels of APIs.
2 Add Google Play Service library in your project by following simple steps given below.
3 Modify src/MainActivity.java file and add required code as shown below to take care of getting current location and its equivalent address.
4 Modify layout XML file res/layout/activity_main.xml to add all GUI components which include three buttons and two text views to show location/address.
5 Modify res/values/strings.xml to define required constant values
6 Modify AndroidManifest.xml as shown below
7 Run the application to launch Android emulator and verify the result of the changes done in the aplication.

Let’s add Google Play Service reference in the project. Right click on the project and select Build Path > Configure Build Path > Android > and then click Add button which will show google-play-service_liboption to be added, just double click on it, which will add required library reference and you will have window as follows:

Google Play Service

Following is the content of the modified main activity file src/com.example.lbsdemo/MainActivity.java.

package com.example.lbsdemo;

import java.io.IOException;
import java.util.List;
import java.util.Locale;

import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesClient;
import com.google.android.gms.location.LocationClient;

import android.content.Context;
import android.location.Address;
import android.location.Geocoder;
import android.location.Location;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;

import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends FragmentActivity implements
GooglePlayServicesClient.ConnectionCallbacks,
GooglePlayServicesClient.OnConnectionFailedListener
{
   LocationClient mLocationClient;
   private TextView addressLabel;
   private TextView locationLabel;
   private Button getLocationBtn;
   private Button disconnectBtn;
   private Button connectBtn;

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

      locationLabel = (TextView) findViewById(R.id.locationLabel);
      addressLabel = (TextView) findViewById(R.id.addressLabel);
      getLocationBtn = (Button) findViewById(R.id.getLocation);

      getLocationBtn.setOnClickListener(new View.OnClickListener() {
         public void onClick(View view) {
            displayCurrentLocation();
         }
      });
      disconnectBtn = (Button) findViewById(R.id.disconnect);  
      disconnectBtn.setOnClickListener(new View.OnClickListener() {
         public void onClick(View view) {
            mLocationClient.disconnect();
            locationLabel.setText("Got disconnected....");
         }
      });
      connectBtn = (Button) findViewById(R.id.connect);  
      connectBtn.setOnClickListener(new View.OnClickListener() {
         public void onClick(View view) {
            mLocationClient.connect();
            locationLabel.setText("Got connected....");
         }
      });	
      // Create the LocationRequest object
      mLocationClient = new LocationClient(this, this, this);	
   }	
   @Override
   protected void onStart() {
      super.onStart();
      // Connect the client.
      mLocationClient.connect();
      locationLabel.setText("Got connected....");
   }
   @Override
   protected void onStop() {
      // Disconnect the client.
      mLocationClient.disconnect();
      super.onStop();
      locationLabel.setText("Got disconnected....");
   }
   @Override
   public void onConnected(Bundle dataBundle) {
      // Display the connection status
      Toast.makeText(this, "Connected", Toast.LENGTH_SHORT).show();
   }
   @Override
   public void onDisconnected() {
      // Display the connection status
      Toast.makeText(this, "Disconnected. Please re-connect.",
      Toast.LENGTH_SHORT).show();
   }
   @Override
   public void onConnectionFailed(ConnectionResult connectionResult) {
      // Display the error code on failure
      Toast.makeText(this, "Connection Failure : " + 
      connectionResult.getErrorCode(),
      Toast.LENGTH_SHORT).show();
   }
   public void displayCurrentLocation() {
      // Get the current location's latitude & longitude
      Location currentLocation = mLocationClient.getLastLocation();
      String msg = "Current Location: " +
      Double.toString(currentLocation.getLatitude()) + "," +
      Double.toString(currentLocation.getLongitude());
     
      // Display the current location in the UI
      locationLabel.setText(msg);
      
      // To display the current address in the UI
      (new GetAddressTask(this)).execute(currentLocation);
   }
   /*
    * Following is a subclass of AsyncTask which has been used to get
    * address corresponding to the given latitude & longitude.
    */
   private class GetAddressTask extends AsyncTask<Location, Void, String>{
      Context mContext;
      public GetAddressTask(Context context) {
         super();
         mContext = context;
      }

      /*
       * When the task finishes, onPostExecute() displays the address. 
       */
      @Override
      protected void onPostExecute(String address) {
         // Display the current address in the UI
         addressLabel.setText(address);
      }
      @Override
      protected String doInBackground(Location... params) {
         Geocoder geocoder =
         new Geocoder(mContext, Locale.getDefault());
         // Get the current location from the input parameter list
         Location loc = params[0];
         // Create a list to contain the result address
         List<Address> addresses = null;
         try {
            addresses = geocoder.getFromLocation(loc.getLatitude(),
            loc.getLongitude(), 1);
         } catch (IOException e1) {
            Log.e("LocationSampleActivity", 
            "IO Exception in getFromLocation()");
            e1.printStackTrace();
            return ("IO Exception trying to get address");
         } catch (IllegalArgumentException e2) {
            // Error message to post in the log
            String errorString = "Illegal arguments " +
            Double.toString(loc.getLatitude()) +
            " , " +
            Double.toString(loc.getLongitude()) +
            " passed to address service";
            Log.e("LocationSampleActivity", errorString);
            e2.printStackTrace();
            return errorString;
         }
         // If the reverse geocode returned an address
         if (addresses != null && addresses.size() > 0) {
            // Get the first address
            Address address = addresses.get(0);
            /*
            * Format the first line of address (if available),
            * city, and country name.
            */
            String addressText = String.format(
            "%s, %s, %s",
            // If there's a street address, add it
            address.getMaxAddressLineIndex() > 0 ?
            address.getAddressLine(0) : "",
            // Locality is usually a city
            address.getLocality(),
            // The country of the address
            address.getCountryName());
            // Return the text
            return addressText;
         } else {
            return "No address found";
         }
      }
   }// AsyncTask class
}

Following will be the content of res/layout/activity_main.xml file:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
   android:layout_width="fill_parent"
   android:layout_height="fill_parent"
   android:orientation="vertical" >

   <Button android:id="@+id/getLocation"
   android:layout_width="fill_parent"
   android:layout_height="wrap_content"
   android:text="@string/get_location"/>

   <Button android:id="@+id/disconnect"
   android:layout_width="fill_parent"
   android:layout_height="wrap_content"
   android:text="@string/disconnect"/>
  
   <Button android:id="@+id/connect"
   android:layout_width="fill_parent"
   android:layout_height="wrap_content"
   android:text="@string/connect"/>
      
    <TextView
   android:id="@+id/locationLabel"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"/>
    
   <TextView
   android:id="@+id/addressLabel"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"/>
    
</LinearLayout>

Following will be the content of res/values/strings.xml to define two new constants:

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <string name="app_name">LBSDemo</string>
    <string name="action_settings">Settings</string>
    <string name="hello_world">Hello world!</string>
    <string name="get_location">Get Location</string>
    <string name="disconnect">Disconnect Service</string>
    <string name="connect">Connect Service</string>
</resources>

Following is the default content of AndroidManifest.xml:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.lbsdemo"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="17" />
   <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.example.lbsdemo.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

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

</manifest>

Let’s try to run your LBSDemo application. I assume you have connected your actual Android Mobile device with your computer. To run the app from Eclipse, open one of your project’s activity files and click Run Eclipse Run Icon icon from the toolbar. Before starting your application, Eclipse will display following window to select an option where you want to run your Android application.

Android Mobile Device

Select mobile device as an option and then check your mobile device which will display following screen:

Android Mobile Location Screen

Now to see location select Get Location Button which will display location information as follows:

Android Mobile Location Info

You can try by disconnecting location client using Disconnect Service and then connecting it by usingConnect Service button. You can also modify to get location update as explained above and in Android Official documentation.

Android Sending Email

You have learnt Android Intent, which is an object carrying an intent ie. message from one component to another component with-in the application or outside the application.

As such you do not need to develop your email client from scratch because they are already available like Gmail and K9mail. But you will need to send email from your Android application, where you will have to write an Activity that needs to launch an email client and sends an email using your Android device. For this purpose, your Activity will send an ACTION_SEND along with appropriate data load, to the Android Intent Resolver. The specified chooser gives the proper interface for the user to pick how to send your email data.

Following section explains different parts of our Intent object required to send an email.

Intent Object – Action to send Email

You will use ACTION_SEND action to launch an email client installed on your Android device. Following is simple syntax to create an intent with ACTION_SEND action

Intent emailIntent = new Intent(Intent.ACTION_SEND);

Intent Object – Data/Type to send Email

To send an email you need to specify mailto: as URI using setData() method and data type will be totext/plain using setType() method as follows:

emailIntent.setData(Uri.parse("mailto:"));
emailIntent.setType("text/plain");

Intent Object – Extra to send Email

Android has built-in support to add TO, SUBJECT, CC, TEXT etc. fields which can be attached to the intent before sending the intent to a target email client. You can use following extra fields in your email:

S.N. Extra Data & Description
1 EXTRA_BCC
A String[] holding e-mail addresses that should be blind carbon copied.
2 EXTRA_CC
A String[] holding e-mail addresses that should be carbon copied.
3 EXTRA_EMAIL
A String[] holding e-mail addresses that should be delivered to.
4 EXTRA_HTML_TEXT
A constant String that is associated with the Intent, used with ACTION_SEND to supply an alternative to EXTRA_TEXT as HTML formatted text.
5 EXTRA_SUBJECT
A constant string holding the desired subject line of a message.
6 EXTRA_TEXT
A constant CharSequence that is associated with the Intent, used with ACTION_SEND to supply the literal data to be sent.
7 EXTRA_TITLE
A CharSequence dialog title to provide to the user when used with a ACTION_CHOOSER.

Here is an example showing you how to assign extra data to your intent:

emailIntent.putExtra(Intent.EXTRA_EMAIL  , new String[]{"recipient@example.com"});
emailIntent.putExtra(Intent.EXTRA_SUBJECT, "subject of email");
emailIntent.putExtra(Intent.EXTRA_TEXT   , "body of email");

Example

Following example shows you in practical how to use Intent object to launch Email client to send an Email to the given recipients.

To experiment with this example, you will need actual Mobile device equipped with latest Android OS, otherwise you will have to struggle with emulator which may not work. Second you will need to have an Email client like GMail or K9mail installed on your device.

Step Description
1 You will use Eclipse IDE to create an Android application and name it as SendEmailDemo under a package com.example.sendemaildemo. While creating this project, make sure you Target SDKand Compile With at the latest version of Android SDK to use higher levels of APIs.
2 Modify src/MainActivity.java file and add required code to take care of sending email.
3 Modify layout XML file res/layout/activity_main.xml add any GUI component if required. I’m adding a simple button to launch Email Client.
4 Modify res/values/strings.xml to define required constant values
5 Modify AndroidManifest.xml as shown below
6 Run the application to launch Android emulator and verify the result of the changes done in the aplication.

Following is the content of the modified main activity filesrc/com.example.sendemaildemo/MainActivity.java.

package com.example.sendemaildemo;

import android.net.Uri;
import android.os.Bundle;
import android.app.Activity;
import android.content.Intent;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

public class MainActivity extends Activity {

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

      Button startBtn = (Button) findViewById(R.id.sendEmail);
      startBtn.setOnClickListener(new View.OnClickListener() {
         public void onClick(View view) {
         sendEmail();
      }
   });

   }
   protected void sendEmail() {
      Log.i("Send email", "");

      String[] TO = {"amrood.admin@gmail.com"};
      String[] CC = {"mcmohd@gmail.com"};
      Intent emailIntent = new Intent(Intent.ACTION_SEND);
      emailIntent.setData(Uri.parse("mailto:"));
      emailIntent.setType("text/plain");


      emailIntent.putExtra(Intent.EXTRA_EMAIL, TO);
      emailIntent.putExtra(Intent.EXTRA_CC, CC);
      emailIntent.putExtra(Intent.EXTRA_SUBJECT, "Your subject");
      emailIntent.putExtra(Intent.EXTRA_TEXT, "Email message goes here");

      try {
         startActivity(Intent.createChooser(emailIntent, "Send mail..."));
         finish();
         Log.i("Finished sending email...", "");
      } catch (android.content.ActivityNotFoundException ex) {
         Toast.makeText(MainActivity.this, 
         "There is no email client installed.", Toast.LENGTH_SHORT).show();
      }
   }
   @Override
   public boolean onCreateOptionsMenu(Menu menu) {
      // Inflate the menu; this adds items to the action bar if it is present.
      getMenuInflater().inflate(R.menu.main, menu);
      return true;
   }
}

Following will be the content of res/layout/activity_main.xml file:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
   android:layout_width="fill_parent"
   android:layout_height="fill_parent"
   android:orientation="vertical" >

   <Button android:id="@+id/sendEmail"
   android:layout_width="fill_parent"
   android:layout_height="wrap_content"
   android:text="@string/compose_email"/>
    
</LinearLayout>

Following will be the content of res/values/strings.xml to define two new constants:

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <string name="app_name">SendEmailDemo</string>
    <string name="hello_world">Hello world!</string>
    <string name="action_settings">Settings</string>
    <string name="compose_email">Compose Email</string>

</resources>

Following is the default content of AndroidManifest.xml:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.sendemaildemo"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="17" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.example.sendemaildemo.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

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

Let’s try to run your SendEmailDemo application. I assume you have connected your actual Android Mobile device with your computer. To run the app from Eclipse, open one of your project’s activity files and click Run Eclipse Run Icon icon from the toolbar. Before starting your application, Eclipse will display following window to select an option where you want to run your Android application.

Android Mobile Device

Select your mobile device as an option and then check your mobile device which will display following screen:

Android Mobile Email Compose

Now use Compose Email button to list down all the installed email clients. From the list, you can choose one of email clients to send your email. I’m going to use Gmail client to send my email which will have all the provided defaults fields available as shown below. Here From: will be default email ID you have registered for your Android device.

Android Mobile Gmail Screen

You can modify either of the given default fields and finally use send email button (marked with red rectangle) to send your email to the mentioned recipients.

Android Sending SMS

There are following two ways to send SMS using Android device:

  • Using SmsManager to send SMS
  • Using Built-in Intent to send SMS

Using SmsManager to send SMS

The SmsManager manages SMS operations such as sending data to the given mobile device. You can create this object by calling the static method SmsManager.getDefault() as follows:

SmsManager smsManager = SmsManager.getDefault();

Once you have SmsManager object, you can use sendDataMessage() method to send SMS at the specified mobile number as below:

smsManager.sendTextMessage("phoneNo", null, "SMS text", null, null);

Apart from the above method, there are few other important functions available in SmsManager class. These methods are listed below:

S.N. Method & Description
1 ArrayList<String> divideMessage(String text)
This method divides a message text into several fragments, none bigger than the maximum SMS message size.
2 static SmsManager getDefault()
This method is used to get the default instance of the SmsManager
3 void sendDataMessage(String destinationAddress, String scAddress, short destinationPort, byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent)
This method is used to send a data based SMS to a specific application port.
4 void sendMultipartTextMessage(String destinationAddress, String scAddress, ArrayList<String> parts, ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents)
Send a multi-part text based SMS.
5 void sendTextMessage(String destinationAddress, String scAddress, String text, PendingIntent sentIntent, PendingIntent deliveryIntent)
Send a text based SMS.

Example

Following example shows you in practical how to use SmsManager object to send an SMS to the given mobile number.

To experiment with this example, you will need actual Mobile device equipped with latest Android OS, otherwise you will have to struggle with emulator which may not work.

Step Description
1 You will use Eclipse IDE to create an Android application and name it as SendSMSDemo under a package com.example.sendsmsdemo. While creating this project, make sure you Target SDKand Compile With at the latest version of Android SDK to use higher levels of APIs.
2 Modify src/MainActivity.java file and add required code to take care of sending email.
3 Modify layout XML file res/layout/activity_main.xml add any GUI component if required. I’m adding a simple GUI to take mobile number and SMS text to be sent and a simple button to send SMS.
4 Modify res/values/strings.xml to define required constant values
5 Modify AndroidManifest.xml as shown below
6 Run the application to launch Android emulator and verify the result of the changes done in the aplication.

Following is the content of the modified main activity filesrc/com.example.sendsmsdemo/MainActivity.java.

package com.example.sendsmsdemo;

import android.os.Bundle;
import android.app.Activity;
import android.telephony.SmsManager;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

public class MainActivity extends Activity {

   Button sendBtn;
   EditText txtphoneNo;
   EditText txtMessage;

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

      sendBtn = (Button) findViewById(R.id.btnSendSMS);
      txtphoneNo = (EditText) findViewById(R.id.editTextPhoneNo);
      txtMessage = (EditText) findViewById(R.id.editTextSMS);

      sendBtn.setOnClickListener(new View.OnClickListener() {
         public void onClick(View view) {
            sendSMSMessage();
         }
      });

   }
   protected void sendSMSMessage() {
      Log.i("Send SMS", "");

      String phoneNo = txtphoneNo.getText().toString();
      String message = txtMessage.getText().toString();

      try {
         SmsManager smsManager = SmsManager.getDefault();
         smsManager.sendTextMessage(phoneNo, null, message, null, null);
         Toast.makeText(getApplicationContext(), "SMS sent.",
         Toast.LENGTH_LONG).show();
      } catch (Exception e) {
         Toast.makeText(getApplicationContext(),
         "SMS faild, please try again.",
         Toast.LENGTH_LONG).show();
         e.printStackTrace();
      }
   }
   @Override
   public boolean onCreateOptionsMenu(Menu menu) {
      // Inflate the menu; this adds items to the action bar if it is present.
      getMenuInflater().inflate(R.menu.main, menu);
      return true;
   }
}

Following will be the content of res/layout/activity_main.xml file:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >

   <TextView
   android:id="@+id/textViewPhoneNo"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:text="@string/phone_label" />

   <EditText
   android:id="@+id/editTextPhoneNo"
   android:layout_width="fill_parent"
   android:layout_height="wrap_content"
   android:inputType="phone"/>

   <TextView
   android:id="@+id/textViewMessage"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:text="@string/sms_label" />

   <EditText
   android:id="@+id/editTextSMS"
   android:layout_width="fill_parent"
   android:layout_height="wrap_content"
   android:inputType="textMultiLine"/>

   <Button android:id="@+id/btnSendSMS"
   android:layout_width="fill_parent"
   android:layout_height="wrap_content"
   android:text="@string/send_sms_label"/>

</LinearLayout>

Following will be the content of res/values/strings.xml to define two new constants:

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <string name="app_name">SendSMSDemo</string>
    <string name="action_settings">Settings</string>
    <string name="hello_world">Hello world!</string>
    <string name="phone_label">Enter Phone Number:</string>
    <string name="sms_label">Enter SMS Message:</string>
    <string name="send_sms_label">Send SMS</string>
    
</resources>

Following is the default content of AndroidManifest.xml:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.sendsmsdemo"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="17" />
    <uses-permission android:name="android.permission.SEND_SMS" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.example.sendsmsdemo.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

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

</manifest>

Let’s try to run your SendSMSDemo application. I assume you have connected your actual Android Mobile device with your computer. To run the app from Eclipse, open one of your project’s activity files and click Run Eclipse Run Icon icon from the toolbar. Before starting your application, Eclipse will display following window to select an option where you want to run your Android application.

Android Mobile Device

Select your mobile device as an option and then check your mobile device which will display following screen:

Android Mobile SMS Compose

Now you can enter a desired mobile number and a text message to be sent on that number. Finally click on Send SMS button to send your SMS. Make sure your GSM connection is working fine to deliver your SMS to its recipient.

You can take a number of SMS separated by comma and then inside your program you will have to parse them into an array string and finally you can use a loop to send message to all the given numbers. That’s how you can write your own SMS client. Next section will show you how to use existing SMS client to send SMS.

Using Built-in Intent to send SMS

You can use Android Intent to send SMS by calling built-in SMS functionality of the Android. Following section explains different parts of our Intent object required to send an SMS.

Intent Object – Action to send SMS

You will use ACTION_VIEW action to launch an SMS client installed on your Android device. Following is simple syntax to create an intent with ACTION_VIEW action

Intent smsIntent = new Intent(Intent.ACTION_VIEW);

Intent Object – Data/Type to send SMS

To send an SMS you need to specify smsto: as URI using setData() method and data type will be tovnd.android-dir/mms-sms using setType() method as follows:

smsIntent.setData(Uri.parse("smsto:"));
smsIntent.setType("vnd.android-dir/mms-sms");

Intent Object – Extra to send SMS

Android has built-in support to add phone number and text message to send an SMS as follows:

smsIntent.putExtra("address"  , new String("0123456789;3393993300"));
smsIntent.putExtra("sms_body"  , "Test SMS to Angilla");

Here address and sms_body are case sensitive and should be specified in small characters only. You can specify more than one number in single string but separated by semi-colon (;).

Example

Following example shows you in practical how to use Intent object to launch SMS client to send an SMS to the given recipients.

To experiment with this example, you will need actual Mobile device equipped with latest Android OS, otherwise you will have to struggle with emulator which may not work.

Step Description
1 You will use Eclipse IDE to create an Android application and name it as SendSMSDemo under a package com.example.sendsmsdemo. While creating this project, make sure you Target SDKand Compile With at the latest version of Android SDK to use higher levels of APIs.
2 Modify src/MainActivity.java file and add required code to take care of sending SMS.
3 Modify layout XML file res/layout/activity_main.xml add any GUI component if required. I’m adding a simple button to launch SMS Client.
4 Modify res/values/strings.xml to define required constant values
5 Modify AndroidManifest.xml as shown below
6 Run the application to launch Android emulator and verify the result of the changes done in the aplication.

Following is the content of the modified main activity filesrc/com.example.sendsmsdemo/MainActivity.java.

package com.example.sendsmsdemo;

import android.net.Uri;
import android.os.Bundle;
import android.app.Activity;
import android.content.Intent;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

public class MainActivity extends Activity {

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

      Button startBtn = (Button) findViewById(R.id.sendSMS);
      startBtn.setOnClickListener(new View.OnClickListener() {
         public void onClick(View view) {
         sendSMS();
      }
   });

   }
   protected void sendSMS() {
      Log.i("Send SMS", "");

      Intent smsIntent = new Intent(Intent.ACTION_VIEW);
      smsIntent.setData(Uri.parse("smsto:"));
      smsIntent.setType("vnd.android-dir/mms-sms");

      smsIntent.putExtra("address"  , new String ("0123456789"));
      smsIntent.putExtra("sms_body"  , "Test SMS to Angilla");
      try {
         startActivity(smsIntent);
         finish();
         Log.i("Finished sending SMS...", "");
      } catch (android.content.ActivityNotFoundException ex) {
         Toast.makeText(MainActivity.this, 
         "SMS faild, please try again later.", Toast.LENGTH_SHORT).show();
      }
   }
   @Override
   public boolean onCreateOptionsMenu(Menu menu) {
      // Inflate the menu; this adds items to the action bar if it is present.
      getMenuInflater().inflate(R.menu.main, menu);
      return true;
   }
}

Following will be the content of res/layout/activity_main.xml file:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
   android:layout_width="fill_parent"
   android:layout_height="fill_parent"
   android:orientation="vertical" >

   <Button android:id="@+id/sendSMS"
   android:layout_width="fill_parent"
   android:layout_height="wrap_content"
   android:text="@string/compose_sms"/>
    
</LinearLayout>

Following will be the content of res/values/strings.xml to define two new constants:

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <string name="app_name">SendSMSDemo</string>
    <string name="hello_world">Hello world!</string>
    <string name="action_settings">Settings</string>
    <string name="compose_sms">Compose SMS</string>

</resources>

Following is the default content of AndroidManifest.xml:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.sendsmsdemo"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="17" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.example.sendsmsdemo.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

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

Let’s try to run your SendSMSDemo application. I assume you have connected your actual Android Mobile device with your computer. To run the app from Eclipse, open one of your project’s activity files and click Run Eclipse Run Icon icon from the toolbar. Before starting your application, Eclipse will display following window to select an option where you want to run your Android application.

Android Mobile Device

Select your mobile device as an option and then check your mobile device which will display following screen:

Android Mobile SMS Compose

Now use Compose SMS button to launch Android built-in SMS clients which is shown below:

Android Mobile SMS Screen

You can modify either of the given default fields and finally use send SMS button (marked with red rectangle) to send your SMS to the mentioned recipient.

Android Phone Calls

As such every Android Device specially Mobile phone is meant to provide a functionality to make a phone call but still you may need to write an application where you want to give an option to your user to make a call using a hard coded phone number.

This chapter lists down all the simple steps to create an application which can be used to make a Phone Call. You can use Android Intent to make phone call by calling built-in Phone Call functionality of the Android. Following section explains different parts of our Intent object required to make a call.

Intent Object – Action to make Phone Call

You will use ACTION_CALL action to trigger built-in phone call functionality available in Android device. Following is simple syntax to create an intent with ACTION_CALL action

Intent phoneIntent = new Intent(Intent.ACTION_CALL);

You can use ACTION_DIAL action instead of ACTION_CALL, in that case you will have option to modify hardcoded phone number before making a call instead of making a direct call.

Intent Object – Data/Type to make Phone Call

To make a phone call at a given number 91-800-001-0101, you need to specify tel: as URI using setData() method as follows:

phoneIntent.setData(Uri.parse("tel:91-800-001-0101"));

The interesting point is that, to make a phone call, you do not need to specify any extra data or data type.

Example

Following example shows you in practical how to use Android Intent to make phone call to the given mobile number.

To experiment with this example, you will need actual Mobile device equipped with latest Android OS, otherwise you will have to struggle with emulator which may not work.

Step Description
1 You will use Eclipse IDE to create an Android application and name it as PhoneCallDemo under a package com.example.phonecalldemo. While creating this project, make sure you Target SDKand Compile With at the latest version of Android SDK to use higher levels of APIs.
2 Modify src/MainActivity.java file and add required code to take care of making a call.
3 Modify layout XML file res/layout/activity_main.xml add any GUI component if required. I’m adding a simple button to Call 91-800-001-0101 number
4 Modify res/values/strings.xml to define required constant values
5 Modify AndroidManifest.xml as shown below
6 Run the application to launch Android emulator and verify the result of the changes done in the aplication.

Following is the content of the modified main activity filesrc/com.example.phonecalldemo/MainActivity.java.

package com.example.phonecalldemo;

import android.net.Uri;
import android.os.Bundle;
import android.app.Activity;
import android.content.Intent;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

public class MainActivity extends Activity {

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

      Button startBtn = (Button) findViewById(R.id.makeCall);
      startBtn.setOnClickListener(new View.OnClickListener() {
         public void onClick(View view) {
         makeCall();
      }
   });

   }
   protected void makeCall() {
      Log.i("Make call", "");

      Intent phoneIntent = new Intent(Intent.ACTION_CALL);
      phoneIntent.setData(Uri.parse("tel:91-800-001-0101"));

      try {
         startActivity(phoneIntent);
         finish();
         Log.i("Finished making a call...", "");
      } catch (android.content.ActivityNotFoundException ex) {
         Toast.makeText(MainActivity.this, 
         "Call faild, please try again later.", Toast.LENGTH_SHORT).show();
      }
   }
   @Override
   public boolean onCreateOptionsMenu(Menu menu) {
      // Inflate the menu; this adds items to the action bar if it is present.
      getMenuInflater().inflate(R.menu.main, menu);
      return true;
   }
}

Following will be the content of res/layout/activity_main.xml file:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
   android:layout_width="fill_parent"
   android:layout_height="fill_parent"
   android:orientation="vertical" >

   <Button android:id="@+id/makeCall"
   android:layout_width="fill_parent"
   android:layout_height="wrap_content"
   android:text="@string/make_call"/>
    
</LinearLayout>

Following will be the content of res/values/strings.xml to define two new constants:

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <string name="app_name">PhoneCallDemo</string>
    <string name="hello_world">Hello world!</string>
    <string name="action_settings">Settings</string>
    <string name="make_call">Call 91-800-001-0101</string>

</resources>

Following is the default content of AndroidManifest.xml:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.phonecalldemo"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="17" />
   <uses-permission android:name="android.permission.CALL_PHONE" />
   <uses-permission android:name="android.permission.READ_PHONE_STATE" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.example.phonecalldemo.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

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

Let’s try to run your PhoneCallDemo application. I assume you have connected your actual Android Mobile device with your computer. To run the app from Eclipse, open one of your project’s activity files and click Run Eclipse Run Icon icon from the toolbar. Before starting your application, Eclipse will display following window to select an option where you want to run your Android application.

Android Mobile Device

Select your mobile device as an option and then check your mobile device which will display following screen:

Android Mobile Call Screen

Now use Call 91-800-001-0101 button to make phone call as shown below:

Android Mobile Call Progress

Publishing Android Application

Android application publishing is a process that makes your Android applications available to users. Infact, publishing is the last phase of the Android application development process.

Android Application Publish

Once you developed and fully tested your Android Application, you can start selling or distributing free using Google Play (A famous Android marketplace). You can also release your applications by sending them directly to users or by letting users download them from your own website.

You can check a detailed publishing process at Android official website, but this tutorial will take you through simple steps to launch your application on Google Play. Here is a simplified check list which will help you in launching your Android application:

Step Activity
1 Regression Testing Before you publish your application, you need to make sure that its meeting the basic quality expectations for all Android apps, on all of the devices that you are targeting. So perform all the required testing on different devices including phone and tablets.
2 Application Rating When you will publish your application at Google Play, you will have to specify a content rating for your app, which informs Google Play users of its maturity level. Currently available ratings are (a) Everyone (b) Low maturity (c) Medium maturity (d) High maturity.
3 Targeted Regions Google Play lets you control what countries and territories where your application will be sold. Accordingly you must take care of setting up time zone, localization or any other specific requirement as per the targeted region.
4 Application Size Currently, the maximum size for an APK published on Google Play is 50 MB. If your app exceeds that size, or if you want to offer a secondary download, you can use APK Expansion Files, which Google Play will host for free on its server infrastructure and automatically handle the download to devices.
5 SDK and Screen Compatibility It is important to make sure that your app is designed to run properly on the Android platform versions and device screen sizes that you want to target.
6 Application Pricing Deciding whether you app will be free or paid is important because, on Google Play, free apps must remain free. If you want to sell your application then you will have to specify its price in different currencies.
7 Promotional Content It is a good marketing practice to supply a variety of high-quality graphic assets to showcase your app or brand. After you publish, these appear on your product details page, in store listings and search results, and elsewhere.
8 Build and Upload release-ready APK The release-ready APK is what you you will upload to the Developer Console and distribute to users. You can check complete detail on how to create a release-ready version of your app: Preparing for Release.
9 Finalize Application Detail Google Play gives you a variety of ways to promote your app and engage with users on your product details page, from colorful graphics, screenshots, and videos to localized descriptions, release details, and links to your other apps. So you can decorate your application page and provide as much as clear crisp detail you can provide.

Export Android Application

You will need to export your application as an APK (Android Package) file before you upload it Google Play marketplace.

To export an application, just open that application project in Eclipse and select File->Export from your Eclipse and follow the simple steps to export your application:

Android Export Screen

Next select, Export Android Application option as shown in the above screen shot and then click Nextand again Next so that you get following screen where you will choose Create new keystore to store your application.

Android Key Store

Enter your password to protect your application and click on Next button once again. It will display following screen to let you create a key for your application:

Android Key Creation

Once you filled up all the information, click Next button and finally it will ask you a location where Application will be exported:

Android Export Location

Finally, you click on Finish button to generate your Android Application Package File which will be uploaded at Google Play marketplace.

Google Play Registration

The most important step is to register with Google Play using Google Play Marketplace. You can use your existing google ID if you have any otherwise you can create a new Google ID and then register with the marketplace. You will have following screen to accept terms and condition.

Android Market Place Terms and Conditions

You can use Continue to payment button to proceed to make a payment of $25 as a registration fee and finally to complete your account detail.

Once you are a registered user at Google Play, you can upload release-ready APK for your application and finally you will complete application detail using application detail page as mentioned in step 9 of the above mentioned checklist.

 

 

 

Rate: 0

Mobile Protocol Tutorial

Mobile Protocol Tutorial

General Description

The protocol is designed for access to a server API from applications running on mobile devices. It must be emphasized that a web browser is not such an application.

The protocol is subdivided into three virtually independent components:

  • High-level component (API query language): defines the method whereby API queries and responses are converted to binary messages.
  • Cryptographic (authorization) layer: defines the method by which messages are encrypted prior to being transmitted through the transport protocol.
  • Transport component: defines the method for the client and the server to transmit messages over some other existing network protocol (such as, http, https, tcp, udp).
MTProto encryption

 

Note 1: Each plaintext message to be encrypted in MTProto always contains the following data to be checked upon decryption in order to make the system robust against known problems with the components:

  • server salt (64-Bit)
  • session id
  • message sequence number
  • message length
  • time

Note 2: See additional comments on our use of IGE,SHA-1 and Modified encrypt and mac.

Brief Component Summary

High-Level Component (RPC Query Language/API)

From the standpoint of the high-level component, the client and the server exchange messages inside a session. The session is attached to the client device (the application, to be more exact) rather than a specific http/https/tcp connection. In addition, each session is attached to a user key ID by which authorization is actually accomplished.

Several connections to a server may be open; messages may be sent in either direction through any of the connections (a response to a query is not necessarily returned through the same connection that carried the original query, although most often, that is the case; however, in no case can a message be returned through a connection belonging to a different session). When the UDP protocol is used, a response might be returned by a different IP address than the one to which the query had been sent.

There are several types of messages:

  • RPC calls (client to server): calls to API methods
  • RPC responses (server to client): results of RPC calls
  • Message received acknowledgment (or rather, notification of status of a set of messages)
  • Message status query
  • Multipart message or container (a container that holds several messages; needed to send several RPC calls at once over an HTTP connection, for example; also, a container may support gzip).

From the standpoint of lower level protocols, a message is a binary data stream aligned along a 4 or 16-byte boundary. The first several fields in the message are fixed and are used by the cryptographic/authorization system.

Each message, either individual or inside a container, consists of a message identifier (64 bits, see below), a message sequence number within a session (32 bits), the length (of the message body in bytes; 32 bits), and a body (any size which is a multiple of 4 bytes). In addition, when a container or a single message is sent, an internal header is added at the top (see below), then the entire message is encrypted, and an external header is placed at the top of the message (a 64-bit key identifier and a 128-bit message key).

A message body normally consists of a 32-bit message type followed by type-dependent parameters. In particular, each RPC function has a corresponding message type. For more detail, see Binary data serialization,mobile procol:service messages.

All numbers are written as little endian. However, very large numbers (2048-bit) used in RSA and DH are written in the big endian format because that is what the OpenSSL library does.

Authorization and Encryption

Prior to a message (or a multipart message) being transmitted over a network using a transport protocol, it is encrypted in a certain way, and an external header is added at the top of the message which is: a 64-bit key identifier (that uniquely identifies an authorization key for the server as well as the user) and a 128-bit message key. A user key together with the message key defines an actual 256-bit key which is what encrypts the message using AES-256 encryption. Note that the initial part of the message to be encrypted contains variable data (session, message ID, sequence number, server salt) that obviously influences the message key (and thus the AES key and iv). The message key is defined as the 128 lower-order bits of the SHA1 of the message body (including session, message ID, etc.). Multipart messages are encrypted as a single message.

For a technical specification, see mobile protocol :mobile protocol :detailed descriptio.
The first thing a client application must do is create an authorization key  which is normally generated when it is first run and almost never changes.

The protocol’s principal drawback is that an intruder passively intercepting messages and then somehow appropriating the authorization key (for example, by stealing a device) will be able to decrypt all the intercepted messages post factum. This probably is not too much of a problem (by stealing a device, one could also gain access to all the information cached on the device without decrypting anything); however, the following steps could be taken to overcome this weakness:

  • Session keys generated using the Diffie-Hellman protocol and used in conjunction with the authorization and the message keys to select AES parameters. To create these, the first thing a client must do after creating a new session is send a special RPC query to the server (“generate session key”) to which the server will respond, whereupon all subsequent messages within the session are encrypted using the session key as well.
  • Protecting the key stored on the client device with a (text) password; this password is never stored in memory and is entered by a user when starting the application or more frequently (depending on application settings).
  • Data stored (cached) on the user device can also be protected by encryption using an authorization key which, in turn, is to be password-protected. Then, a password will be required to gain access even to those data.

Time Synchronization

If client time diverges widely from server time, a server may start ignoring client messages, or vice versa, because of an invalid message identifier (which is closely related to creation time). Under these circumstances, the server will send the client a special message containing the correct time and a certain 128-bit salt (either explicitly provided by the client in a special RPC synchronization request or equal to the key of the latest message received from the client during the current session). This message could be the first one in a container that includes other messages (if the time discrepancy is significant but does not as yet result in the client’s messages being ignored).

Having received such a message or a container holding it, the client first performs a time synchronization (in effect, simply storing the difference between the server’s time and its own to be able to compute the “correct” time in the future) and then verifies that the message identifiers for correctness.

Where a correction has been neglected, the client will have to generate a new session to assure the monotonicity of message identifiers.

Transport

Enables the delivery of encrypted containers together with the external header (hereinafter, Payload) from client to server and back. There are three types of transport:

  • HTTP
  • TCP
  • UDP

We shall examine the first two types.

HTTP Transport

Implemented over HTTP/1.1 (with keepalive) running over the traditional TCP Port 80. HTTPS is not used; the above encryption method is used instead.

An HTTP connection is attached to a session (or rather, to session + key identifier) specified in the most recent user query received; normally, the session is the same in all queries, but crafty HTTP proxies may corrupt that. A server may not return a message into an HTTP connection unless it belongs to the same session, and unless it is the server’s turn (an HTTP request had been received from the client to which a response has not been sent yet).

The overall arrangement is as follows. The client opens one or more keepalive HTTP connections to the server. If one or more messages need to be sent, they are made into a payload which is followed by a POST request to the URL/api to which the payload is transmitted as data. In addition, Content-Length, Keepalive, and Host are valid HTTP headers.

Having received the query, the server may either wait a little while (if the query requires a response following a short timeout) or immediately return a dummy response (only acknowledging the receipt of the container). In any case, the response may contain any number of messages. The server may at the same time send out any other messages it might be holding for the session.

In addition, there exists a special long poll RPC query (valid for HTTP connections only) which transmits maximum timeout T. If the server has messages for the session, they are returned immediately; otherwise, a wait state is entered until such time as the server has a message for the client or T seconds have elapsed. If no events occur in the span of T seconds, a dummy response is returned (special message).

If a server needs to send a message to a client, it checks for an HTTP connection that belongs to the required session and is in the “answering an HTTP request” state (including long poll) whereupon the message is added to the response container for the connection and sent to the user. In a typical case, there is some additional wait time (50 milliseconds) against the eventuality that the server will soon have more messages for the session.

If no suitable HTTP connection is available, the messages are placed in the current session’s send queue. However, they find their way there anyway until receipt is explicitly or indirectly confirmed by the client. For the HTTP protocol, sending the next query into the same HTTP connection is regarded as an implicit acknowledgment (not any more, the HTTP protocol also requires that explicit acknowledgments be sent); in other cases, the client must return an explicit acknowledgment within a reasonable time (it can be added to a container for the following request).

Important: if the acknowledgment fails to arrive on time, the message can be resent (possibly, in a different container). The parties must autonomously be ready for this and must store the identifiers of the most recent messages received (and ignore such duplicates rather than repeat actions). In order not to have the identifiers stored forever, there exist special garbage collection messages that take advantage of message identifier monotonicity.

If the send queue overflows or if messages stay in the queue for over 10 minutes, the server forgets them (or sends them to swap, no genius required). This may happen even faster, if the server is running out of buffer space (for example, because of serious network issues resulting in a large number of connections becoming severed).

TCP Transport

This is very similar to the HTTP transport. May also be implemented over Port 80 (to penetrate all firewalls) and even use the same server IP addresses. In this situation, the server understands whether HTTP or TCP protocol must be used for the connection, based on the first four incoming bytes (for HTTP, it is POST).

When a TCP connection is created, it is assigned to the session (and the authorization key) transmitted in the first user message, and subsequently used exclusively for this session (multiplexing arrangements are not allowed).

If a payload (packet) needs to be transmitted from server to client or from client to server, it is encapsulated as follows: 4 length bytes are added at the front (to include the length, the sequence number, and CRC32; always divisible by 4) and 4 bytes with the packet sequence number within this TCP connection (the first packet sent is numbered 0, the next one 1, etc.), and 4 CRC32 bytes at the end (length, sequence number, and payload together).

There is an abridged version of the same protocol: if the client sends 0xef as the first byte (**important:** only prior to the very first data packet), then packet length is encoded by a single byte (0x01..0x7e = data length divided by 4; or 0x7f followed by 3 length bytes (little endian) divided by 4) followed by the data themselves (sequence number and CRC32 not added). In this case, server responses look the same (the server does not send 0xefas the first byte).

In case 4-byte data alignment is needed, an intermediate version of the original protocol may be used: if the client sends 0xeeeeeeee as the first int (four bytes), then packet length is encoded always by four bytes as in the original version, but the sequence number and CRC32 are omitted, thus decreasing total packet size by 8 bytes.

The full, the intermediate and the abridged versions of the protocol have support for fast acknowledgment. In this case, the client sets the highest-order length bit in the query packet, and the server responds with a special 4 bytes as a separate packet. They are the 32 higher-order SHA1 bits of the encrypted portion of the packet with the most significant bit set to make clear that this is not the length of a regular server response packet; if the abridged version is used, bswap is applied to these four bytes.

There are no implicit acknowledgments for the TCP transport: all messages must be acknowledged explicitly. Most frequently, acknowledgments are placed in a container with the next query or response if it is transmitted in short order. For example, this is almost always the case for client messages containing RPC queries: the acknowledgment normally arrives with the RPC response.

In the event of an error, the server may send a packet whose payload consists of 4 bytes as the error code. For example, Error Code 403 corresponds to situations where the corresponding HTTP error would have been returned by the HTTP protocol.

 

Creating an Authorization Key

The query format is described using binary data serialization and the TL Language. All large numbers are transmitted as strings containing the required sequence of bytes in big endian order. Hash functions, such as SHA1, return strings (of 20 bytes) which can also be interpreted as big endian numbers. Small numbers (int, long, int128, int256) are normally little endian; however, if they are part of SHA1, the bytes are not rearranged. This way, if long x is the 64 lower-order bits of SHA1 of string s, then the final 8 bytes of 20-byte string SHA1(s) are taken and interpreted as a 64-bit integer.

Prior to sending off unencrypted messages (required in this instance to generate an authorization key), the client must undergo (p,q) authorization as follows:

1) Client sends query to server

req_pq#60469778 nonce:int128 = ResPQ

The value of nonce is selected randomly by the client (random number) and identifies the client within this communication. Following this step, it is known to all.

2) Server sends response of the form

resPQ#05162463 nonce:int128 server_nonce:int128 pq:string server_public_key_fingerprints:Vector long = ResPQ

Here, string pq is a representation of a natural number (in binary big endian format). This number is the product of two different odd prime numbers. Normally, pq is less than or equal to 2^63-1. The value of server_nonce is selected randomly by the server; following this step, it is known to all.

server_public_key_fingerprints is a list of public RSA key fingerprints (64 lower-order bits of SHA1 (server_public_key); the public key is represented as a bare type rsa_public_key n:string e:string = RSAPublicKey, where, as usual, n and е are numbers in big endian format serialized as strings of bytes, following which SHA1 is computed) received by the server.

Let us note that all subsequent messages contain the pair (nonce, server_nonce) both in the plain-text, and the encrypted portions which enables its use to identify a “temporary session” (one run of the key generation protocol under discussion). An intruder could not create a parallel session with the server with the same parameters and reuse parts of server- or client-encrypted messages for its own purposes in such a parallel session because a different server_nonce would be selected by the server for a new “temporary session”.

3) Client decomposes pq into prime factors such that p < q.

This starts a round of Diffie-Hellman key exchanges:

4) Client sends query to server

req_DH_params#d712e4be nonce:int128 server_nonce:int128 p:string q:string public_key_fingerprint:long encrypted_data:string = Server_DH_Params

Here, encrypted_data is obtained as follows:

  • new_nonce := another (good) random number generated by the client; after this query, it is known to both client and server;
  • data := a serialization of
    p_q_inner_data#83c95aec pq:string p:string q:string nonce:int128 server_nonce:int128 new_nonce:int256 = P_Q_inner_data

    or of

    p_q_inner_data_temp#3c6a84d4 pq:string p:string q:string nonce:int128 server_nonce:int128 new_nonce:int256 expires_in:int = P_Q_inner_data;
  • data_with_hash := SHA1(data) + data + (any random bytes); such that the length equal 255 bytes;
  • encrypted_data := RSA (data_with_hash, server_public_key); a 255-byte long number (big endian) is raised to the requisite power over the requisite modulus, and the result is stored as a 256-byte number.

Someone might intercept the query and replace it with their own, independently decomposing pq into factors instead of the client. The only field that it makes sense to modify is new_nonce which would be the one an intruder would have to re-generate (because an intruder cannot decrypt the encrypted data sent by the client). Since all subsequent messages are encrypted using new_nonce or contain new_nonce_hash, they will not be processed by the client (an intruder would not be able to make it look as though they had been generated by the server because they would not contain new_nonce). Therefore, this intercept will only result in the intruder’s completing the authorization key generation protocol in place of the client and creating a new key (that has nothing to do with the client); however, the same effect could be achieved simply by creating a new key in one’s own name.

An alternative form of inner data (p_q_inner_data_temp) is used to create temporary keys, that are only stored in the server RAM and are discarded after at most expires_in seconds. The server is free to discard its copy earlier. In all other respects the temporary key generation protocol is the same. After a temporary key is created, the client usually binds it to its principal authorisation key by means of the auth .bind tempauth key  method, and uses it for all client-server communication until it expires; then a new temporary key is generated. Thus Perfect Forward Secrecy (PFS) in client-server communication is achieved.

5) Server responds in one of two ways:

server_DH_params_fail#79cb045d nonce:int128 server_nonce:int128 new_nonce_hash:int128 = Server_DH_Params;
server_DH_params_ok#d0e8075c nonce:int128 server_nonce:int128 encrypted_answer:string = Server_DH_Params;

Here, encrypted_answer is obtained as follows:

  • new_nonce_hash := 128 lower-order bits of SHA1 (new_nonce);
  • answer := serialization
      server_DH_inner_data#b5890dba nonce:int128 server_nonce:int128 g:int dh_prime:string g_a:string server_time:int = Server_DH_inner_data;
  • answer_with_hash := SHA1(answer) + answer + (0-15 random bytes); such that the length be divisible by 16;
  • tmp_aes_key := SHA1(new_nonce + server_nonce) + substr (SHA1(server_nonce + new_nonce), 0, 12);
  • tmp_aes_iv := substr (SHA1(server_nonce + new_nonce), 12, 8) + SHA1(new_nonce + new_nonce) + substr (new_nonce, 0, 4);
  • encrypted_answer := AES256_ige_encrypt (answer_with_hash, tmp_aes_key, tmp_aes_iv); here, tmp_aes_key is a 256-bit key, and tmp_aes_iv is a 256-bit initialization vector. The same as in all the other instances that use AES encryption, the encrypted data is padded with random bytes to a length divisible by 16 immediately prior to encryption.

Following this step, new_nonce is still known to client and server only. The client is certain that it is the server that responded and that the response was generated specifically in response to client query req_DH_params, since the response data are encrypted using new_nonce.

Client is expected to check whether p = dh_prime is a safe 2048-bit prime (meaning that both p and (p-1)/2 are prime, and that 2^2047 < p < 2^2048), and that g generates a cyclic subgroup of prime order (p-1)/2, i.e. is a quadratic residue mod p. Since g is always equal to 2, 3, 4, 5, 6 or 7, this is easily done using quadratic reciprocity law, yielding a simple condition on p mod 4g — namely, p mod 8 = 7 for g = 2; p mod 3 = 2 for g = 3; no extra condition for g = 4; p mod 5 = 1 or 4 for g = 5; p mod 24 = 19 or 23 for g = 6; and p mod 7 = 3, 5 or 6 for g = 7. After g and p have been checked by the client, it makes sense to cache the result, so as not to repeat lengthy computations in future.

If the verification takes too long time (which is the case for older mobile devices), one might initially run only 15 Miller—Rabin iterations for verifying primeness of p and (p – 1)/2 with error probability not exceeding one billionth, and do more iterations later in the background.

Another optimization is to embed into the client application code a small table with some known “good” couples(g,p) (or just known safe primes p, since the condition on g is easily verified during execution), checked during code generation phase, so as to avoid doing such verification during runtime altogether. Server changes these values rarely, thus one usually has to put the current value of server’s dh_prime into such a table. For example, current value of dh_prime equals (in big-endian byte order)

C7 1C AE B9 C6 B1 C9 04 8E 6C 52 2F 70 F1 3F 73 98 0D 40 23 8E 3E 21 C1 49 34 D0 37 56 3D 93 0F 48 19 8A 0A A7 C1 40 58 22 94 93 D2 25 30 F4 DB FA 33 6F 6E 0A C9 25 13 95 43 AE D4 4C CE 7C 37 20 FD 51 F6 94 58 70 5A C6 8C D4 FE 6B 6B 13 AB DC 97 46 51 29 69 32 84 54 F1 8F AF 8C 59 5F 64 24 77 FE 96 BB 2A 94 1D 5B CD 1D 4A C8 CC 49 88 07 08 FA 9B 37 8E 3C 4F 3A 90 60 BE E6 7C F9 A4 A4 A6 95 81 10 51 90 7E 16 27 53 B5 6B 0F 6B 41 0D BA 74 D8 A8 4B 2A 14 B3 14 4E 0E F1 28 47 54 FD 17 ED 95 0D 59 65 B4 B9 DD 46 58 2D B1 17 8D 16 9C 6B C4 65 B0 D6 FF 9C A3 92 8F EF 5B 9A E4 E4 18 FC 15 E8 3E BE A0 F8 7F A9 FF 5E ED 70 05 0D ED 28 49 F4 7B F9 59 D9 56 85 0C E9 29 85 1F 0D 81 15 F6 35 B1 05 EE 2E 4E 15 D0 4B 24 54 BF 6F 4F AD F0 34 B1 04 03 11 9C D8 E3 B9 2F CC 5B

6) Client computes random 2048-bit number b (using a sufficient amount of entropy) and sends the server a message

set_client_DH_params#f5045f1f nonce:int128 server_nonce:int128 encrypted_data:string = Set_client_DH_params_answer;

Here, encrypted_data is obtained thus:

  • g_b := pow(g, b) mod dh_prime;
  • data := serialization
      client_DH_inner_data#6643b654 nonce:int128 server_nonce:int128 retry_id:long g_b:string = Client_DH_Inner_Data
  • data_with_hash := SHA1(data) + data + (0-15 random bytes); such that length be divisible by 16;
  • encrypted_data := AES256_ige_encrypt (data_with_hash, tmp_aes_key, tmp_aes_iv);

The retry_id field is equal to zero at the time of the first attempt; otherwise, it is equal to auth_key_aux_hash from the previous failed attempt (see Item 9).

7) Thereafter, auth_key equals pow(g, {ab}) mod dh_prime; on the server, it is computed as pow(g_b, a) mod dh_prime, and on the client as (g_a)^b mod dh_prime.

8) auth_key_hash is computed := 64 lower-order bits of SHA1 (auth_key). The server checks whether there already is another key with the same auth_key_hash and responds in one of the following ways:

9) Server responds in one of three ways:

dh_gen_ok#3bcbf734 nonce:int128 server_nonce:int128 new_nonce_hash1:int128 = Set_client_DH_params_answer;
dh_gen_retry#46dc1fb9 nonce:int128 server_nonce:int128 new_nonce_hash2:int128 = Set_client_DH_params_answer;
dh_gen_fail#a69dae02 nonce:int128 server_nonce:int128 new_nonce_hash3:int128 = Set_client_DH_params_answer;
  • new_nonce_hash1, new_nonce_hash2, and new_nonce_hash3 are obtained as the 128 lower-order bits of SHA1 of the byte string derived from the new_nonce string by adding a single byte with the value of 1, 2, or 3, and followed by another 8 bytes with auth_key_aux_hash. Different values are required to prevent an intruder from changing server response dh_gen_ok into dh_gen_retry.
  • auth_key_aux_hash is the 64 higher-order bits of SHA1(auth_key). It must not be confused with auth_key_hash.

In the other case, the client goes to Item 6) generating a new b.
In the first case, the client and the server have negotiated auth_key, following which they forget all other temporary data, and the client creates another encrypted session using auth_key. At the same time, server_salt is initially set tosubstr(new_nonce, 0, 8) XOR substr(server_nonce, 0, 8). If required, the client stores the difference between server_time received in 5) and its local time, to be able always to have a good approximation of server time which is required to generate correct message identifiers.

IMPORTANT: Apart from the conditions on the Diffie-Hellman prime dh_prime and generator g, both sides are to check that g, g_a and g_b are greater than 1 and less than dh_prime – 1. We recommend checking that g_a and g_bare between 2^{2048-64} and dh_prime – 2^{2048-64} as well.

Error Handling (Lost Queries and Responses)

If the client fails to receive any response to its query from the server within a certain time interval, it may simply re-send the query. If the server has already sent a response to this query (*exactly* the same request and not just similar: all the parameters during the repeat request must take on the same values) but it did not get to the client, the server will simply re-send the same response. The server remembers the response for up to 10 minutes after having received the query in 1). If the server has already forgotten the response or the requisite temporary data, the client will have to start from the beginning.

The server may consider that if the client has already sent in the next query using the data from the previous server response to the specific client, the response is known to have been received by the client and may be forgotten by the server.

Usage Example

An example of a complete list of queries required to generate an authorization key is shown on a separate page.

Creating an Authorization Key (Samples)

If a payload (packet) needs to be transmitted from server to client or from client to server, it is encapsulated as follows: 4 bytes are added at the front (to include the length, the sequence number, and CRC32; always divisible by 4) and 4 bytes with the packet sequence number for this TCP connection (the first packet sent is numbered 0, the next one 1, etc.), and 4 CRC32 bytes at the end (length, sequence number, and payload together).

There is an abridged version of the same protocol: if the client sends 0xef as the first byte (**important:** only prior to the very first data packet), then packet length is encoded by a single byte (0x01-0x7e = data length divided by 4; or 0x7f followed by 3 bytes (little endian) divided into 4) followed by the data themselves (sequence number and CRC32 not added). In this case, server responses have the same form (although the server does not send 0xefas the first byte).

Detailed documentation on creating authorization keys is available here.

1. Request for (p,q) Authorization

req_pq#60469778 nonce:int128 = ResPQ
Parameter Offset, Length in bytes Value Description
auth_key_id 0, 8 0 Since message is in plain text
message_id 8, 8 51e57ac42770964a Exact unixtime * 2^32
message_length 16, 4 20 Message body length
%(req_pq) 20, 4 60469778 req_pq constructor number from TL schema
nonce 24, 16 3E0549828CCA27E966B301A48FECE2FC Random number

The header is 20 bytes long, the message body is 20 bytes long, and the entire message is 40 bytes in length.

0000 | 00 00 00 00 00 00 00 00 4A 96 70 27 C4 7A E5 51
0010 | 14 00 00 00 78 97 46 60 3E 05 49 82 8C CA 27 E9
0020 | 66 B3 01 A4 8F EC E2 FC

2. A response from the server has been received with the following content:

0000 | 00 00 00 00 00 00 00 00 01 C8 83 1E C9 7A E5 51
0010 | 40 00 00 00 63 24 16 05 3E 05 49 82 8C CA 27 E9
0020 | 66 B3 01 A4 8F EC E2 FC A5 CF 4D 33 F4 A1 1E A8
0030 | 77 BA 4A A5 73 90 73 30 08 17 ED 48 94 1A 08 F9
0040 | 81 00 00 00 15 C4 B5 1C 01 00 00 00 21 6B E8 6C
0050 | 02 2B B4 C3
Response decomposition using the following formula:
resPQ#05162463 nonce:int128 server_nonce:int128 pq:string server_public_key_fingerprints:Vector long = ResPQ 
Parameter Offset, Length in bytes Value Description
auth_key_id 0, 8 0 Since message is in plain text
message_id 8, 8 51E57AC91E83C801 Server message ID
message_length 16, 4 64 Message body length
%(resPQ) 20, 4 05162463 resPQ constructor number from TL schema
nonce 24, 16 3E0549828CCA27E966B301A48FECE2FC Value generated by client in Step 1
server_nonce 40, 16 A5CF4D33F4A11EA877BA4AA573907330 Server-generated random number
pq 56, 12 17ED48941A08F981 Single-byte prefix denoting length, an 8-byte string, and three bytes of padding
%(Vector long) 68, 4 1cb5c415 Vector long constructor number from TL schema
count 72, 4 1 Number of elements in key fingerprint list
fingerprints[] 76, 8 c3b42b026ce86b21 64 lower-order bits of SHA1 (server_public_key)

The server_public_key public key has been selected whose fingerprint corresponds to the only one received from the server: c3b42b026ce86b21.

3. Pq = 17ED48941A08F981 decomposed into 2 prime cofactors:

p = 494C553B
q = 53911073

4. encrypted_data Generation

p_q_inner_data#83c95aec pq:string p:string q:string nonce:int128 server_nonce:int128 new_nonce:int256 = P_Q_inner_data
Parameter Offset, Length in bytes Value Description
%(p_q_inner_data) 0, 4 83c95aec p_q_inner_data constructor number from TL schema
pq 4, 12 17ED48941A08F981 Single-byte prefix denoting length, 8-byte string, and three bytes of padding
p 16, 8 494C553B First prime cofactor: single-byte prefix denoting length, 4-byte string, and three bytes of padding
q 24, 8 53911073 Second prime cofactor: single-byte prefix denoting length, 4-byte string, and three bytes of padding
nonce 32, 16 3E0549828CCA27E966B301A48FECE2FC Value generated by client in Step 1
server_nonce 48, 16 A5CF4D33F4A11EA877BA4AA573907330 Value received from server in Step 2
new_nonce 64, 32 311C85DB234AA2640AFC4A76A735CF5B1F0FD68BD17FA181E1229AD867CC024D Client-generated random number

The serialization of P_Q_inner_data produces some string data. This is followed by encrypted_data:

SHA1 (data) = DB761C27718A2305044F71F2AD951629D78B2449
RSA (data_with_hash, server_public_key) = 7BB0100A523161904D9C69FA04BC60DECFC5DD74B99995C768EB60D8716E2109BAF2D4601DAB6B09610DC11067BB89021E09471FCFA52DBD0F23204AD8CA8B012BF40A112F44695AB6C266955386114EF5211E6372227ADBD34995D3E0E5FF02EC63A43F9926878962F7C570E6A6E78BF8366AF917A5272675C46064BE62E3E202EFA8B1ADFB1C32A898C2987BE27B5F31D57C9BB963ABCB734B16F652CEDB4293CBB7C878A3A3FFAC9DBEA9DF7C67BC9E9508E111C78FC46E057F5C65ADE381D91FEE430A6B576A99BDF8551FDB1BE2B57069B1A45730618F27427E8A04720B4971EF4A9215983D68F2830C3EAA6E40385562F970D38A05C9F1246DC33438E6

The length of the final string was 256 bytes.

Request to Start Diffie-Hellman Key Exchange
req_DH_params#d712e4be nonce:int128 server_nonce:int128 p:string q:string public_key_fingerprint:long encrypted_data:string = Server_DH_Params
Parameter Offset, Length in bytes Value Description
auth_key_id 0, 8 0 Since message is in plain text
message_id 8, 8 51e57ac917717a27 Exact unixtime * 2^32
message_length 16, 4 320 Message body length
%(req_DH_params) 20, 4 d712e4be req_DH_params constructor number from TL schema
nonce 24, 16 3E0549828CCA27E966B301A48FECE2FC Value generated by client in Step 1
server_nonce 40, 16 A5CF4D33F4A11EA877BA4AA573907330 Value received from server in Step 2
p 56, 8 494C553B First prime cofactor: single-byte prefix denoting length, 4-byte string, and three bytes of padding
q 64, 8 53911073 Second prime cofactor: single-byte prefix denoting length, 4-byte string, and three bytes of padding
public_key_fingerprint 72, 8 c3b42b026ce86b21 Fingerprint of public key used
encrypted_data 80, 260 See above See “Generation of encrypted_data”
0000 | 00 00 00 00 00 00 00 00 27 7A 71 17 C9 7A E5 51
0010 | 40 01 00 00 BE E4 12 D7 3E 05 49 82 8C CA 27 E9
0020 | 66 B3 01 A4 8F EC E2 FC A5 CF 4D 33 F4 A1 1E A8
0030 | 77 BA 4A A5 73 90 73 30 04 49 4C 55 3B 00 00 00
0040 | 04 53 91 10 73 00 00 00 21 6B E8 6C 02 2B B4 C3
0050 | FE 00 01 00 7B B0 10 0A 52 31 61 90 4D 9C 69 FA
0060 | 04 BC 60 DE CF C5 DD 74 B9 99 95 C7 68 EB 60 D8
0070 | 71 6E 21 09 BA F2 D4 60 1D AB 6B 09 61 0D C1 10
0080 | 67 BB 89 02 1E 09 47 1F CF A5 2D BD 0F 23 20 4A
0090 | D8 CA 8B 01 2B F4 0A 11 2F 44 69 5A B6 C2 66 95
00A0 | 53 86 11 4E F5 21 1E 63 72 22 7A DB D3 49 95 D3
00B0 | E0 E5 FF 02 EC 63 A4 3F 99 26 87 89 62 F7 C5 70
00C0 | E6 A6 E7 8B F8 36 6A F9 17 A5 27 26 75 C4 60 64
00D0 | BE 62 E3 E2 02 EF A8 B1 AD FB 1C 32 A8 98 C2 98
00E0 | 7B E2 7B 5F 31 D5 7C 9B B9 63 AB CB 73 4B 16 F6
00F0 | 52 CE DB 42 93 CB B7 C8 78 A3 A3 FF AC 9D BE A9
0100 | DF 7C 67 BC 9E 95 08 E1 11 C7 8F C4 6E 05 7F 5C
0110 | 65 AD E3 81 D9 1F EE 43 0A 6B 57 6A 99 BD F8 55
0120 | 1F DB 1B E2 B5 70 69 B1 A4 57 30 61 8F 27 42 7E
0130 | 8A 04 72 0B 49 71 EF 4A 92 15 98 3D 68 F2 83 0C
0140 | 3E AA 6E 40 38 55 62 F9 70 D3 8A 05 C9 F1 24 6D
0150 | C3 34 38 E6

5. A response from the server has been received with the following content:

0000 | 00 00 00 00 00 00 00 00 01 54 43 36 CB 7A E5 51
0010 | 78 02 00 00 5C 07 E8 D0 3E 05 49 82 8C CA 27 E9
0020 | 66 B3 01 A4 8F EC E2 FC A5 CF 4D 33 F4 A1 1E A8
0030 | 77 BA 4A A5 73 90 73 30 FE 50 02 00 28 A9 2F E2
0040 | 01 73 B3 47 A8 BB 32 4B 5F AB 26 67 C9 A8 BB CE
0050 | 64 68 D5 B5 09 A4 CB DD C1 86 24 0A C9 12 CF 70
0060 | 06 AF 89 26 DE 60 6A 2E 74 C0 49 3C AA 57 74 1E
0070 | 6C 82 45 1F 54 D3 E0 68 F5 CC C4 9B 44 44 12 4B
0080 | 96 66 FF B4 05 AA B5 64 A3 D0 1E 67 F6 E9 12 86
0090 | 7C 8D 20 D9 88 27 07 DC 33 0B 17 B4 E0 DD 57 CB
00A0 | 53 BF AA FA 9E F5 BE 76 AE 6C 1B 9B 6C 51 E2 D6
00B0 | 50 2A 47 C8 83 09 5C 46 C8 1E 3B E2 5F 62 42 7B
00C0 | 58 54 88 BB 3B F2 39 21 3B F4 8E B8 FE 34 C9 A0
00D0 | 26 CC 84 13 93 40 43 97 4D B0 35 56 63 30 38 39
00E0 | 2C EC B5 1F 94 82 4E 14 0B 98 63 77 30 A4 BE 79
00F0 | A8 F9 DA FA 39 BA E8 1E 10 95 84 9E A4 C8 34 67
0100 | C9 2A 3A 17 D9 97 81 7C 8A 7A C6 1C 3F F4 14 DA
0110 | 37 B7 D6 6E 94 9C 0A EC 85 8F 04 82 24 21 0F CC
0120 | 61 F1 1C 3A 91 0B 43 1C CB D1 04 CC CC 8D C6 D2
0130 | 9D 4A 5D 13 3B E6 39 A4 C3 2B BF F1 53 E6 3A CA
0140 | 3A C5 2F 2E 47 09 B8 AE 01 84 4B 14 2C 1E E8 9D
0150 | 07 5D 64 F6 9A 39 9F EB 04 E6 56 FE 36 75 A6 F8
0160 | F4 12 07 8F 3D 0B 58 DA 15 31 1C 1A 9F 8E 53 B3
0170 | CD 6B B5 57 2C 29 49 04 B7 26 D0 BE 33 7E 2E 21
0180 | 97 7D A2 6D D6 E3 32 70 25 1C 2C A2 9D FC C7 02
0190 | 27 F0 75 5F 84 CF DA 9A C4 B8 DD 5F 84 F1 D1 EB
01A0 | 36 BA 45 CD DC 70 44 4D 8C 21 3E 4B D8 F6 3B 8A
01B0 | B9 5A 2D 0B 41 80 DC 91 28 3D C0 63 AC FB 92 D6
01C0 | A4 E4 07 CD E7 C8 C6 96 89 F7 7A 00 74 41 D4 A6
01D0 | A8 38 4B 66 65 02 D9 B7 7F C6 8B 5B 43 CC 60 7E
01E0 | 60 A1 46 22 3E 11 0F CB 43 BC 3C 94 2E F9 81 93
01F0 | 0C DC 4A 1D 31 0C 0B 64 D5 E5 5D 30 8D 86 32 51
0200 | AB 90 50 2C 3E 46 CC 59 9E 88 6A 92 7C DA 96 3B
0210 | 9E B1 6C E6 26 03 B6 85 29 EE 98 F9 F5 20 64 19
0220 | E0 3F B4 58 EC 4B D9 45 4A A8 F6 BA 77 75 73 CC
0230 | 54 B3 28 89 5B 1D F2 5E AD 9F B4 CD 51 98 EE 02
0240 | 2B 2B 81 F3 88 D2 81 D5 E5 BC 58 01 07 CA 01 A5
0250 | 06 65 C3 2B 55 27 15 F3 35 FD 76 26 4F AD 00 DD
0260 | D5 AE 45 B9 48 32 AC 79 CE 7C 51 1D 19 4B C4 2B
0270 | 70 EF A8 50 BB 15 C2 01 2C 52 15 CA BF E9 7C E6
0280 | 6B 8D 87 34 D0 EE 75 9A 63 8A F0 13
Response decomposition using the following formula:
server_DH_params_fail#79cb045d nonce:int128 server_nonce:int128 new_nonce_hash:int128 = Server_DH_Params;
server_DH_params_ok#d0e8075c nonce:int128 server_nonce:int128 encrypted_answer:string = Server_DH_Params;
Parameter Offset, Length in bytes Value Description
auth_key_id 0, 8 0 Since message is in plain text
message_id 8, 8 51E57ACB36435401 Exact unixtime * 2^32
message_length 16, 4 632 Message body length
%(server_DH_params_ok) 20, 4 d0e8075c server_DH_params_ok constructor number from TL schema
nonce 24, 16 3E0549828CCA27E966B301A48FECE2FC Value generated by client in Step 1
server_nonce 40, 16 A5CF4D33F4A11EA877BA4AA573907330 Value received from server in Step 2
encrypted_answer 56, 596 See below See “Decomposition of encrypted_answer”
Conversion of encrypted_answer into answer:
encrypted_answer = 28A92FE20173B347A8BB324B5FAB2667C9A8BBCE6468D5B509A4CBDDC186240AC912CF7006AF8926DE606A2E74C0493CAA57741E6C82451F54D3E068F5CCC49B4444124B9666FFB405AAB564A3D01E67F6E912867C8D20D9882707DC330B17B4E0DD57CB53BFAAFA9EF5BE76AE6C1B9B6C51E2D6502A47C883095C46C81E3BE25F62427B585488BB3BF239213BF48EB8FE34C9A026CC8413934043974DB03556633038392CECB51F94824E140B98637730A4BE79A8F9DAFA39BAE81E1095849EA4C83467C92A3A17D997817C8A7AC61C3FF414DA37B7D66E949C0AEC858F048224210FCC61F11C3A910B431CCBD104CCCC8DC6D29D4A5D133BE639A4C32BBFF153E63ACA3AC52F2E4709B8AE01844B142C1EE89D075D64F69A399FEB04E656FE3675A6F8F412078F3D0B58DA15311C1A9F8E53B3CD6BB5572C294904B726D0BE337E2E21977DA26DD6E33270251C2CA29DFCC70227F0755F84CFDA9AC4B8DD5F84F1D1EB36BA45CDDC70444D8C213E4BD8F63B8AB95A2D0B4180DC91283DC063ACFB92D6A4E407CDE7C8C69689F77A007441D4A6A8384B666502D9B77FC68B5B43CC607E60A146223E110FCB43BC3C942EF981930CDC4A1D310C0B64D5E55D308D863251AB90502C3E46CC599E886A927CDA963B9EB16CE62603B68529EE98F9F5206419E03FB458EC4BD9454AA8F6BA777573CC54B328895B1DF25EAD9FB4CD5198EE022B2B81F388D281D5E5BC580107CA01A50665C32B552715F335FD76264FAD00DDD5AE45B94832AC79CE7C511D194BC42B70EFA850BB15C2012C5215CABFE97CE66B8D8734D0EE759A638AF013
tmp_aes_key = F011280887C7BB01DF0FC4E17830E0B91FBB8BE4B2267CB985AE25F33B527253
tmp_aes_iv = 3212D579EE35452ED23E0D0C92841AA7D31B2E9BDEF2151E80D15860311C85DB
answer = BA0D89B53E0549828CCA27E966B301A48FECE2FCA5CF4D33F4A11EA877BA4AA57390733002000000FE000100C71CAEB9C6B1C9048E6C522F70F13F73980D40238E3E21C14934D037563D930F48198A0AA7C14058229493D22530F4DBFA336F6E0AC925139543AED44CCE7C3720FD51F69458705AC68CD4FE6B6B13ABDC9746512969328454F18FAF8C595F642477FE96BB2A941D5BCD1D4AC8CC49880708FA9B378E3C4F3A9060BEE67CF9A4A4A695811051907E162753B56B0F6B410DBA74D8A84B2A14B3144E0EF1284754FD17ED950D5965B4B9DD46582DB1178D169C6BC465B0D6FF9CA3928FEF5B9AE4E418FC15E83EBEA0F87FA9FF5EED70050DED2849F47BF959D956850CE929851F0D8115F635B105EE2E4E15D04B2454BF6F4FADF034B10403119CD8E3B92FCC5BFE000100262AABA621CC4DF587DC94CF8252258C0B9337DFB47545A49CDD5C9B8EAE7236C6CADC40B24E88590F1CC2CC762EBF1CF11DCC0B393CAAD6CEE4EE5848001C73ACBB1D127E4CB93072AA3D1C8151B6FB6AA6124B7CD782EAF981BDCFCE9D7A00E423BD9D194E8AF78EF6501F415522E44522281C79D906DDB79C72E9C63D83FB2A940FF779DFB5F2FD786FB4AD71C9F08CF48758E534E9815F634F1E3A80A5E1C2AF210C5AB762755AD4B2126DFA61A77FA9DA967D65DFD0AFB5CDF26C4D4E1A88B180F4E0D0B45BA1484F95CB2712B50BF3F5968D9D55C99C0FB9FB67BFF56D7D4481B634514FBA3488C4CDA2FC0659990E8E868B28632875A9AA703BCDCE8FCB7AE551
Server_DH_inner_data decomposition using the following formula:
server_DH_inner_data#b5890dba nonce:int128 server_nonce:int128 g:int dh_prime:string g_a:string server_time:int = Server_DH_inner_data;
Parameter Offset, Length in bytes Value Description
%(server_DH_inner_data) 0, 4 b5890dba server_DH_inner_data constructor number from TL schema
nonce 4, 16 3E0549828CCA27E966B301A48FECE2FC Value generated by client in Step 1
server_nonce 20, 16 A5CF4D33F4A11EA877BA4AA573907330 Value received from server in Step 2
g 36, 4 2 Value received from server in Step 2
dh_prime 40, 260 C71CAEB9C6B1C9048E6C522F70F13F73980D40238E3E21C14934D037563D930F48198A0AA7C14058229493D22530F4DBFA336F6E0AC925139543AED44CCE7C3720FD51F69458705AC68CD4FE6B6B13ABDC9746512969328454F18FAF8C595F642477FE96BB2A941D5BCD1D4AC8CC49880708FA9B378E3C4F3A9060BEE67CF9A4A4A695811051907E162753B56B0F6B410DBA74D8A84B2A14B3144E0EF1284754FD17ED950D5965B4B9DD46582DB1178D169C6BC465B0D6FF9CA3928FEF5B9AE4E418FC15E83EBEA0F87FA9FF5EED70050DED2849F47BF959D956850CE929851F0D8115F635B105EE2E4E15D04B2454BF6F4FADF034B10403119CD8E3B92FCC5B
g_a 300, 260 262AABA621CC4DF587DC94CF8252258C0B9337DFB47545A49CDD5C9B8EAE7236C6CADC40B24E88590F1CC2CC762EBF1CF11DCC0B393CAAD6CEE4EE5848001C73ACBB1D127E4CB93072AA3D1C8151B6FB6AA6124B7CD782EAF981BDCFCE9D7A00E423BD9D194E8AF78EF6501F415522E44522281C79D906DDB79C72E9C63D83FB2A940FF779DFB5F2FD786FB4AD71C9F08CF48758E534E9815F634F1E3A80A5E1C2AF210C5AB762755AD4B2126DFA61A77FA9DA967D65DFD0AFB5CDF26C4D4E1A88B180F4E0D0B45BA1484F95CB2712B50BF3F5968D9D55C99C0FB9FB67BFF56D7D4481B634514FBA3488C4CDA2FC0659990E8E868B28632875A9AA703BCDCE8F
server_time 560, 4 1373993675 Server time

6. Random number b is computed:

b = 6F620AFA575C9233EB4C014110A7BCAF49464F798A18A0981FEA1E05E8DA67D9681E0FD6DF0EDF0272AE3492451A84502F2EFC0DA18741A5FB80BD82296919A70FAA6D07CBBBCA2037EA7D3E327B61D585ED3373EE0553A91CBD29B01FA9A89D479CA53D57BDE3A76FBD922A923A0A38B922C1D0701F53FF52D7EA9217080163A64901E766EB6A0F20BC391B64B9D1DD2CD13A7D0C946A3A7DF8CEC9E2236446F646C42CFE2B60A2A8D776E56C8D7519B08B88ED0970E10D12A8C9E355D765F2B7BBB7B4CA9360083435523CB0D57D2B106FD14F94B4EEE79D8AC131CA56AD389C84FE279716F8124A543337FB9EA3D988EC5FA63D90A4BA3970E7A39E5C0DE5
Generation of encrypted_data
client_DH_inner_data#6643b654 nonce:int128 server_nonce:int128 retry_id:long g_b:string = Client_DH_Inner_Data
Parameter Offset, Length in bytes Value Description
%(client_DH_inner_data) 0, 4 6643b654 client_DH_inner_data constructor number from TL schema
nonce 4, 16 3E0549828CCA27E966B301A48FECE2FC Value generated by client in Step 1
server_nonce 20, 16 A5CF4D33F4A11EA877BA4AA573907330 Value received from server in Step 2
retry_id 36, 8 0 First attempt
g_b 44, 260 73700E7BFC7AEEC828EB8E0DCC04D09A0DD56A1B4B35F72F0B55FCE7DB7EBB72D7C33C5D4AA59E1C74D09B01AE536B318CFED436AFDB15FE9EB4C70D7F0CB14E46DBBDE9053A64304361EB358A9BB32E9D5C2843FE87248B89C3F066A7D5876D61657ACC52B0D81CD683B2A0FA93E8ADAB20377877F3BC3369BBF57B10F5B589E65A9C27490F30A0C70FFCFD3453F5B379C1B9727A573CFFDCA8D23C721B135B92E529B1CDD2F7ABD4F34DAC4BE1EEAF60993DDE8ED45890E4F47C26F2C0B2E037BB502739C8824F2A99E2B1E7E416583417CC79A8807A4BDAC6A5E9805D4F6186C37D66F6988C9F9C752896F3D34D25529263FAF2670A09B2A59CE35264511F g^b mod dh_prime

The serialization of Client_DH_Inner_Data produces some string data. This is followed by encrypted_data:

data_with_hash := SHA1(data) + data + (0-15 random bytes); such that the length be divisible by 16;
AES256_ige_encrypt (data_with_hash, tmp_aes_key, tmp_aes_iv) = 928A4957D0463B525C1CC48AABAA030A256BE5C746792C84CA4C5A0DF60AC799048D98A38A8480EDCF082214DFC79DCB9EE34E206513E2B3BC1504CFE6C9ADA46BF9A03CA74F192EAF8C278454ADABC795A566615462D31817382984039505F71CB33A41E2527A4B1AC05107872FED8E3ABCEE1518AE965B0ED3AED7F67479155BDA8E4C286B64CDF123EC748CF289B1DB02D1907B562DF462D8582BA6F0A3022DC2D3504D69D1BA48B677E3A830BFAFD67584C8AA24E1344A8904E305F9587C92EF964F0083F50F61EAB4A393EAA33C9270294AEDC7732891D4EA1599F52311D74469D2112F4EDF3F342E93C8E87E812DC3989BAECFE6740A46077524C75093F5A5405736DE8937BB6E42C9A0DCF22CA53227D462BCCC2CFE94B6FE86AB7FBFA395021F66661AF7C0024CA2986CA03F3476905407D1EA9C010B763258DB1AA2CC7826D91334EFC1FDC665B67FE45ED0

The length of the final string was 336 bytes.

Request
set_client_DH_params#f5045f1f nonce:int128 server_nonce:int128 encrypted_data:string = Set_client_DH_params_answer;
Parameter Offset, Length in bytes Value Description
auth_key_id 0, 8 0 Since message is in plain text
message_id 8, 8 51e57acd2aa32c6d Exact unixtime * 2^32
message_length 16, 4 20 Message body length
%(set_client_DH_params) 20, 4 f5045f1f set_client_DH_params constructor number from TL schema
nonce 24, 16 3E0549828CCA27E966B301A48FECE2FC Value generated by client in Step 1
server_nonce 40, 16 A5CF4D33F4A11EA877BA4AA573907330 Value received from server in Step 2
encrypted_data 56, 340 See above See “Generation of encrypted_data”
0000 | 00 00 00 00 00 00 00 00 6D 2C A3 2A CD 7A E5 51
0010 | 78 01 00 00 1F 5F 04 F5 3E 05 49 82 8C CA 27 E9
0020 | 66 B3 01 A4 8F EC E2 FC A5 CF 4D 33 F4 A1 1E A8
0030 | 77 BA 4A A5 73 90 73 30 FE 50 01 00 92 8A 49 57
0040 | D0 46 3B 52 5C 1C C4 8A AB AA 03 0A 25 6B E5 C7
0050 | 46 79 2C 84 CA 4C 5A 0D F6 0A C7 99 04 8D 98 A3
0060 | 8A 84 80 ED CF 08 22 14 DF C7 9D CB 9E E3 4E 20
0070 | 65 13 E2 B3 BC 15 04 CF E6 C9 AD A4 6B F9 A0 3C
0080 | A7 4F 19 2E AF 8C 27 84 54 AD AB C7 95 A5 66 61
0090 | 54 62 D3 18 17 38 29 84 03 95 05 F7 1C B3 3A 41
00A0 | E2 52 7A 4B 1A C0 51 07 87 2F ED 8E 3A BC EE 15
00B0 | 18 AE 96 5B 0E D3 AE D7 F6 74 79 15 5B DA 8E 4C
00C0 | 28 6B 64 CD F1 23 EC 74 8C F2 89 B1 DB 02 D1 90
00D0 | 7B 56 2D F4 62 D8 58 2B A6 F0 A3 02 2D C2 D3 50
00E0 | 4D 69 D1 BA 48 B6 77 E3 A8 30 BF AF D6 75 84 C8
00F0 | AA 24 E1 34 4A 89 04 E3 05 F9 58 7C 92 EF 96 4F
0100 | 00 83 F5 0F 61 EA B4 A3 93 EA A3 3C 92 70 29 4A
0110 | ED C7 73 28 91 D4 EA 15 99 F5 23 11 D7 44 69 D2
0120 | 11 2F 4E DF 3F 34 2E 93 C8 E8 7E 81 2D C3 98 9B
0130 | AE CF E6 74 0A 46 07 75 24 C7 50 93 F5 A5 40 57
0140 | 36 DE 89 37 BB 6E 42 C9 A0 DC F2 2C A5 32 27 D4
0150 | 62 BC CC 2C FE 94 B6 FE 86 AB 7F BF A3 95 02 1F
0160 | 66 66 1A F7 C0 02 4C A2 98 6C A0 3F 34 76 90 54
0170 | 07 D1 EA 9C 01 0B 76 32 58 DB 1A A2 CC 78 26 D9
0180 | 13 34 EF C1 FD C6 65 B6 7F E4 5E D0

7. Computing auth_key using formula g^{ab} mod dh_prime:

auth_key = AB96E207C631300986F30EF97DF55E179E63C112675F0CE502EE76D74BBEE6CBD1E95772818881E9F2FF54BD52C258787474F6A7BEA61EABE49D1D01D55F64FC07BC31685716EC8FB46FEACF9502E42CFD6B9F45A08E90AA5C2B5933AC767CBE1CD50D8E64F89727CA4A1A5D32C0DB80A9FCDBDDD4F8D5A1E774198F1A4299F927C484FEEC395F29647E43C3243986F93609E23538C21871DF50E00070B3B6A8FA9BC15628E8B43FF977409A61CEEC5A21CF7DFB5A4CC28F5257BC30CD8F2FB92FBF21E28924065F50E0BBD5E11A420300E2C136B80E9826C6C5609B5371B7850AA628323B6422F3A94F6DFDE4C3DC1EA60F7E11EE63122B3F39CBD1A8430157

8. The server verifies that auth_key_hash is unique.

The key is unique.

9. A response from the server has been received with the following content:

0000 | 00 00 00 00 00 00 00 00 01 30 AA C5 CE 7A E5 51
0010 | 34 00 00 00 34 F7 CB 3B 3E 05 49 82 8C CA 27 E9
0020 | 66 B3 01 A4 8F EC E2 FC A5 CF 4D 33 F4 A1 1E A8
0030 | 77 BA 4A A5 73 90 73 30 CC EB C0 21 72 66 E1 ED
0040 | EC 7F B0 A0 EE D6 C2 20

Set_client_DH_params_answer decomposition using the following formula:

dh_gen_ok#3bcbf734 nonce:int128 server_nonce:int128 new_nonce_hash1:int128 = Set_client_DH_params_answer;
dh_gen_retry#46dc1fb9 nonce:int128 server_nonce:int128 new_nonce_hash2:int128 = Set_client_DH_params_answer;
dh_gen_fail#a69dae02 nonce:int128 server_nonce:int128 new_nonce_hash3:int128 = Set_client_DH_params_answer;
Parameter Offset, Length in bytes Value Description
%(dh_gen_ok) 0, 4 3bcbf734 dh_gen_ok constructor number from TL schema
nonce 4, 16 3E0549828CCA27E966B301A48FECE2FC Value generated by client in Step 1
server_nonce 20, 16 A5CF4D33F4A11EA877BA4AA573907330 Value received from server in Step 2
new_nonce_hash1 36, 4 CCEBC0217266E1EDEC7FB0A0EED6C220
Rate: 0

Telegram Messenger Beta tutorial

Telegram Messenger Beta

If you have any problems with the registration process or logging in to your account, please contact us at sms@telegram.org

Telegram is a messaging app with a focus on speed and security. It’s super-fast, simple, secure and free.
Telegram seamlessly syncs across all of your devices and can be used on desktops, tablets and phones alike. You can send an unlimited amount of messages, photos, videos and files of any type (.doc, .zip, .pdf, etc.). Telegram groups have up to 200 people and you can send broadcasts to up to 100 contacts at a time. Be sure to check our website for a list of Telegram apps for all platforms.
We built Telegram to make messaging speedy and safe again, without the usual caveats.
New in version 1.1.3.51
- telegram.me/username links open a chat with the user in Telegram
- Integration with phone Contacts
- Improved support for chat background
- Fix self-destruct timer
- Fix emoji keyboard on Full HD screens
- Other improvements and fixes
Rate: 0

GPRS Tutorial

General Packet Radio System is also known as GPRS is a third-generation step toward internet access. GPRS is also known as GSM-IP that is a Global-System Mobile Communications Internet Protocol as it keeps the users of this system online, allows to make voice calls, and access internet on-the-go. Even Time-Division Multiple Access (TDMA) users benefit from this system as it provides packet radio access.

GPRS also permits the network operators to execute an Internet Protocol (IP) based core architecture for integrated voice and data applications that will continue to be used and expanded for 3G services.

GPRS supersedes the wired connections, as this system has simplified access to the packet data networks like the internet. The packet radio principle is employed by GPRS to transport user data packets in a structure way between GSM mobile stations and external packet data networks. These packets can be directly routed to the packet switched networks from the GPRS mobile stations.

In the current versions of GPRS, networks based on the Internet Protocol (IP) like the global internet or private/corporate intranets and X.25 networks are supported.

Who owns GPRS ?

The GPRS specifications are written by the European Telecommunications Standard Institute (ETSI), the European counterpart of the American National Standard Institute (ANSI).

Key Features

Following three key features describe wireless packet data:

  • The always online feature - Removes the dial-up process, making applications only one click away.
  • An upgrade to existing systems - Operators do not have to replace their equipment; rather, GPRS is added on top of the existing infrastructure.
  • An integral part of future 3G systems - GPRS is the packet data core network for 3G systems EDGE and WCDMA.

Goals of GPRS

GPRS is the first step toward an end-to-end wireless infrastructure and has the following goals:

  • Open architecture
  • Consistent IP services
  • Same infrastructure for different air interfaces
  • Integrated telephony and Internet infrastructure
  • Leverage industry investment in IP
  • Service innovation independent of infrastructure

Benefits of GPRS

Higher Data Rate

GPRS benefits the users in many ways, one of which is higher data rates in turn of shorter access times. In the typical GSM mobile, setup alone is a lengthy process and equally, rates for data permission are restrained to 9.6 kbit/s. The session establishment time offered while GPRS is in practice is lower than one second and ISDN-line data rates are up to many 10 kbit/s.

Easy Billing

GPRS packet transmission offers a more user-friendly billing than that offered by circuit switched services. In circuit switched services, billing is based on the duration of the connection. This is unsuitable for applications with bursty traffic. The user must pay for the entire airtime, even for idle periods when no packets are sent (e.g., when the user reads a Web page).

In contrast to this, with packet switched services, billing can be based on the amount of transmitted data. The advantage for the user is that he or she can be “online” over a long period of time but will be billed based on the transmitted data volume.

GPRS has opened a wide range of unique services to the mobile wireless subscriber. Some of the characteristics that have opened a market full of enhanced value services to the users. Below are some of the characteristics:

  • Mobility - The ability to maintain constant voice and data communications while on the move.
  • Immediacy - Allows subscribers to obtain connectivity when needed, regardless of location and without a lengthy login session.
  • Localization - Allows subscribers to obtain information relevant to their current location.

Using the above three characteristics varied possible applications are being developed to offer to the mobile subscribers. These applications, in general, can be divided into two high-level categories:

  • Corporation
  • Consumer

These two levels further include:

  • Communications - E-mail, fax, unified messaging and intranet/internet access, etc.
  • Value-added services - Information services and games, etc.
  • E-commerce - Retail, ticket purchasing, banking and financial trading, etc.
  • Location-based applications - Navigation, traffic conditions, airline/rail schedules and location finder, etc.
  • Vertical applications - Freight delivery, fleet management and sales-force automation.
  • Advertising - Advertising may be location sensitive. For example, a user entering a mall can receive advertisements specific to the stores in that mall.

Along with the above applications, non-voice services like SMS, MMS and voice calls are also possible with GPRS. Closed User Group (CUG) is a common term used after GPRS is in the market, in addition, it is planned to implement supplementary services, such as Call Forwarding Unconditional (CFU), and Call Forwarding on Mobile subscriber Not Reachable (CFNRc), and closed user group (CUG).

GPRS architecture works on the same procedure like GSM network, but, has additional entities that allow packet data transmission. This data network overlaps a second-generation GSM network providing packet data transport at the rates from 9.6 to 171 kbps. Along with the packet data transport the GSM network accommodates multiple users to share the same air interface resources concurrently.

Following is the GPRS Architecture diagram:

GPRS Architecture

GPRS attempts to reuse the existing GSM network elements as much as possible, but to effectively build a packet-based mobile cellular network, some new network elements, interfaces, and protocols for handling packet traffic are required.

Therefore, GPRS requires modifications to numerous GSM network elements as summarized below:

GSM Network Element Modification or Upgrade Required for GPRS.
Mobile Station (MS) New Mobile Station is required to access GPRS services. These new terminals will be backward compatible with GSM for voice calls.
BTS A software upgrade is required in the existing Base Transceiver Station(BTS).
BSC The Base Station Controller (BSC) requires a software upgrade and the installation of new hardware called the packet control unit (PCU). The PCU directs the data traffic to the GPRS network and can be a separate hardware element associated with the BSC.
GPRS Support Nodes (GSNs) The deployment of GPRS requires the installation of new core network elements called the serving GPRS support node (SGSN) and gateway GPRS support node (GGSN).
Databases (HLR, VLR, etc.) All the databases involved in the network will require software upgrades to handle the new call models and functions introduced by GPRS.

GPRS Mobile Stations

New Mobile Stations (MS) are required to use GPRS services because existing GSM phones do not handle the enhanced air interface or packet data. A variety of MS can exist, including a high-speed version of current phones to support high-speed data access, a new PDA device with an embedded GSM phone, and PC cards for laptop computers. These mobile stations are backward compatible for making voice calls using GSM.

GPRS Base Station Subsystem

Each BSC requires the installation of one or more Packet Control Units (PCUs) and a software upgrade. The PCU provides a physical and logical data interface to the Base Station Subsystem (BSS) for packet data traffic. The BTS can also require a software upgrade but typically does not require hardware enhancements.

When either voice or data traffic is originated at the subscriber mobile, it is transported over the air interface to the BTS, and from the BTS to the BSC in the same way as a standard GSM call. However, at the output of the BSC, the traffic is separated; voice is sent to the Mobile Switching Center (MSC) per standard GSM, and data is sent to a new device called the SGSN via the PCU over a Frame Relay interface.

GPRS Support Nodes

Following two new components, called Gateway GPRS Support Nodes (GSNs) and, Serving GPRS Support Node (SGSN) are added:

Gateway GPRS Support Node (GGSN)

The Gateway GPRS Support Node acts as an interface and a router to external networks. It contains routing information for GPRS mobiles, which is used to tunnel packets through the IP based internal backbone to the correct Serving GPRS Support Node. The GGSN also collects charging information connected to the use of the external data networks and can act as a packet filter for incoming traffic.

Serving GPRS Support Node (SGSN)

The Serving GPRS Support Node is responsible for authentication of GPRS mobiles, registration of mobiles in the network, mobility management, and collecting information on charging for the use of the air interface.

Internal Backbone

The internal backbone is an IP based network used to carry packets between different GSNs. Tunnelling is used between SGSNs and GGSNs, so the internal backbone does not need any information about domains outside the GPRS network. Signalling from a GSN to a MSC, HLR or EIR is done using SS7.

Routing Area

GPRS introduces the concept of a Routing Area. This concept is similar to Location Area in GSM, except that it generally contains fewer cells. Because routing areas are smaller than location areas, less radio resources are used While broadcasting a page message.

The flow of GPRS protocol stack and end-to-end message from MS to the GGSN is displayed in the below diagram. GTP is the protocol used between the SGSN and GGSN using the Gn interface. This is a Layer 3 tunneling protocol.

GPRS Protocol Stack

The process that takes place in the application looks like a normal IP sub-network for the users both inside and outside the network. The vital thing that needs attention is, the application communicates via standard IP, that is carried through the GPRS network and out through the gateway GPRS. The packets that are mobile between the GGSN and the SGSN use the GPRS tunneling protocol, this way the IP addresses located on the external side of the GPRS network do not have deal with the internal backbone. UDP and IP are run by GTP.

SubNetwork Dependent Convergence Protocol (SNDCP) and Logical Link Control (LLC) combination used in between the SGSN and the MS. The SNDCP flattens data to reduce the load on the radio channel. A safe logical link by encrypting packets is provided by LLC and the same LLC link is used as long as a mobile is under a single SGSN.

In case, the mobile moves to a new routing area that lies under a different SGSN; then, the old LLC link is removed and a new link is established with the new Serving GSN X.25. Services are provided by running X.25 on top of TCP/IP in the internal backbone.

Quality of Service (QoS) requirements of conventional mobile packet data applications are in assorted forms. The QoS is a vital feature of GPRS services as there are different QoS support requirements for assorted GPRS applications like realtime multimedia, web browsing, and e-mail transfer.

GPRS allows defining QoS profiles using the following parameters :

  • Service Precedence
  • Reliability
  • Delay and
  • Throughput

These parameters are described below:

Service Precedence

The preference given to a service when compared to another service is known as Service Precedence.This level of priority is classified into three levels called:

  • high
  • normal
  • low

When there is network congestion, the packets of low priority are discarded as compared to high or normal priority packets.

Reliability

This parameter signifies the transmission characteristics required by an application.The reliability classes are defined which guarantee certain maximum values for the probability of loss, duplication, mis-sequencing, and corruption of packets.

Delay

The delay is defined as the end-to-end transfer time between two communicating mobile stations or between a mobile station and the GI interface to an external packet data network.

This includes all delays within the GPRS network, e.g., the delay for request and assignment of radio resources and the transit delay in the GPRS backbone network. Transfer delays outside the GPRS network, e.g., in external transit networks, are not taken into account.

Throughput

The throughput specifies the maximum/peak bit rate and the mean bit rate.

Using these QoS classes, QoS profiles can be negotiated between the mobile user and the network for each session, depending on the QoS demand and the available resources.

The billing of the service is then based on the transmitted data volume, the type of service, and the chosen QoS profile.

Mobile Station Classes talk about the globally-known equipment handset which is also known as Mobile Station (MS) and its three different classes. This equipment, more popular as handset, is used to make phone calls and access data services. The MS comprises of Terminal Equipment (TE) and Mobile Terminal (MT).

TE is the equipment that accommodates the applications and the user interaction, while the MT is the part that connects to the network.

In the following example, Palm Pilot is TE and Mobile phone is MT.

GPRS MS Classes

In order to take advantage of the new GPRS services, we need new GPRS enabled handsets. There are three different classes of GPRS terminal equipments:

Class A

Class A terminals can manage both packet data and voice simultaneously. Which means, one needs two transceivers, as the handset has to send or receive data and voice at the same time.This is the main reason why class A terminals are high-priced to manufacture than class B and C terminals.

Class B

Class B terminals do not play the same role like Class A. These terminals can manage either packet data or voice at a time. One can use a single transceiver for both, resulting in the low cost of terminals.

For example, If a user is using the GPRS session (like WAP browsing, file transfer, etc.) then this session is halted if he or she receives a call. This terminal does not allow both the sessions active in one go. This backlog needs rectification thereby giving the user a facility of both receiving a call and maintaining the data session.

Class C

Class C terminals can manage either only packet data or only voice. Examples of class C terminals are GPRS PCM/CIA cards, embedded modules in vending machines, and so on.

Due to the high cost of class A handsets, most handset manufacturers have announced that their first handsets will be class B. Currently, work is going on in 3GPP to standardize a lightweight class A in order to make handsets with simultaneous voice and data available at a reasonable cost.

PDP stands for Packet Data Protocol. The PDP addresses are network layer addresses (Open Standards Interconnect [OSI] model Layer 3). GPRS systems support both X.25 and IP network layer protocols. Therefore, PDP addresses can be X.25, IP, or both.

Each PDP address is anchored at a Gateway GPRS Support Node (GGSN), as shown in figure below. All packet data traffic sent from the public packet data network for the PDP address goes through the gateway (GGSN).

GPRS PDP Context

The public packet data network is only concerned that the address belongs to a specific GGSN. The GGSN hides the mobility of the station from the rest of the packet data network and from computers connected to the public packet data network.

Statically assigned PDP addresses are usually anchored at a GGSN in the subscriber’s home network. Conversely, dynamically assigned PDP addresses can be anchored either in the subscriber’s home network or the network that the user is visiting.

When a MS is already attached to a SGSN and it is about to transfer data, it must activate a PDP address. Activating a PDP address establishes an association between the current SGSN of mobile device and the GGSN that anchors the PDP address.

The record kept by the SGSN and the GGSN regarding this association is called the PDP context.

It is important to understand the difference between a MS attaching to a SGSN and a MS activating a PDP address. A single MS attaches to only one SGSN, however, it may have multiple PDP addresses that are all active at the same time.

Each of the addresses may be anchored to a different GGSN. If packets arrive from the public packet data network at a GGSN for a specific PDP address and the GGSN does not have an active PDP context corresponding to that address, it may simply discard the packets. Conversely, the GGSN may attempt to activate a PDP context with a MS if the address is statically assigned to a particular mobile device.

Data routing or routing of data packets to and fro from a mobile user, is one of the pivot requisites in the GPRS network. The requirement can be divided into two areas:

  • Data packet routing
  • Mobility management.

Data Packet Routing

The important roles of GGSN involve synergy with the external data network. The GGSN updates the location directory using routing information supplied by the SGSNs about the location of an MS. It routes the external data network protocol packet encapsulated over the GPRS backbone to the SGSN currently serving the MS. It also decapsulates and forwards external data network packets to the appropriate data network and collects charging data that is forwarded to a charging gateway (CG).

There are three important routing schemes:

  • Mobile-originated message - This path begins at the GPRS mobile device and ends at the host.
  • Network-initiated message when the MS is in its home network - This path begins at the host and ends at the GPRS mobile device.
  • Network-initiated message when the MS roams to another GPRS network -This path begins at the host of visited network and ends at the GPRS mobile device.

The GPRS network encapsulates all data network protocols into its own encapsulation protocol called the GPRS tunnelling protocol (GTP). The GTP ensures security in the backbone network and simplifies the routing mechanism and the delivery of data over the GPRS network.

Mobility Management

The operation of the GPRS is partly independent of the GSM network. However, some procedures share the network elements with current GSM functions to increase efficiency and to make optimum use of free GSM resources (such as unallocated time slots).

An MS can be in any of the following three states in the GPRS system. The three-state model is unique to packet radio. GSM uses a two-state model either idle or active.

Active State

Data is transmitted between an MS and the GPRS network only when the MS is in the active state. In the active state, the SGSN knows the cell location of the MS.

Packet transmission to an active MS is initiated by packet paging to notify the MS of an incoming data packet. The data transmission proceeds immediately after packet paging through the channel indicated by the paging message. The purpose of the paging message is to simplify the process of receiving packets. The MS listens to only the paging messages instead of to all the data packets in the downlink channels. This reduces battery usage significantly.

When an MS has a packet to transmit, it must access the uplink channel (i.e., the channel to the packet data network where services reside). The uplink channel is shared by a number of MSs, and its use is allocated by a BSS. The MS requests use of the channel in a random access message. The BSS allocates an unused channel to the MS and sends an access grant message in reply to the random access message.

Standby State

In the standby state, only the routing area of the MS is known. (The routing area can consist of one or more cells within a GSM location area).

When the SGSN sends a packet to an MS that is in the standby state, the MS must be paged. Because the SGSN knows the routing area of the MS, a packet paging message is sent to the routing area. On receiving the packet paging message, the MS relays its cell location to the SGSN to establish the active state.

Idle State

In the idle state, the MS does not have a logical GPRS context activated or any Packet-Switched Public Data Network (PSPDN) addresses allocated. In this state, the MS can receive only those multicast messages that can be received by any GPRS MS. Because the GPRS network infrastructure does not know the location of the MS, it is not possible to send messages to the MS from external data networks.

Routing Updates

When an MS that is in an active or a standby state moves from one routing area to another within the service area of one SGSN, it must perform a routing update. The routing area information in the SGSN is updated, and the success of the procedure is indicated in the response message.

A cell-based routing update procedure is invoked when an active MS enters a new cell. The MS sends a short message containing the identity of the MS and its new location through GPRS channels to its current SGSN. This procedure is used only when the MS is in the active state.

The inter-SGSN routing update is the most complicated routing update. The MS changes from one SGSN area to another, and it must establish a new connection to a new SGSN. This means creating a new logical link context between the MS and the new SGSN and informing the GGSN about the new location of the MS.

The GPRS access modes specify whether or not the GGSN requests user authentication at the access point to a Public Data Network (PDN). The available options are:

  • Transparent - No security authorization/authentication is requested by the GGSN.
  • Non-transparent - In this case, GGSN acts as a proxy for authenticating.

The GPRS transparent and non-transparent modes relate only to PDP type IPv4.

Transpatent Mode

Transparent access pertains to a GPRS PLMN that is not involved in subscriber access authorization and authentication. Access to PDN-related security procedures are transparent to GSNs.

In transparent access mode, the MS is given an address belonging to the operator or any other addressing space of domain. The address is given either at subscription as a static address or at PDP context activation, as a dynamic address. The dynamic address is allocated from a Dynamic Host Configuration Protocol (DHCP) server in the GPRS network. Any user authentication is done within the GPRS network. No RADIUS authentication is performed; only IMSI-based authentication (from the subscriber identity module in the handset) is done.

Non Transpatent Mode

Non-transparent access to an intranet/ISP means that the PLMN plays a role in the intranet/ISP authentication of the MS. Non-transparent access uses the Password Authentication Protocol (PAP) or Challenge Handshake Authentication Protocol (CHAP) message issued by the mobile terminal and piggybacked in the GTP PDP context activation message. This message is used to build a RADIUS request toward the RADIUS server associated with the access point name (APN).

GPRS Access Point Name

The GPRS standards define a network identity called an Access Point Name (APN). An APN identifies a PDN that is accessible from a GGSN node in a GPRS network. In GPRS, only the APN is used to select the target network. To configure an APN, the operator configures three elements on the GSN node:

  • Access point - Defines an APN and its associated access characteristics, including security (RADIUS), dynamic address allocation (DHCP), and DNS services.
  • Access point list - Defines a logical interface that is associated with the virtual template.
  • Access group - Defines whether access is permitted between the PDN and the MS.

 

This chapter gives a brief description of the basic processes used in GPRS networks:

  • Attach process - Process by which the MS attaches (i.e., connects) to the SGSN in a GPRS network.
  • Authentication process - Process by which the SGSN authenticates the mobile subscriber.
  • PDP activation process - Process by which a user session is established between the MS and the destination network.
  • Detach process - Process by which the MS detaches (i.e., disconnects) from the SGSN in the GPRS network.
  • Network-initiated PDP request for static IP address - Process by which a call from the packet data network reaches the MS using a static IP address.
  • Network-initiated PDP request for dynamic IP address - Process by which a call from the packet data network reaches the MS using a dynamic IP address.
  • As packet data is introduced into mobile systems, the question of how to bill for the services arises. Always online and paying by the minute does not sound all that appealing. Here, we describe the possibilities but it totally depends on different service providers, how they want to charge their customers.

    The SGSN and GGSN register all possible aspects of a GPRS user’s behavior and generate billing information accordingly. This information is gathered in so-called Charging Data Records (CDR) and is delivered to a billing gateway.

    The GPRS service charging can be based on the following parameters:

    • Volume - The amount of bytes transferred, i.e., downloaded and uploaded.
    • Duration - The duration of a PDP context session.
    • Time - Date, time of day, and day of the week (enabling lower tariffs at offpeak hours).
    • Final destination - A subscriber could be charged for access to the specific network, such as through a proxy server.
    • Location - The current location of the subscriber.
    • Quality of Service - Pay more for higher network priority.
    • SMS - The SGSN will produce specific CDRs for SMS.
    • Served IMSI/subscriber - Different subscriber classes (different tariffs for frequent users, businesses, or private users).
    • Reverse charging - The receiving subscriber is not charged for the received data; instead, the sending party is charged.
    • Free of charge - Specified data to be free of charge.
    • Flat rate - A fixed monthly fee.
    • Bearer service - Charging based on different bearer services (for an operator who has several networks, such as GSM900 and GSM1800, and who wants to promote usage of one of the networks). Or, perhaps the bearer service would be good for areas where it would be cheaper for the operator to offer services from a wireless LAN rather than from the GSM network.
    • GPRS has almost become a default or a mandatory feature of the latest GSM phones. In case you have plans to buy a GPRS enabled mobile phone, then; GSM mobile phone should be opted than going for CDMA technology.

      GSMArena.com is a website that has become a one-stop shop for all the latest GSM Mobile Phones. The page below displays a list of latest GSM mobile phones subscribers is a courtesy of GSM Arena. As a staunch follower of this site, I suggest you to go through all the reviews posted on the site, and pick the best suitable mobile phone.

      At present, numerous noted mobile device manufacturers provide state–of-the-art mobile handsets:

      Alcatel Amoi
      Apple Asus
      Benefon BenQ
      BenQ-Siemens Bird
      BlackBerry Bosch
      Chea Ericsson
      Eten Fujitsu Siemens
      Gigabyte Haier
      HP HTC
      i-mate Innostream
      Kyocera LG
      Maxon Mitac
      Mitsubishi Motorola
      NEC Neonode
      Nokia O2
      Palm Panasonic
      Pantech Philips
      Qtek Sagem
      Samsung Sendo
      Sewon Sharp
      Siemens Sony
      Sony Ericsson Tel.Me.
      Telit Thuraya
      Toshiba Vertu
      VK Mobile WND
      XCute

       

 

Rate: 0

HOW TO CREATE FIRST ANDROID MOBILE APP TUTORIAL

HOW TO CREATE FIRST ANDROID MOBILE APP TUTORIAL

1. What do you need:

  • Basic XML knowledge
  • Basic Java knowledge
  • Basic Eclipse knowledge
  • 2h of your time

2. Prerequisites:

  • Before you can start you need the Android SDK and a IDE. Android offers a special bundle for that:Android SDK Bundle
  • Download the bundle, unzip and run the “SDK Manager.exe”.
  • start Eclipse

3. Create a Android virtual machine (dalvik):

To run, test and debug your Application you can create and run a virtual android machine on your computer. Later you can deploy your Application to this virtual machine.

  • Click on “Windows” at the navigation toolbar
  • Open “Android Virtual Device manager

 

virtualdevicemanager

 

Create a “New” Virtual Device:

CreatenewVD

Be sure that “Use Host GPU” is enabled. This allows the AVD to use the Host GPU and this helps to render the AVD much faster.

After that you can start the AVD:

AVD

 

4. Create a new Project:

  • Open “File
  • New
  • Android Application Project

 

Choose a new for your Project:

projectname

 

Configure Project:

configureproject

 

Configure Launcher Icon:

Here you can choose a Launcher Icon that will be displayed on your mobile phone.

launchericon

 

Create a new Activity:

createActivity

 

Configure your Activity:

ConfigureActivity

 

After finishing Eclipse looks similar to that:

firstStart
Hello World Application

 

5. Implement the Look & Feel:

  • Navigate in the package explorer to “/res/layout/” and open “activity_main.xml
  • Right-click on “Hello World” and delete

5.1 Create static Attributes:

  • Select “/res/values/strings.xml

stringsXML

  • Add” a new entry
  • Select the Color entry – press OK and set the following attributes:

myColorAttributes

 

Add a few more String(!) Attributes:

  • Name/value: “miles” / “to Miles
  • Name/value: “kmh” / “to km/h
  • Name/value: “calc” / “Calculate

Switch from “Resources” to “strings.xml” and make sure that your code look similar to that snippet:

view plaincopy to clipboardprint?

  1. <resources>
  2. <string name=“app_name”>TutorialApplication</string>
  3. <string name=“action_settings”>Settings</string>
  4. <string name=“hello_world”>Hello world!</string>
  5. <color name=“myColor”>#eeeeee</color>
  6. <string name=“miles”>to Miles</string>
  7. <string name=“kmh”>to km/h</string>
  8. <string name=“calc”>Calculate</string>
  9. </resources>

 

5.2 Add Views

  • Select “/res/layout/activity_main.xml
  • Open Android editor via double-click

You have two possibilities. You can create new Views via drag and drop or you can edit the XML source code. In this tutorial we add the Views via drag and drop :)

So let’s start building our App. At first we have to add a “Text Field” for the input.

textfield

 

Drag this Text Field to your Application.

Afterwards select the “Form Widget” section and drag a RadioGroupto your App and make sure that the RadioGroup has twoRadioButtons. Finally you can add a normal Button.

appafterdrag

 

Switch from “Graphical Layout” to “activity_main.xml” and make sure that your code looks similar to that:

 

view plaincopy to clipboardprint?
  1. <RelativeLayout xmlns:android=“http://schemas.android.com/apk/res/android”
  2. xmlns:tools=“http://schemas.android.com/tools”
  3. android:layout_width=“match_parent”
  4. android:layout_height=“match_parent”
  5. android:paddingBottom=“@dimen/activity_vertical_margin”
  6. android:paddingLeft=“@dimen/activity_horizontal_margin”
  7. android:paddingRight=“@dimen/activity_horizontal_margin”
  8. android:paddingTop=“@dimen/activity_vertical_margin”
  9. tools:context=“.MainActivity” >
  10. <EditText
  11. android:id=“@+id/editText1″
  12. android:layout_width=“wrap_content”
  13. android:layout_height=“wrap_content”
  14. android:layout_alignParentLeft=“true”
  15. android:layout_alignParentTop=“true”
  16. android:layout_marginLeft=“24dp”
  17. android:layout_marginTop=“31dp”
  18. android:ems=“10”
  19. android:inputType=“numberDecimal|numberSigned” >
  20. <requestFocus />
  21. </EditText>
  22. <RadioGroup
  23. android:id=“@+id/radioGroup1″
  24. android:layout_width=“wrap_content”
  25. android:layout_height=“wrap_content”
  26. android:layout_alignLeft=“@+id/editText1″
  27. android:layout_below=“@+id/editText1″
  28. android:layout_marginTop=“28dp” >
  29. <RadioButton
  30. android:id=“@+id/radio0″
  31. android:layout_width=“wrap_content”
  32. android:layout_height=“wrap_content”
  33. android:checked=“true”
  34. android:text=“RadioButton” />
  35. <RadioButton
  36. android:id=“@+id/radio1″
  37. android:layout_width=“wrap_content”
  38. android:layout_height=“wrap_content”
  39. android:text=“RadioButton” />
  40. </RadioGroup>
  41. <Button
  42. android:id=“@+id/button1″
  43. android:layout_width=“wrap_content”
  44. android:layout_height=“wrap_content”
  45. android:layout_alignLeft=“@+id/radioGroup1″
  46. android:layout_centerVertical=“true”
  47. android:text=“Button” />
  48. </RelativeLayout>

 

5.3. Edit view properties

You can edit properties of Views via right-click on the view or via XML.

  • Navigate to “res/layout/” and open the Graphical Layout of your “activity_main.xml
  • right-click on the first Radio Button and open “Edit Text”

propertykmh

 

  • Assign the miles property to the second Radio Button
  • Set the “Checked” property for the first Radio Button (Other Properties -> inherited from compoundbutton -> checked -> true)
  • Set the “Input type” property for the Text Field to “numberSigned” and “numberDecimal
  • Assign “calc” to the Button and set “calculate” for the “onClick” property (Other Properties -> inherited from view -> onClick)
  • Set Background-Color (Right-click on an empty space on your Application -> Edit Background)

editbackground

 

After that change the Background should be #eeeeee! I think it can be difficult to see the difference.

 

6. Implement the Logic

After we implemented the Frontend-View we have to implement the logical part with Java!

  • Switch to “src/com.example.tutorialapplication/” and open “MainActivity.java

 

  view plaincopy to clipboardprint?
  1. package com.example.tutorialapplication;
  2. import android.os.Bundle;
  3. import android.app.Activity;
  4. import android.view.Menu;
  5. import android.view.View;
  6. import android.widget.EditText;
  7. import android.widget.RadioButton;
  8. import android.widget.Toast;
  9. public class MainActivity extends Activity {
  10.     // public var
  11.     private EditText text;
  12.     // default func
  13.     @Override
  14.     protected void onCreate(Bundle savedInstanceState) {
  15.         super.onCreate(savedInstanceState);
  16.         setContentView(R.layout.activity_main);
  17.         // findViewById = Finds a view that was identified by the id attribute
  18.         // from the XML that was processed in onCreate(Bundle).
  19.         // (EditText) = typecast
  20.         text = (EditText) findViewById(R.id.editText1);
  21.     }
  22.     // default func
  23.     @Override
  24.     public boolean onCreateOptionsMenu(Menu menu) {
  25.         // Inflate the menu; this adds items to the action bar if it is present.
  26.         getMenuInflater().inflate(R.menu.main, menu);
  27.         return true;
  28.     }
  29.     /*
  30.      * Will be executed by clicking on the calculate button because we assigned
  31.      * “calculate” to the “onClick” Property!
  32.      */
  33.     public void calculate(View view) {
  34.         RadioButton mileButton = (RadioButton) findViewById(R.id.radio0);
  35.         RadioButton kmhButton = (RadioButton) findViewById(R.id.radio1);
  36.         // if the text field is empty show the message “enter a valid number”
  37.         if (text.getText().length() == 0) {
  38.             // Toast = focused floating view that will be shown over the main
  39.             // application
  40.             Toast.makeText(this“enter a valid number”, Toast.LENGTH_LONG)
  41.                     .show();
  42.         } else {
  43.             //parse input Value from Text Field
  44.             double inputValue = Double.parseDouble(text.getText().toString());
  45.             // convert to…
  46.             if (mileButton.isChecked()) {
  47.                 text.setText(String.valueOf(convertToMiles(inputValue)));
  48.                 // uncheck “to miles” Button
  49.                 mileButton.setChecked(false);
  50.                 // check “to km/h” Button
  51.                 kmhButton.setChecked(true);
  52.             } else { /* if kmhButton isChecked() */
  53.                 text.setText(String.valueOf(convertToKmh(inputValue)));
  54.                 // uncheck “to km/h” Button
  55.                 kmhButton.setChecked(false);
  56.                 // check “to miles” Button
  57.                 mileButton.setChecked(true);
  58.             }
  59.         }
  60.     }
  61.     private double convertToMiles(double inputValue) {
  62.         // convert km/h to miles
  63.         return (inputValue * 1.609344);
  64.     }
  65.     private double convertToKmh(double inputValue) {
  66.         // convert miles to km/h
  67.         return (inputValue * 0.621372);
  68.     }
  69. }

 

Rate: 0

Web Design with Magento Toturial

What is responsive web design with Magento?

Response is a natural behavior of humans and animals. Without it, people can’t communicate with others and express themselves. It’s a primitive human need and it has been present since birth, and this need never regresses. In the world of today, people need it more than ever. That is the reason why there are so many high-speed technologies being developed today. People need immediate responses. People need everything else to adapt to them.

Recommended reading: Multipurpose magento resposive thems 

Magento, as a developer of applications, has created different themes that people can customize to support their online stores, but aside from these creations, Magento has come up with a way to deliver responsive mobile and web applications to you, the user. Magento Resposive Themes promise to make life easier and sweeter.

How do Magento Responsive themes work? Because of the advent of handheld devices like smartphones and tablets, not to mention desktop computers and laptops, you can now view websites in different ways, but the problem with this is that the layouts of your online store can get rearranged and possibly disorganized when viewed using a particular gadget. If you have customized, let’s say for example, your logo on the right side of your store using your computer, you might be surprised that it is nowhere to be seen when you view it on your smartphone. As a response, you would surely fix it again on your phone, but that is not the only gadget that you have. You still have a tablet and a laptop. This definitely takes up too much of your time and effort. So, Magento Responsive is here to allow you to do it in just one device and it will do the rest.

A responsive design of a website means that the design responds or adapts to its environment in terms of orientation and size, to the platform of the device, and to the behavior of the user. This works with the use of flexible layouts and images to be able to respond to the differences in environment. Device resolutions, operating systems, and platforms come into play in this aspect and so Magento Responsive has definitely mastered the art of interacting with these factors.

Top 5 affordable magento hosting for new business

Having a responsive website has a lot of advantages. The first one has already been mentioned – you get to save time and effort trying to make your site viewable across different devices. You can opt to hire developers to make them for you, but the problem here is you’ll have to shell out more money. As a business owner, this is the last thing you’d want to do. This can save you time and effort, but this won’t save you the costs of maintaining multiple websites. Losing time and money is not wise. This then leads to the second advantage – you get to save more money. The third advantage is that you get to control your website in one device. Store management would be centralized, thus giving you access on all your sites at once.

Through Magento Responsive themes, you can give your customers a fun shopping experience. They get to see the pictures and videos of your products with the right resolution and size. They can easily surf through your website from their phones and computers. Surely, mobile phones have been dominating the internet industry for the past few years and they will continue to do so in the next few years. Having a responsive website helps you reach out to your market instantly. With a lot of internet-ready gadgets with different platforms coming out in the market today, you are sure that no matter what people use, they’ll get to see the best that your store has to offer.

Rate: 0

Android Live Wallpaper Tutorial

How To Create Android Live Wallpaper

Introduction

Starting with Android 2.1. (API Level 7), developers can create live wallpapers – richer, animated, interactive backgrounds – on their home screens. A live wallpaper is very similar to a normal Android application: you can create menu with settings, use SGL and OpenGL for drawing, accelerometer, etc.

In this article, I want to demonstrate how to create live wallpaper from scratch. Step-by-step, we will create live wallpaper that would output TV test pattern on out home screen. Just like on real TV during night hours!

This article will highlight the following aspects of Live Wallpaper development:

  1. Drawing on graphic primitives (circles, rectangles) using android.graphics.Canvas class
  2. Developing of applications for screens with different resolution and orientation
  3. Creation of settings dialog for live wallpaper
  4. Reading of variables values for resource XML file
  5. Actual creation of live wallpaper for Android

Background

In this article, I show how to create a very simple live wallpaper.

On the internet, you can find much more profound and cooler apps, but I want you to check the following examples:

  •  CubeLive Wallpaper- Android SDK sample
  •  Mario Live Wallpaper- Awesome!!!
  •  AndEngie Live Wallpaper- Creating live wallpapers using AndEngie.

Using the Code

1. Making Android Virtual Device

As I mentioned earlier, we have to create an appropriate Android Virtual Device (AVD) to run our application.

Open Android SDK and AVD manager.

And create AVD with the following capabilities:

  1. Target platform Android 2.1 or higher
  2. With accelerometer support (we will add support for screen rotation detection)
  3. Touch-screen support

Resolution might be any. Our application will detect screen resolution and rescale graphic elements if necessary.

2. Creating Project Files

I named the app as LiveWallpaper.

When creating Android project, set Build Target as Android 2.1.

By default, project will be created with the following files:

We have to change them slightly and add new files that would contain values for application’s variables.

First, delete layout folder and main.xml file in res directory. This file is used for creating layout for application controls which we won’t use in our project.

Instead of this, create folder xml where we will create two files livewallpaper.xml and livewallpaper_settings.xmlthat will contain values for live wallpaper service and settings dialog.

Livewallpaper.xml contains the following data:

<?xml version="1.0" encoding="utf-8"?>
<wallpaper xmlns:android="http://schemas.android.com/apk/res/android"
    android:settingsActivity="ca.jvsh.livewallpaper.LiveWallpaperSettings"
    android:thumbnail="@drawable/icon"/>

Where wallpaper tag says that we are creating live wallpaper service. This file will be processed during apk filecreation.

Livewallpaper_settings.xml contains description of available settings for our live wallpaper:

<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
    android:title="@string/livewallpaper_settings"
    android:key="livewallpaper_settings">

    <ListPreference
        android:key="livewallpaper_testpattern"
        android:title="@string/livewallpaper_settings_title"
        android:summary="@string/livewallpaper_settings_summary"
        android:entries="@array/livewallpaper_testpattern_names"
        android:entryValues="@array/livewallpaper_testpattern_prefix"/>
    <CheckBoxPreference android:key="livewallpaper_movement"
        android:summary="@string/livewallpaper_movement_summary"
        android:title="@string/livewallpaper_movement_title"
        android:summaryOn="Moving test pattern"
        android:summaryOff="Still test pattern"/>
</PreferenceScreen>

Where tag ListPreference shows that we provide user option to choose between several items and the tagCheckBoxPreference shows that we have check box (Yes/No) option.

File strings.xml in values folder contains all strings values that we are using in our project.

<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
    <!-- General -->
    <skip />
    <!-- Application name -->
    <string name="app_name">Live Wallpaper</string>

    <string name="livewallpaper_settings">Settings</string>
    <string name="livewallpaper_settings_title">Select test pattern</string>
    <string name="livewallpaper_settings_summary">
		Choose which test pattern to display</string>
    <string name="livewallpaper_movement_title">Motion</string>
    <string name="livewallpaper_movement_summary">
		Apply movement to test pattern</string>
</resources>

You can modify this file during localization of your software.

Also in project, you will find testpattern.xml file. This file contains TV test patterns names and colors that they are using (TV test patterns mostly consist of rectangles).

3. Let’s Explore the Code!

You can check the code in the project file I’ve provided. I will just show the important points.

How to detect screen size and orientation?

You have to use DisplayMetrics class!

DisplayMetrics metrics = new DisplayMetrics();
Display display = ((WindowManager) getSystemService(WINDOW_SERVICE)).getDefaultDisplay();
display.getMetrics(metrics);

mRectFrame = new Rect(0, 0, metrics.widthPixels, metrics.heightPixels);


int rotation = display.getOrientation();
if(rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180)
    mHorizontal = false;
else
    mHorizontal = true;

How to draw a gradient?

You should use GradientDrawable class!

private Rect                mGradientRect;
GradientDrawable            mGradient;

mGradientRect = new Rect(10,10, 40, 40);
mGradient = new GradientDrawable(Orientation.LEFT_RIGHT, new int[] 
		{ 0xff050505, 0xfffdfdfd });
mGradient.setBounds(mGradientRect);
mGradient.draw(c);

Check out this code:

public void onSharedPreferenceChanged(SharedPreferences prefs,
        String key)
{
    mShape = prefs.getString("livewallpaper_testpattern", "smpte");
    mMotion = prefs.getBoolean("livewallpaper_movement", true);
    readColors();
}

private void readColors()
{
    int pid = getResources().getIdentifier(mShape + "colors", "array", getPackageName());

    rectColor = getResources().getIntArray(pid);
    mRectCount = rectColor.length;
    mColorRectangles = new Rect[mRectCount];

    System.out.println("mRectCount "+mRectCount);
    initFrameParams();
}

Those functions are called when we change our settings.

In readColors() function, we are reading color values from resources (testpatterns.xml file).

4. Editing AndroidManifest.xml

Proving a proper AndroidManifest.xml file is a crucial point if you want your app to be accepted at Android Market.

In our project, Android Manifest looks as follows:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="ca.jvsh.livewallpaper"
    android:versionName="1.0.20100908.1"
    android:versionCode="1">

    <uses-sdk android:minSdkVersion="7" />
    <uses-feature android:name="android.software.live_wallpaper" />

    <application android:icon="@drawable/icon"
        android:label="@string/app_name"
        android:permission="android.permission.BIND_WALLPAPER">

        <service android:name=".LiveWallpaper"
            android:label="@string/app_name"
            android:icon="@drawable/icon">

            <intent-filter>
                <action android:name="android.service.wallpaper.WallpaperService" />
            </intent-filter>
            <meta-data android:name="android.service.wallpaper"
                android:resource="@xml/livewallpaper" />

        </service>

        <activity android:label="@string/livewallpaper_settings"
            android:name=".LiveWallpaperSettings"
            android:theme="@android:style/Theme.Light.WallpaperSettings"
            android:exported="true"
            android:icon="@drawable/icon">
        </activity>

    </application>
</manifest>

It is very important to set up android:permission="android.permission.BIND_WALLPAPER" because this will allow the wallpaper to stay on your home screen.

5. Result

Points of Interest

Android live wallpapers are supported only on Android 2.1. (API level 7) and higher versions of the platform. To ensure that your application can only be installed on devices that support live wallpapers, remember to add to the applications’s manifest before publishing to Android Market which indicates to Android Market and the platform that your app requires Android 2.1 or higher.

<uses-feature android:name="android.software.live_wallpaper" />

which tells Android Market that your application includes a live wallpaper

Rate: 0

AngularJS Tutorial

AngularJS Introduction


Angular
AngularJS extends HTML with new attributesAngularJS is perfect for SPAs (Single Page Applications)AngularJS is easy to learn

AngularJS Introduction

AngularJS is a JavaScript framework. It can be added to an HTML page with a <script> tag.

AngularJS extends HTML attributes with Directives, and binds data to HTML with Expressions.

AngularJS is a JavaScript Framework

AngularJS is a JavaScript framework. It is a library written in JavaScript.

AngularJS is distributed as a JavaScript file, and can be added to a web page with a script tag:

<script src=“http://ajax.googleapis.com/ajax/libs/angularjs/1.2.26/angular.min.js”></script>

AngularJS Extends HTML

AngularJS extends HTML with ng-directives.

The ng-app directive defines an AngularJS application.

The ng-model directive binds the value of HTML controls (input, select, textarea) to application data.

The ng-bind directive binds application data to the HTML view.

AngularJS Example

<!DOCTYPE html>
<html><head>
<script src=“http://ajax.googleapis.com/ajax/libs/angularjs/1.2.26/angular.min.js”></script>
</head><body><div ng-app=“”>
<p>Name: <input type=“text” ng-model=“name”></p>
<p ng-bind=“name”></p>
</div></body>
</html>

Example explained:

AngularJS starts automatically when the web page has loaded.

The ng-app directive tells AngularJS that the <div> element is the “owner” of an AngularJS application.

The ng-model directive binds the value of the input field to the application variable name.

The ng-bind directive binds the innerHTML of the <p> element to the application variable name.

AngularJS Directives

As you have already seen, AngularJS directives are HTML attributes with an ng prefix.

The ng-init directive initialize AngularJS application variables.

AngularJS Example

<div ng-app=“” ng-init=“firstName=’John'”><p>The name is <span ng-bind=“firstName”></span></p></div>
You can use data-ng-, instead of ng-, if you want to make your page HTML5 valid.

Alternatively with valid HTML5:

AngularJS Example

<div data-ng-app=“” data-ng-init=“firstName=’John'”><p>The name is <span data-ng-bind=“firstName”></span></p></div>

AngularJS Expressions

AngularJS expressions are written inside double braces: {{ expression }}.

AngularJS expressions bind data to HTML the same way as the ng-bind directive.

AngularJS will “output” data exactly where the expression is written.

AngularJS Example

<!DOCTYPE html>
<html><head>
<script src=“http://ajax.googleapis.com/ajax/libs/angularjs/1.2.26/angular.min.js”></script>
</head><body><div ng-app=“”>
<p>My first expression: {{ 5 + 5 }}</p>
</div></body>
</html>

AngularJS Controllers

AngularJS applications are controlled by controllers.

The ng-controller directive defines the controller.

The controller code will execute when the page loads.

AngularJS Example AngularJS Controllers

<div ng-app=“” ng-controller=“personController”>First Name: <input type=“text” ng-model=“firstName”><br>
Last Name: <input type=“text” ng-model=“lastName”><br>
<br>
Full Name: {{firstName + ” ” + lastName}}</div><script>
function personController($scope) {
$scope.firstName = “John”;
$scope.lastName = “Doe”;
}
</script>

AngularJS Expressions

 AngularJS expressions are written inside double braces: {{ expression }}.

AngularJS expressions binds data to HTML the same way as the ng-bind directive.

AngularJS will “output” data exactly where the expression is written.

AngularJS expressions are much like JavaScript expressions: They can contain literals, operators, and variables.

Example {{ 5 + 5 }} or {{ firstName + ” ” + lastName }}

AngularJS Example

<!DOCTYPE html>
<html><head>
<script src=“http://ajax.googleapis.com/ajax/libs/angularjs/1.2.26/angular.min.js”></script>
</head><body><div ng-app=“”>
<p>My first expression: {{ 5 + 5 }}</p>
</div></body>
</html>

AngularJS Example

<!DOCTYPE html>

<html><head>
<script src=“http://ajax.googleapis.com/ajax/libs/angularjs/1.2.26/angular.min.js”></script>
</head><body><div>
<p>My first expression: {{ 5 + 5 }}</p>
</div></body>
</html>

AngularJS Numbers

AngularJS numbers are like JavaScript numbers:

AngularJS Example

<div ng-app=“” ng-init=“quantity=1;cost=5″><p>Total in dollar: {{ quantity * cost }}</p></div>

AngularJS Example

<div ng-app=“” ng-init=“quantity=1;cost=5″><p>Total in dollar: <span ng-bind=“quantity * cost”></span></p></div>
Using ng-init is not very common. You will learn a better way to initialize data in the chapter about controllers.

AngularJS Strings

AngularJS strings are like JavaScript strings:

AngularJS Example

<div ng-app=“” ng-init=“firstName=’John';lastName=’Doe'”><p>The name is {{ firstName + ” ” + lastName }}</p></div>

AngularJS Example

<div ng-app=“” ng-init=“firstName=’John';lastName=’Doe'”><p>The name is <span ng-bind=“firstName + ‘ ‘ + lastName”></span></p></div>

AngularJS Objects

AngularJS objects are like JavaScript objects:

AngularJS Example

<div ng-app=“” ng-init=“person={firstName:’John’,lastName:’Doe’}”><p>The name is {{ person.lastName }}</p></div>

Same example using ng-bind:

AngularJS Example

<div ng-app=“” ng-init=“person={firstName:’John’,lastName:’Doe’}”><p>The name is <span ng-bind=“person.lastName”></span></p></div>

AngularJS Arrays

AngularJS arrays are like JavaScript arrays:

AngularJS Example

<div ng-app=“” ng-init=“points=[1,15,19,2,40]”>

<p>The points are {{ points[2] }}</p></div>

AngularJS Example

<div ng-app=“” ng-init=“points=[1,15,19,2,40]”>

<p>The points are <span ng-bind=“points[2]”></span></p></div>

AngularJS Directives

AngularJS directives are extended HTML attributes with the prefix ng-.

The ng-app directive initializes an AngularJS application.

The ng-init directive initialize application data.

The ng-model directive binds the value of HTML controls (input, select, textarea) to application data.

AngularJS Example

<div ng-app=“” ng-init=“firstName=’John'”><p>Name: <input type=“text” ng-model=“firstName”></p>
<p>You wrote: {{ firstName }}</p></div>

Data Binding

The {{ firstName }} expression, in the example above, is an AngularJS data binding expression.

Data binding in AngularJS, synchronizes AngularJS expressions with AngularJS data.

{{ firstName }} is synchronized with ng-model=”firstName”.

In the next example two text fields are synchronized with two ng-model directives:

AngularJS Example

<div ng-app=“” ng-init=“quantity=1;price=5″>Quantity: <input type=“number” ng-model=“quantity”>
Costs:    <input type=“number” ng-model=“price”>Total in dollar: {{ quantity * price }}</div>
Using ng-init is not very common. You will learn how to initialize data in the chapter about controllers.

Repeating HTML Elements

The ng-repeat directive repeats an HTML element:

AngularJS Example

<div ng-app=“” ng-init=“names=[‘Jani’,’Hege’,’Kai’]”>
<ul>
<li ng-repeat=“x in names”>
{{ x }}
</li>
</ul>
</div>

AngularJS Example

<div ng-app=“” ng-init=“names=[
{name:’Jani’,country:’Norway’},
{name:’Hege’,country:’Sweden’},
{name:’Kai’,country:’Denmark’}]”
><ul>
<li ng-repeat=“x in names”>
{{ x.name + ‘, ‘ + x.country }}
</li>
</ul></div>
AngularJS is perfect for database CRUD (Create Read Update Delete) applications.
Just imagine if these objects were records from a database.

The ng-app Directive

The ng-app directive defines the root element of an AngularJS application.

The ng-app directive will auto-bootstrap (automatically initialize) the application when a web page is loaded.

Later you will learn how ng-app can have a value (like ng-app=”myModule”), to connect code modules.

The ng-init Directive

The ng-init directive defines initial values for an AngularJS application.

Normally, you will not use ng-init. You will use a controller or module instead.

You will learn more about controllers and modules later.

The ng-model Directive

The ng-model directive binds the value of HTML controls (input, select, textarea) to application data.

The ng-model directive can also:

  • Provide type validation for application data (number, email, required).
  • Provide status for application data (invalid, dirty, touched, error).
  • Provide CSS classes for HTML elements.
  • Bind HTML elements to HTML forms.

The ng-repeat Directive

The ng-repeat directive clones HTML elements once for each item in a collection (in an array).

 

AngularJS Controllers

AngularJS applications are controlled by controllers.

The ng-controller directive defines the application controller.

A controller is a JavaScript Object, created by a standard JavaScript object constructor.

AngularJS Example

<div ng-app=“” ng-controller=“personController”>First Name: <input type=“text” ng-model=“firstName”><br>
Last Name: <input type=“text” ng-model=“lastName”><br>
<br>
Full Name: {{firstName + ” ” + lastName}}</div><script>
function personController($scope) {
$scope.firstName=”John”,
$scope.lastName=”Doe”
}
</script>

Try it Yourself »

Application explained:

The AngularJS application is defined by ng-app. The application runs inside a <div>.

The ng-controller directive names the controller object.

The personController function is a standard JavaScript object constructor.

AngularJS will invoke personController with a $scope object.

In AngularJS, $scope is the application object (the owner of application variables and functions).

The personController creates two properties (variables) in the scope (firstName and lastName).

The ng-model directives bind the input fields to the controller properties (firstName and lastName).


Controller Methods

The example above demonstrated a controller object with two properties: lastName and firstName.

A controller can also have methods (functions as object properties):

AngularJS Example

<div ng-app=“” ng-controller=“personController”>First Name: <input type=“text” ng-model=“firstName”><br>
Last Name: <input type=“text” ng-model=“lastName”><br>
<br>
Full Name: {{fullName()}}</div><script>
function personController($scope) {
$scope.firstName = “John”,
$scope.lastName = “Doe”,
$scope.fullName = function() {
return $scope.firstName + ” ” + $scope.lastName;
}
}
</script>

Try it Yourself »

 


Controllers In External Files

In larger applications, it is common to store controllers in external files.

Just copy the code between the <script> tags into an external file named personController.js:

AngularJS Example

<div ng-app=“” ng-controller=“personController”>First Name: <input type=“text” ng-model=“firstName”><br>
Last Name: <input type=“text” ng-model=“lastName”><br>
<br>
Full Name: {{firstName + ” ” + lastName}}</div><script src=“personController.js”></script>

Try it Yourself »

 


Another Example

For the next example we will create a new controller file:

function namesController($scope) {
$scope.names = [
{name:’Jani’,country:’Norway’},
{name:’Hege’,country:’Sweden’},
{name:’Kai’,country:’Denmark’}
];
}

And then use the controller file in an application:

AngularJS Example

<div ng-app=“” ng-controller=“namesController”><ul>
<li ng-repeat=“x in names”>
{{ x.name + ‘, ‘ + x.country }}
</li>
</ul></div><script src=“namesController.js”></script>

AngularJS Filters

AngularJS filters can be used to transform data:

Filter Description
currency Format a number to a currency format.
filter Select a subset of items from an array.
lowercase Format a string to lower case.
orderBy Orders an array by an expression.
uppercase Format a string to upper case.

Adding Filters to Expressions

A filter can be added to an expression with a pipe character (|) and a filter.

(For the next two examples we will use the person controller from the previous chapter)

The uppercase filter format strings to upper case:

AngularJS Example

<div ng-app=“” ng-controller=“personController”><p>The name is {{ lastName | uppercase }}</p></div>

Try it Yourself »

The lowercase filter format strings to lower case:

AngularJS Example

<div ng-app=“” ng-controller=“personController”><p>The name is {{ lastName | lowercase }}</p></div>

Try it Yourself »


The currency Filter

The currency filter formats a number as currency:

AngularJS Example

<div ng-app=“” ng-controller=“costController”><input type=“number” ng-model=“quantity”>
<input type=“number” ng-model=“price”><p>Total = {{ (quantity * price) | currency }}</p></div>

Try it Yourself »


Adding Filters to Directives

A filter can be added to a directive with a pipe character (|) and a filter.

The orderBy filter orders an array by an expression:

AngularJS Example

<div ng-app=“” ng-controller=“namesController”><ul>
<li ng-repeat=“x in names | orderBy:’country'”>
{{ x.name + ‘, ‘ + x.country }}
</li>
</ul><div>

Try it Yourself »


Filtering Input

An input filter can be added to a directive with a pipe character (|) and filter followed by a colon and a model name.

The filter filter selects a subset of an array:

AngularJS Example

<div ng-app=“” ng-controller=“namesController”><p><input type=“text” ng-model=“test”></p><ul>
<li ng-repeat=“x in names | filter:test | orderBy:’country'”>
{{ (x.name | uppercase) + ‘, ‘ + x.country }}
</li>
</ul></div>

AngularJS XMLHttpRequest

Reading a JSON File

The following static JSON file is stored on a web server:

http://www.w3schools.com/website/Customers_JSON.php

[
{
“Name” : “Alfreds Futterkiste”,
“City” : “Berlin”,
“Country” : “Germany”
},
{
“Name” : “Berglunds snabbköp”,
“City” : “Luleå”,
“Country” : “Sweden”
},
{
“Name” : “Centro comercial Moctezuma”,
“City” : “México D.F.”,
“Country” : “Mexico”
},
{
“Name” : “Ernst Handel”,
“City” : “Graz”,
“Country” : “Austria”
},
{
“Name” : “FISSA Fabrica Inter. Salchichas S.A.”,
“City” : “Madrid”,
“Country” : “Spain”
},
{
“Name” : “Galería del gastrónomo”,
“City” : “Barcelona”,
“Country” : “Spain”
},
{
“Name” : “Island Trading”,
“City” : “Cowes”,
“Country” : “UK”
},
{
“Name” : “Königlich Essen”,
“City” : “Brandenburg”,
“Country” : “Germany”
},
{
“Name” : “Laughing Bacchus Wine Cellars”,
“City” : “Vancouver”,
“Country” : “Canada”
},
{
“Name” : “Magazzini Alimentari Riuniti”,
“City” : “Bergamo”,
“Country” : “Italy”
},
{
“Name” : “North/South”,
“City” : “London”,
“Country” : “UK”
},
{
“Name” : “Paris spécialités”,
“City” : “Paris”,
“Country” : “France”
},
{
“Name” : “Rattlesnake Canyon Grocery”,
“City” : “Albuquerque”,
“Country” : “USA”
},
{
“Name” : “Simons bistro”,
“City” : “København”,
“Country” : “Denmark”
},
{
“Name” : “The Big Cheese”,
“City” : “Portland”,
“Country” : “USA”
},
{
“Name” : “Vaffeljernet”,
“City” : “Århus”,
“Country” : “Denmark”
},
{
“Name” : “Wolski Zajazd”,
“City” : “Warszawa”,
“Country” : “Poland”
}
]

 


AngularJS $http

AngularJS $http is a core service for reading data from web servers.

$http.get(url) is the function to use for reading server data.

AngularJS Example

<div ng-app=“” ng-controller=“customersController”><ul>
<li ng-repeat=“x in names”>
{{ x.Name + ‘, ‘ + x.Country }}
</li>
</ul></div><script>
function customersController($scope,$http) {
$http.get(“http://www.w3schools.com/website/Customers_JSON.php”)
.success(function(response) {$scope.names = response;});
}
</script>

Try it Yourself »

Application explained:

The AngularJS application is defined by ng-app. The application runs inside a <div>.

The ng-controller directive names the controller object.

The customersController function is a standard JavaScript object constructor.

AngularJS will invoke customersController with a $scope and $http object.

$scope is the application object (the owner of application variables and functions).

$http is an XMLHttpRequest object for requesting external data.

$http.get() reads static JSON data from http://www.w3schools.com/website/Customers_JSON.php.

If success, the controller creates a property (names) in the scope, with JSON data from the server.

The code above can also be used to fetch data from a database.

 

AngularJS Tables

Displaying Data in a Table

Displaying tables with angular is very simple:

AngularJS Example

<div ng-app=“” ng-controller=“customersController”><table>
<tr ng-repeat=“x in names”>
<td>{{ x.Name }}</td>
<td>{{ x.Country }}</td>
</tr>
</table></div><script>
function customersController($scope,$http) {
$http.get(“http://www.w3schools.com/website/Customers_JSON.php”)
.success(function(response) {$scope.names = response;});
}
</script>

Try it Yourself »

 


Displaying with CSS Style

To make it nice, add some CSS to the page:

CSS Style

<style>
table, th , td
{
border: 1px solid grey;
border-collapse: collapse;
padding: 5px;
}
table tr:nth-child(odd) {
background-color: #f1f1f1;
}
table tr:nth-child(even) {
background-color: #ffffff;
}
</style>

Try it Yourself »

 


Display with orderBy Filter

To sort the table, add an orderBy filter:

AngularJS Example

<table>
<tr ng-repeat=“x in names | orderBy : ‘Country'”>
<td>{{ x.Name }}</td>
<td>{{ x.Country }}</td>
</tr>
</table>

Try it Yourself »

 


Display with uppercase Filter

To display uppercase, add an uppercase filter:

AngularJS Example

<table>
<tr ng-repeat=“x in names”>
<td>{{ x.Name }}</td>
<td>{{ x.Country | uppercase}}</td>
</tr>
</table>

 

 

AngularJS SQL

Fetching Data From a PHP Server Running MySQL

AngularJS Example

<div ng-app=“” ng-controller=“customersController”><table>
<tr ng-repeat=“x in names”>
<td>{{ x.Name }}</td>
<td>{{ x.Country }}</td>
</tr>
</table></div><script>
function customersController($scope,$http) {
var site = “http://www.w3schools.com”;
var page = “/website/Customers_MySQL.php”;
$http.get(site + page)
.success(function(response) {$scope.names = response;});
}
</script>

Try it Yourself »

 


Fetching Data From an ASP.NET Server Running SQL

AngularJS Example

<div ng-app=“” ng-controller=“customersController”><table>
<tr ng-repeat=“x in names”>
<td>{{ x.Name }}</td>
<td>{{ x.Country }}</td>
</tr>
</table></div><script>
function customersController($scope,$http) {
var site = “http://www.w3schools.com”;
var page = “/website/Customers_SQL.aspx”;
$http.get(site + page)
.success(function(response) {$scope.names = response;});
}
</script>

Try it Yourself »

 


Server Code Examples

The following section is a listing of the server code used to fetch SQL data.

  1. Using PHP and MySQL. Returning JSON.
  2. Using PHP and MS Access. Returning JSON.
  3. Using ASP.NET, VB, and MS Access. Returning JSON.
  4. Using ASP.NET, Razor, and SQL Lite. Returning JSON.

Cross-Site HTTP Requests

Requests for data from a different server (than the requesting page), are called cross-site HTTP requests.

Cross-site requests are common on the web. Many pages load CSS, images, and scripts from different servers.

In modern browsers, cross-site HTTP requests from scripts are restricted to same site for security reasons.

The following line, in our PHP examples, has been added to allow cross-site access.

header(“Access-Control-Allow-Origin: *”);

 


1. Server Code PHP and MySQL

<?php
header(“Access-Control-Allow-Origin: *”);
header(“Content-Type: application/json; charset=UTF-8″);$conn = new mysqli(“myServer”, “myUser”, “myPassword”, “Northwind”);$result = $conn->query(“SELECT CompanyName, City, Country FROM Customers”);$outp = “[“;
while($rs = $result->fetch_array(MYSQLI_ASSOC)) {
if ($outp != “[“) {$outp .= “,”;}
$outp .= ‘{“Name”:”‘  . $rs[“CompanyName”] . ‘”,';
$outp .= ‘”City”:”‘   . $rs[“City”]        . ‘”,';
$outp .= ‘”Country”:”‘. $rs[“Country”]     . ‘”}';
}
$outp .=”]”;$conn->close();

echo($outp);
?>

 


2. Server Code PHP and MS Access

<?php
header(“Access-Control-Allow-Origin: *”);
header(“Content-Type: application/json; charset=ISO-8859-1″);$conn = new COM(“ADODB.Connection”);
$conn->open(“PROVIDER=Microsoft.Jet.OLEDB.4.0;Data Source=Northwind.mdb”);$rs = $conn->execute(“SELECT CompanyName, City, Country FROM Customers”);$outp = “[“;
while (!$rs->EOF) {
if ($outp != “[“) {$outp .= “,”;}
$outp .= ‘{“Name”:”‘  . $rs[“CompanyName”] . ‘”,';
$outp .= ‘”City”:”‘   . $rs[“City”]        . ‘”,';
$outp .= ‘”Country”:”‘. $rs[“Country”]     . ‘”}';
$rs->MoveNext();
}
$outp .= “]”;$conn->close();

echo ($outp);
?>

 


3. Server Code ASP.NET, VB and MS Access

<%@ Import Namespace=”System.IO”%>
<%@ Import Namespace=”System.Data”%>
<%@ Import Namespace=”System.Data.OleDb”%>
<%
Response.AppendHeader(“Access-Control-Allow-Origin”, “*”)
Response.AppendHeader(“Content-type”, “application/json”)
Dim conn As OleDbConnection
Dim objAdapter As OleDbDataAdapter
Dim objTable As DataTable
Dim objRow As DataRow
Dim objDataSet As New DataSet()
Dim outp
Dim c
conn = New OledbConnection(“Provider=Microsoft.Jet.OLEDB.4.0;data source=Northwind.mdb”)
objAdapter = New OledbDataAdapter(“SELECT CompanyName, City, Country FROM Customers”, conn)
objAdapter.Fill(objDataSet, “myTable”)
objTable=objDataSet.Tables(“myTable”)outp = “[”
c = chr(34)
for each x in objTable.Rows
if outp <> “[” then outp = outp & “,”
outp = outp & “{” & c & “Name”    & c & “:” & c & x(“CompanyName”) & c & “,”
outp = outp &       c & “City”    & c & “:” & c & x(“City”)        & c & “,”
outp = outp &       c & “Country” & c & “:” & c & x(“Country”)     & c & “}”
nextoutp = outp & “]”
response.write(outp)
conn.close
%>

 


4. Server Code ASP.NET, VB Razor and SQL Lite

@{
Response.AppendHeader(“Access-Control-Allow-Origin”, “*”)
Response.AppendHeader(“Content-type”, “application/json”)
var db = Database.Open(“Northwind”);
var query = db.Query(“SELECT CompanyName, City, Country FROM Customers”);
var outp =”[”
}
@foreach(var row in query)
{
if outp <> “[” then outp = outp + “,”
outp = outp + “{” + c + “Name”    + c + “:” + c + @row.CompanyName + c + “,”
outp = outp +       c + “City”    + c + “:” + c + @row.City        + c + “,”
outp = outp +       c + “Country” + c + “:” + c + @row.Country     + c + “}”
}
outp = outp + “]”
@outp

AngularJS HTML DOM

The ng-disabled Directive

The ng-disabled directive binds AngularJS application data to the disabled attribute of HTML elements.

AngularJS Example

<div ng-app=“”><p>
<button ng-disabled=“mySwitch”>Click Me!</button>
</p><p>
<input type=“checkbox” ng-model=“mySwitch”>Button
</p></div>

Try it Yourself »

Application explained:

The ng-disabled directive binds the application data mySwitch to the HTML button’s disabled attribute.

The ng-model directive binds the value of the HTML checkbox element to the value of mySwitch.

If the value of mySwitch evaluates to true, the button will be disabled:

<p>
<button disabled>Click Me!</button>
</p>

If the value of mySwitch evaluates to false, the button will not be disabled:

<p>
<button>Click Me!</button>
</p>

 


The ng-show Directive

The ng-show directive shows or hides an HTML element.

AngularJS Example

<div ng-app=“”><p ng-show=“true”>I am visible.</p><p ng-show=“false”>I am not visible.</p></div>

Try it Yourself »

The ng-show directive shows (or hides) an HTML element based on the value of ng-show.

You can use any expression that evaluates to true or false:

AngularJS Example

<div ng-app=“”><p ng-show=“hour > 12″>I am visible.</p></div>

Try it Yourself »

Note In the next chapter, there are more examples, using the click of a button to hide HTML elements.

The ng-hide Directive

The ng-hide directive hides or shows an HTML element.

AngularJS Example

<div ng-app=“”><p ng-hide=“true”>I am not visible.</p><p ng-hide=“false”>I am visible.</p></div>

AngularJS Events

The ng-click Directive

The ng-click directive defines an AngularJS click event.

AngularJS Example

<div ng-app=“” ng-controller=“myController”><button ng-click=“count = count + 1″>Click me!</button><p>{{ count }}</p></div>

Try it Yourself »

 


Hiding HTML Elements

The ng-hide directive can be used to set the visibility of a part of an application.

The value ng-hide=”true” makes an HTML element invisible.

The value ng-hide=”false” makes the element visible.

AngularJS Example

<div ng-app=“” ng-controller=“personController”><button ng-click=“toggle()”>Toggle</button><p ng-hide=“myVar”>
First Name: <input type=“text” ng-model=“firstName”><br>
Last Name: <input type=“text” ng-model=“lastName”><br>
<br>
Full Name: {{firstName + ” ” + lastName}}
</p></div><script>
function personController($scope) {
$scope.firstName = “John”,
$scope.lastName = “Doe”
$scope.myVar = false;
$scope.toggle = function() {
$scope.myVar = !$scope.myVar;
};
}
</script>

Try it Yourself »

Application explained:

The first part of the personController is the same as in the chapter about controllers.

The application has a default property (a variable): $scope.myVar = false;

The ng-hide directive sets the visibility, of a <p> element with two input fields, according to the value (true or false) of myVar.

The function toggle() toggles myVar between true and false.

The value ng-hide=”true” makes the element invisible.


Showing HTML Elements

The ng-show directive can also be used to set the visibility of a part of an application.

The value ng-show=”false” makes an HTML element invisible.

The value ng-show=”true” makes the element visible.

Here is the same example as above, using ng-show instead of ng-hide:

AngularJS Example

<div ng-app=“” ng-controller=“personController”><button ng-click=“toggle()”>Toggle</button><p ng-show=“myVar”>
First Name: <input type=“text” ng-model=“firstName”><br>
Last Name: <input type=“text” ng-model=“lastName”><br>
<br>
Full Name: {{firstName + ” ” + lastName}}
</p></div><script>
function personController($scope) {
$scope.firstName = “John”,
$scope.lastName = “Doe”
$scope.myVar = true;
$scope.toggle = function() {
$scope.myVar = !$scope.myVar;
};
}
</script>

AngularJS Modules

AngularJS Module Example

In this example, “myApp.js” contains an application module definition, “myCtrl.js” contains a controller:

AngularJS Example

<!DOCTYPE html>
<html><head>
<script src=“http://ajax.googleapis.com/ajax/libs/angularjs/1.2.26/angular.min.js”></script>
</head><body><div ng-app=“myApp” ng-controller=“myCtrl”>
{{ firstName + ” ” + lastName }}
</div><script src=“myApp.js”></script>
<script src=“myCtrl.js”></script>

</body>
</html>

Try it Yourself »

 


Controllers Pollute the Global Namespace

All examples in this tutorial, have used global values (global variables or global functions).

Global values should be avoided in applications. They can easily be overwritten or destroyed by other scripts.

AngularJS modules can solve (or reduce) this problem.


A Controller Without a Module

The application does not have a name, and the controller function is global:

AngularJS Example

<!DOCTYPE html>
<html><head>
<script src=“http://ajax.googleapis.com/ajax/libs/angularjs/1.2.26/angular.min.js”></script>
</head><body><div ng-app=“” ng-controller=“myCtrl”>
{{ firstName + ” ” + lastName }}
</div><script>
function myCtrl($scope) {
$scope.firstName = “John”;
$scope.lastName = “Doe”;
}
</script>

</body>
</html>

Try it Yourself »

 


A Controller With a Module

The application has a name (ng-app=”myApp”), and the controller is a property of the module:

AngularJS Example

<!DOCTYPE html>
<html><head>
<script src=“http://ajax.googleapis.com/ajax/libs/angularjs/1.2.26/angular.min.js”></script>
</head><body><div ng-app=“myApp” ng-controller=“myCtrl”>
{{ firstName + ” ” + lastName }}
</div><script>
var app = angular.module(“myApp”, []);

app.controller(“myCtrl”, function($scope) {
$scope.firstName = “John”;
$scope.lastName = “Doe”;
});
</script>

</body>
</html>

Try it Yourself »

 


When to Load the Library?

Note In all our examples, the AngularJS library is loaded in the <head> section.

A common advise for HTML applications, is to place all scripts at the very bottom of the <body> element.

But, in many AngularJS examples, you will see the library in the <head> element.

This is because calls to angular.module can only be compiled after the library has been loaded.

Another solution is to load the AngularJS library in the <body> element, but before your own AngularJS scripts:

AngularJS Example

<!DOCTYPE html>
<html>
<body><div ng-app=“myApp” ng-controller=“myCtrl”>
{{ firstName + ” ” + lastName }}
</div><script src=“http://ajax.googleapis.com/ajax/libs/angularjs/1.2.26/angular.min.js”></script><script>
var app = angular.module(“myApp”, []);app.controller(“myCtrl”, function($scope) {
$scope.firstName = “John”;
$scope.lastName = “Doe”;
});
</script>

</body>
</html>

Try it Yourself »

 


AngularJS Application Files

Now that you know what modules are, and how they work, it is time to build your application file.

Your application should have at least one module file, and one controller file for each controller.

First create a module file “myApp.js”:

var app = angular.module(“myApp”, []);
Note The [] parameter in the module definition can be used to define dependent modules.

Then create the controller file(s). In this case “myCtrl.js”:

app.controller(“myCtrl”, function($scope) {
$scope.firstName = “John”;
$scope.lastName = “Doe”;
});

Finally, edit your HTML page:

AngularJS Example

<!DOCTYPE html>
<html><head>
<script src=“http://ajax.googleapis.com/ajax/libs/angularjs/1.2.26/angular.min.js”></script>
</head><body><div ng-app=“myApp” ng-controller=“myCtrl”>
{{ firstName + ” ” + lastName }}
</div><script src=“myApp.js”></script>
<script src=“myCtrl.js”></script>

</body>
</html>

AngularJS Forms

HTML Controls

HTML input elements are called HTML controls:

  • input elements
  • select elements
  • button elements
  • textarea elements

HTML Forms

HTML forms group HTML controls together.


An AngularJS Form Example

First Name:

Last Name:

form = {“firstName”:”John”,”lastName”:”Doe”}

master = {“firstName”:”John”,”lastName”:”Doe”}


Application Code

<div ng-app=“” ng-controller=“formController”>
<form novalidate>
First Name:<br>
<input type=“text” ng-model=“user.firstName”><br>
Last Name:<br>
<input type=“text” ng-model=“user.lastName”>
<br><br>
<button ng-click=“reset()”>RESET</button>
</form>
<p>form = {{user}}</p>
<p>master = {{master}}</p>
</div><script>
function formController ($scope) {
$scope.master = {firstName: “John”, lastName: “Doe”};
$scope.reset = function() {
$scope.user = angular.copy($scope.master);
};
$scope.reset();
};
</script>

Try it Yourself »

Note The novalidate attribute is new in HTML5. It disables any default browser validation.

Example Explained

The ng-app directive defines the AngularJS application.

The ng-controller directive defines the application controller.

The ng-model directive binds two input elements to the user object in the model.

The formController() function sets initial values to the master object, and invokes the reset() method.

The reset() method sets the user object equal to the master object.

The ng-click directive invokes the reset() method, only if the button is clicked.

The novalidate attribute is not needed for this application, but normally you will use it in AngularJS forms, to override standard HTML5 validation.

AngularJS Input Validation

 

Input Validation

In the previous chapter, you learned about AngularJS forms and controls.

AngularJS forms and controls can provide validation services, and notify users of invalid input.

Client-side validation cannot alone secure user input. Server side validation is also necessary.

Application Code

<!DOCTYPE html>
<html><head>
<script src=“http://ajax.googleapis.com/ajax/libs/angularjs/1.2.26/angular.min.js”></script>
</head><body>
<h2>Validation Example</h2><form  ng-app=“”  ng-controller=“validateCtrl”
name=
“myForm” novalidate><p>Username:<br>
<input type=“text” name=“user” ng-model=“user” required>
<span style=“color:red” ng-show=“myForm.user.$dirty && myForm.user.$invalid”>
<span ng-show=“myForm.user.$error.required”>Username is required.</span>
</span>
</p>

<p>Email:<br>
<input type=“email” name=“email” ng-model=“email” required>
<span style=“color:red” ng-show=“myForm.email.$dirty && myForm.email.$invalid”>
<span ng-show=“myForm.email.$error.required”>Email is required.</span>
<span ng-show=“myForm.email.$error.email”>Invalid email address.</span>
</span>
</p>

<p>
<input type=“submit”
ng-disabled=
“myForm.user.$dirty && myForm.user.$invalid ||
myForm.email.$dirty && myForm.email.$invalid”
>
</p>

</form>

<script>
function validateCtrl($scope) {
$scope.user = ‘John Doe';
$scope.email = ‘john.doe@gmail.com';
}
</script>

</body>
</html>

Try it Yourself »

The HTML form attribute novalidate is used to disable default browser validation.

 

AngularJS and Twitter Bootstrap

 

Bootstrap

To include Bootstrap in your AngularJS application, add the following line to your <head> element:

<link rel=“stylesheet” href=“http://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css”>

If you want to study Bootstrap, visit our Bootstrap Tutorial.

Below is a complete HTML example, with all AngularJS directives and Bootstrap classes explained.


HTML Code

<!DOCTYPE html>
<html ng-app=“”>
<head>
<link rel=“stylesheet” href=“http://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css”>
<script src=“http://ajax.googleapis.com/ajax/libs/angularjs/1.2.26/angular.min.js”></script>
</head><body ng-controller=“userController”>
<div class=“container”><h3>Users</h3><table class=“table table-striped”>
<thead><tr>
<th>Edit</th>
<th>First Name</th>
<th>Last Name</th>
</tr></thead>
<tbody><tr ng-repeat=“user in users”>
<td>
<button class=“btn” ng-click=“editUser(user.id)”>
<span class=“glyphicon glyphicon-pencil”></span>&nbsp;&nbsp;Edit
</button>
</td>
<td>{{ user.fName }}</td>
<td>{{ user.lName }}</td>
</tr></tbody>
</table><hr>
<button class=“btn btn-success” ng-click=“editUser(‘new’)”>
<span class=“glyphicon glyphicon-user”></span> Create New User
</button>
<hr>

<h3 ng-show=“edit”>Create New User:</h3>
<h3 ng-hide=“edit”>Edit User:</h3>

<form class=“form-horizontal”>
<div class=“form-group”>
<label class=“col-sm-2 control-label”>First Name:</label>
<div class=“col-sm-10″>
<input type=“text” ng-model=“fName” ng-disabled=“!edit” placeholder=“First Name”>
</div>
</div>
<div class=“form-group”>
<label class=“col-sm-2 control-label”>Last Name:</label>
<div class=“col-sm-10″>
<input type=“text” ng-model=“lName” ng-disabled=“!edit” placeholder=“Last Name”>
</div>
</div>
<div class=“form-group”>
<label class=“col-sm-2 control-label”>Password:</label>
<div class=“col-sm-10″>
<input type=“password” ng-model=“passw1″ placeholder=“Password”>
</div>
</div>
<div class=“form-group”>
<label class=“col-sm-2 control-label”>Repeat:</label>
<div class=“col-sm-10″>
<input type=“password” ng-model=“passw2″ placeholder=“Repeat Password”>
</div>
</div>
</form>

<hr>
<button class=“btn btn-success” ng-disabled=“error || incomplete”>
<span class=“glyphicon glyphicon-save”></span> Save Changes
</button>
</div>

<script src = “myUsers.js”></script>
</body>
</html>

Try it Yourself »

 


Directives (Used Above) Explained

AngularJS Directive Description
<html ng-app Defines an (unnamed) application for the <html> element
<body ng-controller Defines a controller for the <body> element
<tr ng-repeat Repeats the <tr> element for each user in users
<button ng-click Invoke the function editUser() when the <button> element is clicked
<h3 ng-show Show the <h3>s element if edit = true
<h3 ng-hide Hide the <h3> element if edit = true
<input ng-model Bind the <input> element to the application
<button ng-disabled Disables the <button> element if error or incomplete = true

 


Bootstrap Classes Explained

Element Bootstrap Class Defines
<div> container A content container
<table> table A table
<table> table-striped A striped table
<button> btn A button
<button> btn-success A success button
<span> glyphicon A glyph icon
<span> glyphicon-pencil A pencil icon
<span> glyphicon-user A user icon
<span> glyphicon-save A save icon
<form> form-horizontal A horizontal form
<div> form-group A form group
<label> control-label A control label
<label> col-sm-2 A 2 columns span
<div> col-sm-10 A 10 columns span

 


JavaScript Code

function userController($scope) {
$scope.fName = ;
$scope.lName = ;
$scope.passw1 = ;
$scope.passw2 = ;
$scope.users = [
{id:1, fName:‘Hege’,  lName:“Pege” },
{id:2, fName:‘Kim’,   lName:“Pim” },
{id:3, fName:‘Sal’,   lName:“Smith” },
{id:4, fName:‘Jack’,  lName:“Jones” },
{id:5, fName:‘John’,  lName:“Doe” },
{id:6, fName:‘Peter’, lName:“Pan” }
];
$scope.edit = true;
$scope.error = false;
$scope.incomplete = false;$scope.editUser = function(id) {
if (id == ‘new’) {
$scope.edit = true;
$scope.incomplete = true;
$scope.fName = ;
$scope.lName = ;
} else {
$scope.edit = false;
$scope.fName = $scope.users[id-1].fName;
$scope.lName = $scope.users[id-1].lName;
}
};$scope.$watch(‘passw1′,function() {$scope.test();});
$scope.$watch(‘passw2′,function() {$scope.test();});
$scope.$watch(‘fName’function() {$scope.test();});
$scope.$watch(‘lName’function() {$scope.test();});$scope.test = function() {
if ($scope.passw1 !== $scope.passw2) {
$scope.error = true;
} else {
$scope.error = false;
}
$scope.incomplete = false;
if ($scope.edit && (!$scope.fName.length ||
!$scope.lName.length ||
!$scope.passw1.length || !$scope.passw2.length)) {
$scope.incomplete = true;
}
};}

 


JavaScript Code Explained

Scope Properties Used for
$scope.fName Model variable (user first name)
$scope.lName Model variable (user last name)
$scope.passw1 Model variable (user password 1)
$scope.passw2 Model variable (user password 2)
$scope.users Model variable (array of users)
$scope.edit Set to true when user clicks on create user.
$scope.error Set to true if passw1 not equal passw2
$scope.incomplete Set to true if any field is empty (length = 0)
$scope.editUser Sets model variables
$scope.watch Watches model variables
$scope.test Tests model variables for errors and incompleteness

 

AngularJS Includes

 

HTML Includes in Future HTML

Including a portion of HTML in HTML is, unfortunately, not (yet) supported by HTML.

HTML imports is a W3C suggestion http://www.w3.org for future versions of HTML:

<link rel=“import” href=“/path/navigation.html”>

 


Server Side Includes

Most web servers support Server Side Includes (SSI).

With SSI, you can include HTML in HTML before the page is sent to the browser.

PHP Example

<?php require(“navigation.php”); ?>

 


Client Side Includes

There are many ways to use JavaScript to include HTML in HTML.

The most common way, is to use an http request (AJAX) to fetch data from a server, and then write the data to the innerHTML of an HTML element.


AngularJS Side Includes

With AngularJS, you can include HTML content, using the ng-include directive:

Example

<body><div class=“container”>
<div ng-include=“‘myUsers_List.htm'”></div>
<div ng-include=“‘myUsers_Form.htm'”></div>
</div></body>

Try it Yourself »

Below is a 3 step introduction.


Step 1: Create the HTML List

myUsers_List.html

<table class=“table table-striped”>
<thead><tr>
<th>Edit</th>
<th>First Name</th>
<th>Last Name</th>
</tr></thead>
<tbody><tr ng-repeat=“user in users”>
<td>
<button class=“btn” ng-click=“editUser(user.id)”>
<span class=“glyphicon glyphicon-pencil”></span>&nbsp;&nbsp;Edit
</button>
</td>
<td>{{ user.fName }}</td>
<td>{{ user.lName }}</td>
</tr></tbody>
</table>

Try it Yourself »

 


Step 2: Create the HTML Form

myUsers_Form.html

<button class=“btn btn-success” ng-click=“editUser(‘new’)”>
<span class=“glyphicon glyphicon-user”></span> Create New User
</button>
<hr><h3 ng-show=“edit”>Create New User:</h3>
<h3 ng-hide=“edit”>Edit User:</h3><form class=“form-horizontal”>
<div class=“form-group”>
<label class=“col-sm-2 control-label”>First Name:</label>
<div class=“col-sm-10″>
<input type=“text” ng-model=“fName” ng-disabled=“!edit” placeholder=“First Name”>
</div>
</div>
<div class=“form-group”>
<label class=“col-sm-2 control-label”>Last Name:</label>
<div class=“col-sm-10″>
<input type=“text” ng-model=“lName” ng-disabled=“!edit” placeholder=“Last Name”>
</div>
</div>
<div class=“form-group”>
<label class=“col-sm-2 control-label”>Password:</label>
<div class=“col-sm-10″>
<input type=“password” ng-model=“passw1″ placeholder=“Password”>
</div>
</div>
<div class=“form-group”>
<label class=“col-sm-2 control-label”>Repeat:</label>
<div class=“col-sm-10″>
<input type=“password” ng-model=“passw2″ placeholder=“Repeat Password”>
</div>
</div>
</form><hr>
<button class=“btn btn-success” ng-disabled=“error || incomplete”>
<span class=“glyphicon glyphicon-save”></span> Save Changes
</button>

Try it Yourself »

 


Step 3: Create the Main Page

myUsers.html

<!DOCTYPE html>
<html ng-app=“”>
<head>
<link rel=“stylesheet” href = “http://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css”>
<script src= “http://ajax.googleapis.com/ajax/libs/angularjs/1.2.26/angular.min.js”></script>
</head><body ng-controller=“userController”><div class=“container”>
<div ng-include=“‘myUsers_List.htm'”></div>
<div ng-include=“‘myUsers_Form.htm'”></div>
</div><script src= “myUsers.js”></script></body>
</html>

AngularJS Application

An AngularJS Application Example

You have learned more than enough to create your first AngularJS application:

My Note

 

Number of characters left: 100

 


Application Explained

AngularJS Example

<html ng-app=“myNoteApp”><head>
<script src=“http://ajax.googleapis.com/ajax/libs/angularjs/1.2.26/angular.min.js”></script>
</head><body><div ng-controller=“myNoteCtrl”><h2>My Note</h2>

<p><textarea ng-model=“message” cols=“40” rows=“10”></textarea></p>

<p>
<button ng_click=“save()”>Save</button>
<button ng-click=“clear()”>Clear</button>
</p>

<p>Number of characters left: <span ng-bind=“left()”></span></p>

</div>

<script src=“myNoteApp.js”></script>
<script src=“myNoteCtrl.js”></script>

</body>
</html>

Try it Yourself »

The application file “myNoteApp.js”:

var app = angular.module(“myNoteApp”, []);

The controller file “myNoteCtrl.js”:

app.controller(“myNoteCtrl”, function($scope) {
$scope.message = “”;
$scope.left  = function() {return 100 – $scope.message.length;};
$scope.clear = function() {$scope.message = “”;};
$scope.save  = function() {alert(“Note Saved”);};
});

The <html> element is the container of the AngularJS application: ng-app=”myNoteApp“:

<html ng-app=“myNoteApp”>

A a <div> in the HTML page is the scope of a controller: ng-controller=”myNoteCtrl“:

<div ng-controller=“myNoteCtrl”>

An ng-model directive binds a <textarea> to the controller variable message:

<textarea ng-model=“message” cols=“40” rows=“10”></textarea>

The two ng-click events invoke the controller functions clear() and save():

<button ng_click=“save()”>Save</button>
<button ng-click=“clear()”>Clear</button>

An ng-bind directive binds the controller function left() to a <span> displaying the characters left:

Number of characters left: <span ng-bind=“left()”></span>

Your application libraries are added to the page (after the library):

<script src=“myNoteApp.js”></script>
<script src=“myNoteCtrl.js”></script>

 


AngularJS Application Skeleton

Above you have the skeleton (scaffolding) of a real life AngularJS, single page application (SPA).

The <html> element is the “container” for the AngularJS application (ng-app=).

A <div> elements defines the scope of an AngularJS controller (ng-controller=).

You can have many controllers in one application.

An application file (my…App.js) defines the application module code.

One or more controller files (my…Ctrl.js) defines the controller code.


Summary – How Does it Work?

The AngularJS library in loaded in <head>,  because scripts depend on the library code to be correctly compiled.

The ng-app directive is placed at the root element the application.

For single page applications (SPA), the root of the application is often the <html> element.

One or more ng-controller directives define the application controllers. Each controller has its own scope: the HTML element where they were defined.

AngularJS starts automatically on the HTML DOMContentLoaded event. If an ng-app directive is found, AngularJS will load any module named in the directive, and compile the DOM with ng-app as the root of the application.

The root of the application can be the whole page, or a smaller portion of the page. The smaller the portion, the faster the application will compile and execute.

 

 

Rate: 0

Bootstrap Tutorial

 

Bootstrap 

Bootstrap Example

<div class=“container”>
<p>Create a responsive table with alternating cell background color:</p>

<div class=“table-responsive”>
<table class=“table table-striped table-bordered”>
<thead>
<tr>
<th>#</th>
<th>Name</th>
<th>Street</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>Anna Awesome</td>
<td>Broome Street</td>
</tr>
<tr>
<td>2</td>
<td>Debbie Dallas</td>
<td>Houston Street</td>
</tr>
<tr>
<td>3</td>
<td>John Doe</td>
<td>Madison Street</td>
</tr>
</tbody>
</table>
</div>

</div>

What You Should Already Know

Before you continue you should have a basic understanding of the following:

  • HTML
  • CSS
  • (JavaScript/jQuery)

I

What is Bootstrap?

  • Bootstrap is a free collection of tools for creating websites and web applications
  • Bootstrap contains HTML and CSS-based design templates for text, forms, buttons, navigation and other components
  • Bootstrap also contains optional JavaScript extensions
  • Bootstrap is open source and available on GitHub

Bootstrap History

Bootstrap was developed by Mark Otto and Jacob Thornton at Twitter as a framework to encourage consistency across internal tools. Before Bootstrap, various libraries were used for interface development, which led to inconsistencies and a high maintenance burden.

Bootstrap was released as an open source product in August 2011 on GitHub.

In June 2014 Bootstrap was the No.1 project on GitHub!

Why Use Bootstrap?

  • Mobile-first approach: Since Bootstrap 3, the framework consists of mobile-first styles throughout the entire library
  • Browser support: Bootstrap is supported by all popular browsers
  • Responsive web design: Bootstrap’s responsive CSS adjusts to Desktops, Tablets, and Mobile phones
  • Easy to get started: With just the knowledge of HTML and CSS anyone can get started with Bootstrap
What is Responsive Web Design?
Responsive web design is to create web sites which adjust and align themselves according to what media tool you use for viewing it.What Does Bootstrap Include?
  • Scaffolding: Contains layout, grid system, fluid grid system, and responsive design
  • Base CSS: Contains classes for typography, tables, forms, buttons, images, and more
  • Components: Contains reusable components: icons, dropdowns, navbars, breadcrumbs, alerts, and more
  • JavaScript Plugins: Contains over a dozen custom jQuery plugins. You can include them all, or one by one
  • Customizable Components : Customize Bootstrap’s components, LESS variables, and jQuery plugins to create your own version

The HTML File

Since Bootstrap uses HTML elements and CSS properties that require the use of the HTML5 doctype, include the HTML5 doctype at the beginning of the page, along with the correct character set:

<!DOCTYPE html>
<html>
<head>
<meta charset=“utf-8″>
</head>
</html>

Keep in mind that Bootstrap 3 is mobile-first. Mobile-first styles are found throughout the entire Bootstrap library instead of in separate files.

To ensure proper rendering and touch zooming, also add the viewport meta tag inside the <head> element:

<meta name=“viewport” content=“width=device-width, initial-scale=1″>

The width=device-width sets the width of the page to follow the screen-width of the device (which will vary depending on the device).

The initial-scale=1 sets the initial zoom level when the page is first loaded by the browser.

Adding Bootstrap to Your Web Pages

There are two ways of starting to use Bootstrap on your own web site.

You can:

  • Download Bootstrap from getbootstrap.com
  • Include Bootstrap from a CDN, like MaxCDN

Bootstrap CDN

If you don’t want to download and host Bootstrap yourself, you can include it from a CDN (Content Delivery Network).

MaxCDN provide CDN support for Bootstrap’s CSS and JavaScript. Also include jQuery:

MaxCDN:

<!– Latest compiled and minified CSS –>
<link rel=“stylesheet” href=“http://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css”>

<!– Optional: Include the jQuery library –>
<script src=“https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js”></script>
<!– Optional: Incorporate the Bootstrap JavaScript plugins –>
<script src=“http://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js”></script>

 

One advantage of using the Bootstrap CDN:
Many users already have downloaded Bootstrap from MaxCDN when visiting another site. As a result, it will be loaded from cache when they visit your site, which leads to faster loading time. Also, most CDN’s will make sure that once a user requests a file from it, it will be served from the server closest to them, which also leads to faster loading time.

 

Put Your HTML Elements Inside Containers

Bootstrap also requires a containing element to wrap site contents.

There are two containers to choose from:

1. Use the .container class for a responsive fixed width container:

Example

<div class=“container”>

</div>

2. Use the .container-fluid class for a full width container, spanning the entire width of the viewport:

Example

<div class=“container-fluid”>

</div>

Bootstrap’s Default Settings

By default, the Bootstrap style sheet has some default settings. These are:

The <body> element have a font-size of 14px, and a line-height of 1.428.

In addition, all <p> elements have a bottom margin that equals half their computed line-height (10px by default).

Bootstrap vs. Browser Defaults

In this chapter, we will look at some HTML elements that will be styled a little bit differently by Bootstrap than browser defaults.

<h1> – <h6>

By default, Bootstrap will style the HTML headings in the following way:

Example

h1 Bootstrap heading (36px)

h2 Bootstrap heading (30px)

h3 Bootstrap heading (24px)

h4 Bootstrap heading (18px)

h5 Bootstrap heading (14px)
h6 Bootstrap heading (12px)

<small>

In Bootstrap the <small> element will create a lighter, secondary text in any heading:

Example

h1 heading lighter, smaller text

h2 heading lighter, smaller text

h3 heading lighter, smaller text

h4 heading lighter, smaller text

h5 heading lighter, smaller text
h6 heading lighter, smaller text

<mark>

By default, Bootstrap will style the HTML <mark> element in the following way:

Example

Use the mark element to highlight text.

<abbr>

By default, Bootstrap will style the HTML <abbr> element in the following way (with a dotted bottom border and a help cursor on hover):

Example

The WHO was founded in 1948.

<blockquote>

By default, Bootstrap will style the HTML <blockquote> element in the following way:

Example

For 50 years, WWF has been protecting the future of nature. The world’s leading conservation organization, WWF works in 100 countries and is supported by 1.2 million members in the United States and close to 5 million globally.

From WWF’s website

<dl>

By default, Bootstrap will style the HTML <dl> element in the following way:

Example

Coffee
- black hot drink
Milk
- white cold drink

<code>

By default, Bootstrap will style the HTML <code> element in the following way:

Example

The following HTML elements: span, section, and div defines a section in a document.

<kbd>

By default, Bootstrap will style the HTML <kbd> element in the following way:

Example

Use ctrl + p to open the Print dialog box.

<pre>

By default, Bootstrap will style the HTML <pre> element in the following way:

Example

Text in a pre element
is displayed in a fixed-width
font, and it preserves
both      spaces and
line breaks.

More Typography Classes

The Bootstrap classes below can be added to style HTML elements further:

Class Description Example
.lead Makes a paragraph stand out Try it
.small Indicates smaller text (set to 85% of the size of the parent) Try it
.text-left Indicates left-aligned text Try it
.text-center Indicates center-aligned text Try it
.text-right Indicates right-aligned text Try it
.text-justify Indicates justified text Try it
.text-nowrap Indicates no wrap text Try it
.text-lowercase Indicates lowercased text Try it
.text-uppercase Indicates uppercased text Try it
.text-capitalize Indicates capitalized text Try it
.initialism Displays the text inside the <abbr> element in a slightly smaller font size Try it
.blockquote-reverse Indicates a blockquote with right-aligned content Try it
.list-unstyled Removes the default list-style and left margin on list items (works on both <ul> and <ol>). This class only applies to immediate children list items (to remove the default list-style from any nested lists, apply this class to any nested lists as well) Try it
.list-inline Places all list items on a single line Try it
.dl-horizontal Lines up the terms and descriptions in the <dl> element side-by-side. Starts off like default <dl>s, but when the browser window expands, it will line up side-by-side Try it
.pre-scrollable Makes a <pre> element scrollable Try it

Bootstrap Browser/Device Support

Bootstrap works best in the latest desktop and mobile browsers.

Older browsers might display different renderings (though fully functional) of certain elements/components.

Bootstrap supports the latest versions of the following browsers and platforms:

Chrome Firefox IE Opera Safari
Android YES YES Not available NO Not available
iOS YES Not available Not available NO YES
Mac OS X YES YES Not available YES YES
Windows YES YES YES* YES NO

* Bootstrap supports Internet Explorer 8 and higher.

Bootstrap Grid System

What is a Grid?

In graphic design, a grid is a structure made up of a series of vertical and horizontal lines used to structure content.

A grid is widely used to design layout and content structure in print design.

In web design, a grid is a very effective method to create a consistent layout rapidly and effectively using HTML and CSS.

Bootstrap Grid System

Bootstrap provides a responsive, mobile-first fluid 12-column grid system.

The responsive grid system appropriately scales up to 12 columns as the device or viewport size increases.

1 1 1 1 1 1 1 1 1 1 1 1
4 4 4
4 8
6 6
12

 

Mobile-first Strategy!
Keep in mind that Bootstrap 3 is mobile-first! The code for Bootstrap now starts by targeting smaller screens like mobile devices and tablets, and then “expands” components and grids for larger screens.

 

Mobile-First Strategy

  • Determine what is most important content
  • Design to smaller widths first
  • The CSS address mobile device first; then have media queries for tablets, desktops
  • Add elements as screen size increases

Grid System Rules

Some Bootstrap grid system rules:

  • Rows must be placed within a .container (fixed-width) or .container-fluid (full-width) for proper alignment and padding
  • Use rows to create horizontal groups of columns
  • Content should be placed within columns, and only columns may be immediate children of rows
  • Predefined classes like .row and .col-xs-4 are available for quickly making grid layouts
  • Columns create gutters (gaps between column content) via padding. That padding is offset in rows for the first and last column via negative margin on .rows
  • Grid columns are created by specifying the number of 12 available columns you wish to span. For example, three equal columns would use three .col-xs-4

Basic Structure of a Bootstrap Grid

The following is a basic structure of a Bootstrap grid:

<div class=”container”>
<div class=”row”>
<div class=”col-*-*”></div>
</div>
<div class=”row”>
<div class=”col-*-*”></div>
<div class=”col-*-*”></div>
<div class=”col-*-*”></div>
</div>
<div class=”row”>

</div>
</div>

So, to create the layout you want, create a container (a <div> element with class=”container”). Then create a row (a <div> element with class=”row”). Then, add the desired number of columns (tags with appropriate .col-*-* classes). Note that numbers in col-*-* should always add up to 12 for each row.

Grid Options

The following table summarizes how the Bootstrap grid system works across multiple devices:

Extra small devices
Phones (<768px)
Small devices
Tablets (>=768px)
Medium devices
Desktops (>=992px)
Large devices
Desktops (>=1200px)
Grid behaviour Horizontal at all times Collapsed to start, horizontal above breakpoints Collapsed to start, horizontal above breakpoints Collapsed to start, horizontal above breakpoints
Container width None (auto) 750px 970px 1170px
Class prefix .col-xs- .col-sm- .col-md- .col-lg-
Number of columns 12 12 12 12
Column width Auto ~62px ~81px ~97px
Gutter width 30px (15px on each side of a column) 30px (15px on each side of a column) 30px (15px on each side of a column) 30px (15px on each side of a column)
Nestable Yes Yes Yes Yes
Offsets Yes Yes Yes Yes
Column ordering Yes Yes Yes Yes

 

  • Bootstrap Grid Example: Stacked-to-horizontal

    We will use the .col-*-* grid classes to create a basic grid system that starts out stacked on mobiles and tablets (small devices), before becoming horizontal on desktop (medium and large) devices.

    The following example shows a simple “stacked-to-horizontal” two-column layout:

    Example: Stacked-to-horizontal

    <div class=“container”>
    <h1>Hello World!</h1>
    <div class=“row”>
    <div class=“col-sm-6″ style=“background-color:lavender;”>
    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt
    ut labore et dolore magna aliqua.</p>
    <p>Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
    commodo consequat.</p>
    </div>
    <div class=“col-sm-6″ style=“background-color:lavenderblush;”>
    <p>Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque
    laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi
    architecto beatae vitae dicta sunt explicabo.</p>
    </div>
    </div>
    </div>
    Tip: The numbers in the .col-sm- classes indicates how many columns the div should span (out of 12). So, .col-sm-1 spans 1 column, .col-sm-4 spans 4 columns, .col-sm-6 spans 6 columns, etc.

    Note: Make sure that the sum always adds up to 12!

    Tip: Turn any fixed-width grid layout into a full-width layout by changing the .container class to .container-fluid:

    Example: Fluid container

    <div class=“container-fluid”>
    <h1>Hello World!</h1>
    <div class=“row”>
    <div class=“col-sm-6″ style=“background-color:lavender;”>
    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt
    ut labore et dolore magna aliqua.</p>
    <p>Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
    commodo consequat.</p>
    </div>
    <div class=“col-sm-6″ style=“background-color:lavenderblush;”>
    <p>Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque
    laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi
    architecto beatae vitae dicta sunt explicabo.</p>
    </div>
    </div>
    </div>

    Bootstrap Grid Example: Small Devices

    Assume we have a simple layout with two columns. We want the columns to be split 25%/75% for small devices.

    Tip: Small devices are defined as having a screen width from 768 pixels to 991 pixels.

    For small devices we will use the .col-sm-* classes.

    We will add the following classes to our two columns:

    <div class=”col-sm-3″>….</div>
    <div class=”col-sm-9″>….</div>

    Now Bootstrap is going to say “at the small size, look for classes with -sm- in them and use those”.

    The following example will result in a 25%/75% split on small devices:

    Example

    <div class=“container-fluid”>
    <h1>Hello World!</h1>
    <div class=“row”>
    <div class=“col-sm-3″ style=“background-color:lavender;”>
    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt
    ut labore et dolore magna aliqua.</p>
    <p>Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
    commodo consequat.</p>
    </div>
    <div class=“col-sm-9″ style=“background-color:lavenderblush;”>
    <p>Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque
    laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi
    architecto beatae vitae dicta sunt explicabo.</p>
    </div>
    </div>
    </div>

    Bootstrap Grid Example: Medium Devices

    In the previous chapter, we presented a grid example with classes for small devices. We used two divs (columns) and we gave them a 25%/75% split:

    <div class=”col-sm-3″>….</div>
    <div class=”col-sm-9″>….</div>

    But on medium devices the design may be better as a 50%/50% split.

    Tip: Medium devices are defined as having a screen width from 992 pixels to 1199 pixels.

    For medium devices we will use the .col-md-* classes.

    Now we will add the column widths for medium devices:

    <div class=”col-sm-3 col-md-6″>….</div>
    <div class=”col-sm-9 col-md-6″>….</div>

    Now Bootstrap is going to say “at the small size, look at classes with -sm- in them and use those. At the medium size, look at classes with -md- in them and use those”.

    The following example will result in a 25%/75% split on small devices and a 50%/50% split on medium devices:

    Example

    <div class=“container-fluid”>
    <h1>Hello World!</h1>
    <div class=“row”>
    <div class=“col-sm-3 col-md-6″ style=“background-color:lavender;”>
    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor
    incididunt ut labore et dolore magna aliqua.</p>
    <p> Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip
    ex ea commodo consequat.</p>
    </div>
    <div class=“col-sm-9 col-md-6″ style=“background-color:lavenderblush;”>
    <p>Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium
    doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis
    et quasi architecto beatae vitae dicta sunt explicabo.</p>
    </div>
    </div>
    </div>

    Bootstrap Grid Example: Large Devices

    In the previous chapter, we presented a grid example with classes for small and medium devices. We used two divs (columns) and we gave them a 25%/75% split on small devices, and a 50%/50% split on medium devices:

    <div class=”col-sm-3 col-md-6″>….</div>
    <div class=”col-sm-9 col-md-6″>….</div>

    But on large devices the design may be better as a 33%/66% split.

    Tip: Large devices are defined as having a screen width from 1200 pixels and above.

    For large devices we will use the .col-lg-* classes.

    So now we will add the column widths for large devices:

    <div class=”col-sm-3 col-md-6 col-lg-4″>….</div>
    <div class=”col-sm-9 col-md-6 col-lg-8″>….</div>

    Now Bootstrap is going to say “at the small size, look at classes with -sm- in them and use those. At the medium size, look at classes with -md- in them and use those. At the large size, look at classes with the word -lg- in them and use those”.

    The following example will result in a 25%/75% split on small devices, a 50%/50% split on medium devices, and a 33%/66% split on large devices:

    Example

    <div class=“container-fluid”>
    <h1>Hello World!</h1>
    <div class=“row”>
    <div class=“col-sm-3 col-md-6 col-lg-4″ style=“background-color:lavender;”>
    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor
    incididunt ut labore et dolore magna aliqua.</p>
    <p> Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip
    ex ea commodo consequat.</p>
    </div>
    <div class=“col-sm-9 col-md-6 col-lg-8″ style=“background-color:lavenderblush;”>
    <p>Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium
    doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis
    et quasi architecto beatae vitae dicta sunt explicabo.</p>
    </div>
    </div>
    </div>

    Bootstrap Grid Examples

    Three Equal Columns

    The following example shows how to get a three equal-width columns starting at tablets and scaling to large desktops. On mobile phones, the columns will automatically stack:

    Example

    <div class=“row”>
    <div class=“col-sm-4″>.col-sm-4</div>
    <div class=“col-sm-4″>.col-sm-4</div>
    <div class=“col-sm-4″>.col-sm-4</div>
    </div>

    Three Unequal Columns

    The following example shows how to get a three various-width columns starting at tablets and scaling to large desktops:

    Example

    <div class=“row”>
    <div class=“col-sm-3″>.col-md-3</div>
    <div class=“col-sm-6″>.col-md-6</div>
    <div class=“col-sm-3″>.col-md-3</div>
    </div>

     

    Two Unequal Columns

    The following example shows how to get two various-width columns starting at tablets and scaling to large desktops:

    Example

    <div class=“row”>
    <div class=“col-sm-4″>.col-sm-4</div>
    <div class=“col-sm-8″>.col-sm-8</div>
    </div>

    Two Columns With Two Nested Columns

    The following example shows how to get two columns starting at tablets and scaling to large desktops, with another two columns (equal widths) within the larger column (at mobile phones, these columns and their nested columns will stack):

    Example

    <div class=“row”>
    <div class=“col-sm-8″>
    .col-sm-8
    <div class=“row”>
    <div class=“col-sm-6″>.col-sm-6</div>
    <div class=“col-sm-6″>.col-sm-6</div>
    </div>
    </div>
    <div class=“col-sm-4″>.col-sm-4</div>
    </div>

    Mixed: Mobile And Desktop

    The Bootstrap grid system has four classes: xs (phones), sm (tablets), md (desktops), and lg (larger desktops). These classes can be combinated to create more dynamic and flexible layouts.

    Tip: Each class scales up, so if you wish to set the same widths for xs and sm, you only need to specify xs.

    Example

    <div class=“row”>
    <div class=“col-xs-12 col-md-8″>.col-xs-12 .col-md-8</div>
    <div class=“col-xs-6 col-md-4″>.col-xs-6 .col-md-4</div>
    </div>
    <div class=“row”>
    <div class=“col-xs-6 col-md-4″>.col-xs-6 .col-md-4</div>
    <div class=“col-xs-6 col-md-4″>.col-xs-6 .col-md-4</div>
    <div class=“col-xs-6 col-md-4″>.col-xs-6 .col-md-4</div>
    </div>
    <div class=“row”>
    <div class=“col-xs-6″>.col-xs-6</div>
    <div class=“col-xs-6″>.col-xs-6</div>
    </div>
    Tip: Remember that grid columns should add up to twelve for a row. More than that, columns will stack no matter the viewport.

     

    Mixed: Mobile, Tablet And Desktop

    Example

    <div class=“row”>
    <div class=“col-xs-12 col-sm-6 col-lg-8″>.col-xs-12 .col-sm-6 .col-lg-8</div>
    <div class=“col-xs-6 col-lg-4″>.col-xs-6 .col-lg-4</div>
    </div>
    <div class=“row”>
    <div class=“col-xs-6 col-sm-4″>.col-xs-6 .col-sm-4</div>
    <div class=“col-xs-6 col-sm-4″>.col-xs-6 .col-sm-4</div>
    <div class=“col-xs-6 col-sm-4″>.col-xs-6 .col-sm-4</div>
    </div>

    Clear Floats

    Clear floats at specific breakpoints to prevent strange wrapping with uneven content:

    Example

    <div class=“row”>
    <div class=“col-xs-6 col-sm-3″>
    Column 1
    <br>
    Resize the browser window to see the effect.
    </div>
    <div class=“col-xs-6 col-sm-3″>Column 2</div>
    <!– Add clearfix for only the required viewport –>
    <div class=“clearfix visible-xs”></div>
    <div class=“col-xs-6 col-sm-3″>Column 3</div>
    <div class=“col-xs-6 col-sm-3″>Column 4</div>
    </div>

    Offsetting Columns

    Move columns to the right using .col-md-offset-* classes. These classes increase the left margin of a column by * columns. For example, .col-md-offset-2 moves .col-md-2 over two columns:

    Example

    <div class=“row”>

      <div class=“col-sm-5 col-md-6″>.col-sm-5 .col-md-6</div>
    <div class=“col-sm-5 col-sm-offset-2 col-md-6 col-md-offset-0″>
    .col-sm-5 .col-sm-offset-2 .col-md-6 .col-md-offset-0</div>
    </div>

    Push And Pull – Change Column Ordering

    Change the order of the grid columns with .col-md-push-* and .col-md-pull-* classes:

    Example

    <div class=“row”>
    <div class=“col-sm-4 col-sm-push-8″>.col-sm-4 .col-sm-push-8</div>
    <div class=“col-sm-8 col-sm-pull-4″>.col-sm-8 .col-sm-pull-4</div>
    </div>

    Bootstrap Form Layouts

    Bootstrap provides three types of form layouts:

    • Vertical form (this is default)
    • Horizontal form
    • Inline form

    Standard rules for all the three types of form layout:

    • Add role=”form” to the <form> element
    • Wrap labels and form controls in a <div> element with class=”form-group” (needed for optimum spacing)
    • Add class=”form-control” to all textual <input>, <textarea>, and <select> elements
    Tip: Individual form controls automatically receive some global styling with Bootstrap. All textual <input>, <textarea>, and <select> elements with class=”form-control” are set to width: 100%; by default.

    Bootstrap Vertical Form (default)

    The following example creates a vertical form with two input fields, one checkbox, and a submit button:

    Example

    <form role=“form”>
    <div class=“form-group”>
    <label for=“email”>Email address:</label>
    <input type=“email” class=“form-control” id=“email”>
    </div>
    <div class=“form-group”>
    <label for=“pwd”>Password:</label>
    <input type=“password” class=“form-control” id=“pwd”>
    </div>
    <div class=“checkbox”>
    <label><input type=“checkbox”> Remember me</label>
    </div>
    <button type=“submit” class=“btn btn-default”>Submit</button>
    </form>

    Bootstrap Inline Form

    In an inline form, all of the elements are inline, left-aligned, and the labels are alongside.

    Note: This only applies to forms within viewports that are at least 768px wide!

    Additional rule for creating an inline form:

    • Add class=”form-inline” to the <form> element

    The following example creates an inline form with two input fields, one checkbox, and a submit button:

    Example

    <form class=“form-inline” role=“form”>
    <div class=“form-group”>
    <label for=“email”>Email address:</label>
    <input type=“email” class=“form-control” id=“email”>
    </div>
    <div class=“form-group”>
    <label for=“pwd”>Password:</label>
    <input type=“password” class=“form-control” id=“pwd”>
    </div>
    <div class=“checkbox”>
    <label><input type=“checkbox”> Remember me</label>
    </div>
    <button type=“submit” class=“btn btn-default”>Submit</button>
    </form>

    Example

    <form class=“form-inline” role=“form”>

      <div class=“form-group”>
    <label class=“sr-only” for=“email”>Email address:</label>
    <input type=“email” class=“form-control” id=“email”>
    </div>
    <div class=“form-group”>
    <label class=“sr-only” for=“pwd”>Password:</label>
    <input type=“password” class=“form-control” id=“pwd”>
    </div>
    <div class=“checkbox”>
    <label><input type=“checkbox”> Remember me</label>
    </div>
    <button type=“submit” class=“btn btn-default”>Submit</button>
    </form>

    Bootstrap Horizontal Form

    A horizontal form stands apart from the other forms both in the amount of markup, and in the presentation of the form.

    Additional rules for creating a horizontal form:

    • Add class=”form-horizontal” to the <form> element
    • Add class=”control-label” to all the labels

    Tip: Use Bootstrap’s predefined grid classes to align labels and groups of form controls in a horizontal layout.

    The following example creates a horizontal form with two input fields, one checkbox, and a submit button:

    Example

    <form class=“form-horizontal” role=“form”>
    <div class=“form-group”>
    <label class=“control-label col-sm-2″ for=“email”>Email:</label>
    <div class=“col-sm-10″>
    <input type=“email” class=“form-control” id=“email” placeholder=“Enter email”>
    </div>
    </div>
    <div class=“form-group”>
    <label class=“control-label col-sm-2″ for=“pwd”>Password:</label>
    <div class=“col-sm-10″>
    <input type=“password” class=“form-control” id=“pwd” placeholder=“Enter password”>
    </div>
    </div>
    <div class=“form-group”>
    <div class=“col-sm-offset-2 col-sm-10″>
    <div class=“checkbox”>
    <label><input type=“checkbox”> Remember me</label>
    </div>
    </div>
    </div>
    <div class=“form-group”>
    <div class=“col-sm-offset-2 col-sm-10″>
    <button type=“submit” class=“btn btn-default”>Submit</button>
    </div>
    </div>
    </form>

    Bootstrap Form Inputs

    Supported Form Controls

    Bootstrap supports the following form controls:

    • input
    • textarea
    • checkbox
    • radio
    • select

    Bootstrap Input

    Bootstrap supports all the HTML5 input types: text, password, datetime, datetime-local, date, month, time, week, number, email, url, search, tel, and color.

    Note: Inputs will NOT be fully styled if their type is not properly declared!

    The following example contains two input elements; one of type text and one of type password:

    Example

    <div class=“form-group”>
    <label for=“usr”>Name:</label>
    <input type=“text” class=“form-control” id=“usr”>
    </div>
    <div class=“form-group”>
    <label for=“pwd”>Password:</label>
    <input type=“password” class=“form-control” id=“pwd”>
    </div>

    Bootstrap Textarea

    The following example contains a textarea:

    Example

    <div class=“form-group”>
    <label for=“comment”>Comment:</label>
    <textarea class=“form-control” rows=“5” id=“comment”></textarea>
    </div>

    Bootstrap Checkboxes

    Checkboxes are used if you want the user to select any number of options from a list of preset options.

    The following example contains three checkboxes. The last option is disabled:

    Example

    <div class=“checkbox”>
    <label><input type=“checkbox” value=“”>Option 1</label>
    </div>
    <div class=“checkbox”>
    <label><input type=“checkbox” value=“”>Option 2</label>
    </div>
    <div class=“checkbox disabled”>
    <label><input type=“checkbox” value=“” disabled>Option 3</label>
    </div>

    Example

    <label class=“checkbox-inline”><input type=“checkbox” value=“”>Option 1</label>
    <label class=“checkbox-inline”><input type=“checkbox” value=“”>Option 2</label>
    <label class=“checkbox-inline”><input type=“checkbox” value=“”>Option 3</label>

    Bootstrap Radio Buttons

    Radio buttons are used if you want to limit the user to just one selection from a list of preset options.

    The following example contains three radio buttons. The last option is disabled:

    Example

    <div class=“radio”>
    <label><input type=“radio” name=“optradio”>Option 1</label>
    </div>
    <div class=“radio”>
    <label><input type=“radio” name=“optradio”>Option 2</label>
    </div>
    <div class=“radio disabled”>
    <label><input type=“radio” name=“optradio” disabled>Option 3</label>
    </div>

    Example

    <label class=“radio-inline”><input type=“radio” name=“optradio”>Option 1</label>
    <label class=“radio-inline”><input type=“radio” name=“optradio”>Option 2</label>
    <label class=“radio-inline”><input type=“radio” name=“optradio”>Option 3</label>

    Bootstrap Select List

    Select lists are used if you want to allow the user to pick from multiple options.

    The following example contains a dropdown list (select list):

    Example

    <div class=“form-group”>
    <label for=“sel1″>Select list:</label>
    <select class=“form-control” id=“sel1″>
    <option>1</option>
    <option>2</option>
    <option>3</option>
    <option>4</option>
    </select>
    </div>

    Bootstrap Form Inputs (more)

     

    Static Control

    If you need to place plain text next to a form label within a horizontal form, use the .form-control-static class on a <p> element:

    Example

     <form class=“form-horizontal” role=“form”>
    <div class=“form-group”>
    <label class=“control-label col-sm-2″ for=“email”>Email:</label>
    <div class=“col-sm-10″>
    <p class=“form-control-static”>someone@example.com</p>
    </div>
    </div>
    </form>

    Bootstrap Form Control States

    • INPUT FOCUS: When an input receives focus, the outline of the input is removed and a box-shadow is applied
    • DISABLED INPUTS: If you need to disable an input, add the disabled attribute
    • DISABLED FIELDSETS: Add the disabled attribute to a <fieldset> to disable all the controls within
    • READONLY INPUTS: Add the readonly attribute to an input to prevent user input
    • VALIDATION STATES: Bootstrap includes validation styles for error, warning, and success messages. To use, add .has-warning, .has-error, or .has-success to the parent element
    • ICONS: You can add feedback icons with the .has-feedback class and the right icon
    • HIDDEN LABELS: Add the .sr-only class on the label for form controls with no visible label

    The following example demonstrates some of the form control states above in a Horizontal form:

    Example

    <form class=“form-horizontal” role=“form”>
    <div class=“form-group”>
    <label class=“col-sm-2 control-label”>Focused</label>
    <div class=“col-sm-10″>
    <input class=“form-control” id=“focusedInput” type=“text” value=“Click to focus”>
    </div>
    </div>
    <div class=“form-group”>
    <label for=“inputPassword” class=“col-sm-2 control-label”>Disabled</label>
    <div class=“col-sm-10″>
    <input class=“form-control” id=“disabledInput” type=“text” disabled>
    </div>
    </div>
    <fieldset disabled>
    <div class=“form-group”>
    <label for=“disabledTextInput” class=“col-sm-2 control-label”>Fieldset disabled</label>
    <div class=“col-sm-10″>
    <input type=“text” id=“disabledTextInput” class=“form-control”>
    </div>
    </div>
    <div class=“form-group”>
    <label for=“disabledSelect” class=“col-sm-2 control-label”></label>
    <div class=“col-sm-10″>
    <select id=“disabledSelect” class=“form-control”>
    <option>Disabled select</option>
    </select>
    </div>
    </div>
    </fieldset>
    <div class=“form-group has-success has-feedback”>
    <label class=“col-sm-2 control-label” for=“inputSuccess”>Input with success and icon</label>
    <div class=“col-sm-10″>
    <input type=“text” class=“form-control” id=“inputSuccess”>
    <span class=“glyphicon glyphicon-ok form-control-feedback”></span>
    </div>
    </div>
    <div class=“form-group has-warning has-feedback”>
    <label class=“col-sm-2 control-label” for=“inputWarning”>Input with warning and icon</label>
    <div class=“col-sm-10″>
    <input type=“text” class=“form-control” id=“inputWarning”>
    <span class=“glyphicon glyphicon-warning-sign form-control-feedback”></span>
    </div>
    </div>
    <div class=“form-group has-error has-feedback”>
    <label class=“col-sm-2 control-label” for=“inputError”>Input with error and icon</label>
    <div class=“col-sm-10″>
    <input type=“text” class=“form-control” id=“inputError”>
    <span class=“glyphicon glyphicon-remove form-control-feedback”></span>
    </div>
    </div>
    </form>

    And here is an example of some of the form control states in an Inline form:

    Example

    <form class=“form-inline” role=“form”>
    <div class=“form-group”>
    <label for=“focusedInput”>Focused</label>
    <input class=“form-control” id=“focusedInput” type=“text”>
    </div>
    <div class=“form-group”>
    <label for=“inputPassword”>Disabled</label>
    <input class=“form-control” id=“disabledInput” type=“text” disabled>
    </div>
    <div class=“form-group has-success has-feedback”>
    <label for=“inputSuccess2″>Input with success</label>
    <input type=“text” class=“form-control” id=“inputSuccess2″>
    <span class=“glyphicon glyphicon-ok form-control-feedback”></span>
    </div>
    <div class=“form-group has-warning has-feedback”>
    <label for=“inputWarning2″>Input with warning</label>
    <input type=“text” class=“form-control” id=“inputWarning2″>
    <span class=“glyphicon glyphicon-warning-sign form-control-feedback”></span>
    </div>
    <div class=“form-group has-error has-feedback”>
    <label for=“inputError2″>Input with error</label>
    <input type=“text” class=“form-control” id=“inputError2″>
    <span class=“glyphicon glyphicon-remove form-control-feedback”></span>
    </div>
    </form>

    Bootstrap Input Sizing

    Input Sizing in Forms

    Set the heights of input elements using classes like .input-lg and .input-sm.

    Set the widths of elements using grid column classes like .col-lg-*, .col-sm-*, and .col-xs-*.

    Height Sizing

    The following examples shows input elements with different heights:

    Example

    <form class=“form-inline” role=“form”>
    <div class=“form-group”>
    <label for=“inputdefault”>Default input</label>
    <input class=“form-control” id=“inputdefault” type=“text”>
    </div>
    <div class=“form-group”>
    <label for=“inputlg”>input-lg</label>
    <input class=“form-control input-lg” id=“inputlg” type=“text”>
    </div>
    <div class=“form-group”>
    <label for=“inputsm”>input-sm</label>
    <input class=“form-control input-sm” id=“inputsm” type=“text”>
    </div>
    </form>

    You can quickly size labels and form controls within a Horizontal form by adding .form-group-lg or .form-group-sm to the <div class=”form-group”> element:

    Example

    <form class=“form-horizontal” role=“form”>
    <div class=“form-group form-group-lg”>
    <label class=“col-sm-2 control-label” for=“lg”>form-group-lg</label>
    <div class=“col-sm-10″>
    <input class=“form-control” type=“text” id=“lg”>
    </div>
    </div>
    <div class=“form-group form-group-sm”>
    <label class=“col-sm-2 control-label” for=“sm”>form-group-sm</label>
    <div class=“col-sm-10″>
    <input class=“form-control” type=“text” id=“sm”>
    </div>
    </div>
    </form>

    Column Sizing

    The following examples shows input elements with different widths using different .col-xs-* classes:

    Example

    <div class=“col-xs-2″>
    <label for=“ex1″>col-xs-2</label>
    <input class=“form-control” id=“ex1″ type=“text”>
    </div>
    <div class=“col-xs-3″>
    <label for=“ex2″>col-xs-3</label>
    <input class=“form-control” id=“ex2″ type=“text”>
    </div>
    <div class=“col-xs-4″>
    <label for=“ex3″>col-xs-4</label>
    <input class=“form-control” id=“ex3″ type=“text”>
    </div>

    Example

    <div class=“form-group”>

      <label for=“pwd”>Password:</label>
    <input type=“password” class=“form-control” id=“pwd” placeholder=“Enter password”>
    <span class=“help-block”>This is some help text…</span>
    </div>

Rate: 0

Telegram Messenger Client auf dem Raspberry Tutorial

Telegram Messenger Client auf dem Raspberry Tutorial

Hallo Zusammen,

aus gegebenen Anlass suchen wohl einige nach einer Alternative für Whatsapp.
Bei mir ist es sogar so weit, dass ich gerne mit dem Smartphone umsteigen möchte.

In dem whatsapp diskussions thread wurde Telegram als Alternative genannt.
Das schöne an Telegram ist der Grundgedanke dahinter (Kostenlos, Sicher, Quelloffen, Schnell) siehe auch die Homepage von telegram.

Aus diesem Grund habe ich mir heute Mittag Telegram aufs Smartphone und den Raspberry gespielt und ein wenig getestet. Aktuell gibt es aufgrund der Serverprobleme bei Whatsapp einen riesigen Hype auf Telegram, weshalb auch deren Server aktuell etwas überlastet sind.

Dennoch hier eine kurze Anleitung, wie Ihr euch Telegram auf dem Raspberry einrichten könnt.
Alle Informationen stammen von der telegram und durchgeführten Tests.Installation und Einrichtung von Telegram

1. Installation der benötigten Pakete

sudo apt-get install libreadline-dev libconfig-dev libssl-dev lua5.2 liblua5.2-dev

2. Herunterladen des Telegram Clients

git clone https://github.com/vysheng/tg.git && cd tg

3. “Installation” des Telegram Clients

./configure

make

Anschließend ist die Installation soweit fertig und es geht an die Einrichtung eures Accounts.
Hierzu wird wie bei Whatsapp eine Handynummer benötigt.
Sobald Ihr ein Handy mit Sim-Karte zum Empfangen des Bestätigungscodes als SMS zur Hand habt, geht es mit den folgenden Schritten weiter.

4. Einrichtung des Accounts

./telegram -k tg.pub

Anschließend kommt ein Dialog, in dem mehrere Eingaben erforderlich sind.

  • Handynummer (im Format +491519876543)
  • Vorname
  • Nachname

Alle Eingaben müssen jeweils mit Enter bestätigt werden.
Daraufhin wird ein Bestätigungscode via SMS an die angegebene Handynummer gesendet.
Diesen Code anschließend noch im Dialog eingeben.

Wenn die Einrichtung erledigt ist, kann mit folgendem Befehl im Telegram Verzeichnis der Telegram Client gestartet werden

./telegram

Es gibt nun einige Befehle, um das Programm zu bedienen:

Supported commands

[b]Messaging[/b]
msg <peer> Text - sends message to this peerfwd <user> <msg-seqno> - forward message to user. You can see message numbers starting client with -Nchat_with_peer <peer> starts one on one chat session with this peer. /exit or /quit to end this mode.add_contact <phone-number> <first-name> <last-name> - tries to add contact to contact-list by phonerename_contact <user> <first-name> <last-name> - tries to rename contact. If you have another device it will be a fightmark_read <peer> - mark read all received messages with peer
[b]Multimedia[/b]
send_photo <peer> <photo-file-name> - sends photo to peersend_video <peer> <video-file-name> - sends video to peersend_text <peer> <text-file-name> - sends text file as plain messagesload_photo/load_video/load_video_thumb <msg-seqno> - loads photo/video to download dirview_photo/view_video/view_video_thumb <msg-seqno> - loads photo/video to download dir and starts system default viewer
[b]Group chat options[/b]
chat_info <chat> - prints info about chatchat_add_user <chat> <user> - add user to chatchat_del_user <chat> <user> - remove user from chatrename_chat <chat> <new-name>
[b]Search[/b]
search <peer> pattern - searches pattern in messages with peerglobal_search pattern - searches pattern in all messages
[b]Secret chat[/b]
create_secret_chat <user> - creates secret chat with this uservisualize_key <secret_chat> - prints visualization of encryption key. You should compare it to your partner's one
[b]Stats and various info[/b]
user_info <user> - prints info about userhistory <peer> [limit] - prints history (and marks it as read). Default limit = 40dialog_list - prints info about your dialogscontact_list - prints info about users in your contact listsuggested_contacts - print info about contacts, you have max common friendsstats - just for debuggingshow_license - prints contents of GPLv2help - prints this help

Hier noch ein Ausschnitt meiner ersten Tests.
Sehr schön zu sehen, dass immer angezeigt wird ob der Chatpartner Online oder Offline ist und die Nachricht gelesen wurde.

> msg Daniel_Zieg hallo
*** t = 2590284552850292994, len = 5
[10:45]  Daniel Zieg <<< hallo
Sent: id = 4
[10:45]  User Daniel Zieg is now online
[10:45]  1 messages marked as read
> msg Daniel_Zieg hallo
*** t = 1531682784180444713, len = 5
[10:45]  Daniel Zieg <<< hallo
Sent: id = 5
[10:45]  1 messages marked as read
[10:45]  User Daniel Zieg is now offline
[10:45]  User Daniel Zieg is now online
[10:45]  User Daniel Zieg is typing....
[10:45]  Updated link with user Daniel Zieg
[10:45]  Daniel Zieg >>> Hallo raspberry
[1 unread]
[1 unread]mark_read
Bad user/chat id
[1 unread]mark_read Daniel_Zieg
[10:46]  User Daniel Zieg is now offline
[10:47]  User Daniel Zieg is now online
[10:47]  User Daniel Zieg is now offline

Sehr erfreulich finde ich auch, wie einfach Bilder mit dem Client verschickt werden können:

> send_photo Daniel_Zieg /home/pi/ocr_pi.png

[10:50]  Daniel Zieg <<< [photo]
[10:50]  User Daniel Zieg is now online
[10:50]  1 messages marked as read
[10:50]  User Daniel Zieg is now offline

Zum Thema API um das ganze in eigene Skripte einzubauen, bin ich bisher nicht weiter gekommen.
In einer Datei im Telegram Verzeichnis namens “test.lua” gibt es einen Teil “onMessageReceive”.
Ich denke, es sollte auch hier so etwas wie der ListenerClient von Yowsup (Whatsapp) möglich sein, um auf eingehende Nachrichten automatisch zu reagieren.

Gerne kann in diesem Thread das Tutorial auch von euch erweitert werden, gerade was die APIs angeht.
Informationen hierzu findet man auf der telegram seite  API.

Rate: 0