Showing posts with label Android. Show all posts
Showing posts with label Android. Show all posts

Tuesday, March 28, 2017

Android WeChat Login Integration

Android WeChat Login:

To integrate Wechat in your Android Application.you need 3 things:

1)AppId
2)Package Name
3)SH1 :Generated using the same Package Name

Like any 3rd party integration there is  a console of WeChat.you can go there generate the App Id by providing very simple information to their console.The app Id is important as it's how WeChat identifies the application requesting authorization.

There are many things which you should take care.

1)The package name of your application must be same whatever you have given in the WeChat console.
2)Generate the SH1 using the same package name.

I couldn't find a gradle import for the WeChat SDK. Their official site gives instructions on how to import their SDK into the libs folder of your application.

http://dev.wechat.com/wechatapi/installguide


Note:Follow these steps line by line .Do not miss anything:

Pitfalls


  • WeChat seems to break if your package name differs from your applicationId. This is probably due to the reflection used by WeChat to respond to your request. If your package name differs from what's set in WeChat, you'll transition to WeChat when an auth attempt is made but you'll never get a response. If your applicationID differs from what's in WeChat, nothing at all will happen when you request an authorization. Basically you must not use applicationId.

  • Package name can be mixed case but what's saved in WeChat must exactly match what's in your application.

  • The Signature hash should only be alpha numeric. Do no include other symbols like ":"
  • You must have a validated WeChat app on the device (use a real phone).

  • You must use the proper project structure. If your package name is com.test.app, you must place your activity for handling WeChat responses at com.test.app.wxapi.WXEntryActivity.

  • You must register before attempting to get a token.

  • Be careful with minified code (Proguard). There are articles online that mention minified code can mess up WeChat communication.

  • You must export your WXEntryActivity in your manifest.

Once everything is lined up, there is very little code needed to generate a token. However if anything is incorrect, you will likely never see any transition to WeChat, a failure to load WeChat if a transition occurs, or no response from WeChat after you give your application access.


Sample Code:

Let say you a WeChat Button then on the click of that button just open this Activity:


public String WE_CHAT_APP_ID = "wxg4c3e70195c29k17";//you put your app id here.you will get something
like this



public class WeChatSendRequestActivity extends Activity {

    Button test;
    private IWXAPI api;

    @Override protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.test);
        api = WXAPIFactory.createWXAPI(this, AppConstants.WE_CHAT_APP_ID,true);
        api.registerApp(AppConstants.WE_CHAT_APP_ID);
        final SendAuth.Req req = new SendAuth.Req();
        req.scope = "snsapi_userinfo";
        req.state = "none";
        api.sendReq(req);
        finish();

    }
}

test.xml:

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"              android:orientation="vertical"              android:layout_width="match_parent"              android:layout_height="match_parent">


</LinearLayout>



Another Activity provided by Wechat Sdk then call back would come here:


package com.pack.package.wxapi;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import com.pack.package.R;
import com.pack.package.util.apputil.AppConstants;
import com.pack.package.util.apputil.AppSharedPreference;
import com.tencent.mm.opensdk.constants.ConstantsAPI;
import com.tencent.mm.opensdk.modelbase.BaseReq;
import com.tencent.mm.opensdk.modelbase.BaseResp;
import com.tencent.mm.opensdk.modelmsg.SendAuth;
import com.tencent.mm.opensdk.modelmsg.ShowMessageFromWX;
import com.tencent.mm.opensdk.modelmsg.WXAppExtendObject;
import com.tencent.mm.opensdk.modelmsg.WXMediaMessage;
import com.tencent.mm.opensdk.openapi.IWXAPI;
import com.tencent.mm.opensdk.openapi.IWXAPIEventHandler;
import com.tencent.mm.opensdk.openapi.WXAPIFactory;

public class WXEntryActivity extends Activity implements IWXAPIEventHandler{
   
   private static final int TIMELINE_SUPPORTED_VERSION = 0x21020001;
   
   private Button gotoBtn, regBtn, launchBtn, checkBtn, scanBtn;
   
   // IWXAPI ǵ�����app��΢��ͨŵopenapiӿ    private IWXAPI api;
   
    @Override    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.frag_login);
        
        // ͨ��WXAPIFactory��������ȡIWXAPI��ʵ��       api = WXAPIFactory.createWXAPI(this, AppConstants.WE_CHAT_APP_ID, true);
      try {
           api.handleIntent(getIntent(), this);
        } catch (Exception e) {
           e.printStackTrace();
        }
    }

   @Override   protected void onNewIntent(Intent intent) {
      super.onNewIntent(intent);
      
      setIntent(intent);
        api.handleIntent(intent, this);
   }

   @Override   public void onReq(BaseReq req) {
      switch (req.getType()) {
      case ConstantsAPI.COMMAND_GETMESSAGE_FROM_WX:
         goToGetMsg();     
         break;
      case ConstantsAPI.COMMAND_SHOWMESSAGE_FROM_WX:
         goToShowMsg((ShowMessageFromWX.Req) req);
         break;
      default:
         break;
      }
   }


   @Override   public void onResp(BaseResp resp) {
      int result = 0;

      SendAuth.Resp response = (SendAuth.Resp) resp;
      Log.V("Access Token::"+response.code);

      //Toast.makeText(this, "baseresp.getType = " + resp.openId, Toast.LENGTH_SHORT).show();            switch (resp.errCode) {
      case BaseResp.ErrCode.ERR_OK:
         result = R.string.errcode_success;
         break;
      case BaseResp.ErrCode.ERR_USER_CANCEL:
         result = R.string.errcode_cancel;
         break;
      case BaseResp.ErrCode.ERR_AUTH_DENIED:
         result = R.string.errcode_deny;
         break;
      case BaseResp.ErrCode.ERR_UNSUPPORT:
         result = R.string.errcode_unsupported;
         break;
      default:
         result = R.string.errcode_unknown;
         break;
      }
      

      finish();
   }
   
   private void goToGetMsg() {
      /*Intent intent = new Intent(this, GetFromWXActivity.class);      intent.putExtras(getIntent());      startActivity(intent);      finish();*/   }
   
   private void goToShowMsg(ShowMessageFromWX.Req showReq) {
   /* WXMediaMessage wxMsg = showReq.message;      WXAppExtendObject obj = (WXAppExtendObject) wxMsg.mediaObject;            StringBuffer msg = new StringBuffer(); // ��֯һ������ʾ����Ϣ����
      msg.append("description: ");      msg.append(wxMsg.description);      msg.append("\n");      msg.append("extInfo: ");      msg.append(obj.extInfo);      msg.append("\n");      msg.append("filePath: ");      msg.append(obj.filePath);            Intent intent = new Intent(this, ShowFromWXActivity.class);      intent.putExtra(Constants.ShowMsgActivity.STitle, wxMsg.title);      intent.putExtra(Constants.ShowMsgActivity.SMessage, msg.toString());      intent.putExtra(Constants.ShowMsgActivity.BAThumbData, wxMsg.thumbData);      startActivity(intent);      finish();*/   }
}



add these in your manifest:


<receiver    android:name=".util.socialutil.wechat.AppRegister"    android:permission="com.tencent.mm.plugin.permission.SEND" >
    <intent-filter>
        <action android:name="com.tencent.mm.plugin.openapi.Intent.ACTION_REFRESH_WXAPP" />
    </intent-filter>
</receiver>

<activity    android:name="com.pack.package.wxapi.WXEntryActivity"    android:label="@string/app_name"    android:exported="true"    android:launchMode="singleTop">
    <!--   <intent-filter>            <action android:name="android.intent.action.MAIN" />            <category android:name="android.intent.category.LAUNCHER" />        </intent-filter>-->
        <intent-filter>
            <action android:name="android.intent.action.VIEW"/>
            <category android:name="android.intent.category.DEFAULT"/>
            <data android:scheme="sdksample"/>
        </intent-filter>
</activity>

<activity    android:name="com.pack.package.util.socialutil.wechat.WeChatSendRequestActivity"    android:label="@string/app_name"    >


in second activity you will get the response(Access Token ) in switch case and you can get anything
from that access token like other access token such as facebook,google,twitter etc.

Tuesday, September 13, 2016

Android TV App Building Concept

Building TV Apps

Android offers a rich user experience that's optimized for apps running on large screen devices, such as high-definition televisions. Apps on TV offer new opportunities to delight your users from the comfort of their couch.


  • TV apps use the same structure as those for phones and tablets.
  • This approach means you can create new TV apps based on what you already know about building apps for Android, or extend your existing apps to also run on TV devices. 
  • However, the user interaction model for TV is substantially different from phone and tablet devices. In order to make your app successful on TV devices, you must design new layouts that can be easily understood from 10 feet away, and provide navigation that works with just a directional pad and a select button.

There are few points you can note while TV app development such as
  1. Handling TV Hardware
  2. Building TV Layouts
  3. Creating TV Navigation
Each of them plays a very vital role in Android Tv app development.Lets see how they
impact on the development but before that you must have understanding about few things
such as

1)Supported Media Formats
2)DRM
3)android.drm
4)ExoPlayer
5)android.media.MediaPlayer

And Android TV app uses lean back support.

1)Declare Leanback support for TV:

Declare that your app uses the Leanback user interface required by Android TV. If you are developing an app that runs on mobile (phones, wearables, tablets, etc.) as well as Android TV, set the required attribute value to false. If you set the required attribute value to true, your app will run only on devices that use the Leanback UI.

<manifest>
    <uses-feature android:name="android.software.leanback"
        android:required="false" />
</manifest>

So there are few things also which are not required at TV app development.

2)Declare touchscreen not required:

Applications that are intended to run on TV devices do not rely on touch screens for input. In order to make this clear, the manifest of your TV app must declare that a the android.hardware.touchscreen feature is not required. This setting identifies your app as being able to work on a TV device, and is required for your app to be considered a TV app in Google Play. The following code example shows how to include this manifest declaration:

<manifest>
    <uses-feature android:name="android.hardware.touchscreen"
              android:required="false" />
</manifest>

3)Provide a home screen banner:

An application must provide a home screen banner image for each localization if it includes a Leanback launcher intent filter. The banner is the app launch point that appears on the home screen in the apps and games rows. When designing your banner, follow the design requirements described in Banners. To add the banner to your app, describe the banner in the manifest as follows:

<application
    android:banner="@drawable/banner" >
</application>

4)Add TV Support Libraries:

The Android SDK includes support libraries that are intended for use with TV apps. These libraries provide APIs and user interface widgets for use on TV devices. The libraries are located in the <sdk>/extras/android/support/ directory. Here is a list of the libraries and their general purpose:

a)v17 leanback library - Provides user interface widgets for TV apps, particularly for apps that do media playback.

b)v7 recyclerview library - Provides classes for managing display of long lists in a memory efficient manner. Several classes in the v17 leanback library depend on the classes in this library.

c)v7 cardview library - Provides user interface widgets for displaying information cards, such as media item pictures and descriptions.
Note: You are not required to use these support libraries for your TV app. However, we strongly recommend using them, particularly for apps that provide a media catalog browsing interface.

If you decide to use the v17 leanback library for your app, you should note that it is dependent on the v4 support library. This means that apps that use the leanback support library should include all of these support libraries:

v4 support library
v7 recyclerview support library
v17 leanback support library
The v17 leanback library contains resources, which require you to take specific steps to include it in app projects. For instructions on importing a support library with resources, see Support Library Setup.


5)Declaring hardware requirements for TV:

<uses-feature android:name="android.hardware.touchscreen"
        android:required="false"/>
<uses-feature android:name="android.hardware.faketouch"
        android:required="false"/>
<uses-feature android:name="android.hardware.telephony"
        android:required="false"/>
<uses-feature android:name="android.hardware.camera"
        android:required="false"/>
<uses-feature android:name="android.hardware.nfc"
        android:required="false"/>
<uses-feature android:name="android.hardware.location.gps"
        android:required="false"/>
<uses-feature android:name="android.hardware.microphone"
        android:required="false"/>
<uses-feature android:name="android.hardware.sensor"
        android:required="false"/>

Android apps can declare hardware feature requirements in the app manifest to ensure that they do not get installed on devices that do not provide those features. If you are extending an existing app for use on TV, closely review your app's manifest for any hardware requirement declarations that might prevent it from being installed on a TV device.

If your app uses hardware features (such as a touchscreen or camera) that are not available on TV, but can operate without the use of those features, modify your app's manifest to indicate that these features are not required by your app. The following manifest code snippet demonstrates how to declare that your app does not require hardware features which are unavailable on TV devices.

So, These are few things which are basic requirement for Android TV App Development and must
be taken care while Android TV app Development. Now,So if we can not use touch screen and so how we will navigate within the Application.Will tell you in next tutorial.



Monday, September 12, 2016

Android Request Run-Time Permission Example

Although Android is being keep developed but the latest update to Android M is totally different since there is some major change that would change everything like new Run-time Permission. Surprisingly it is not much talked about in Android Developer community even though it is extremely important and may cause some big trouble in the near future.

The New Runtime Permission
Android's permission system is one of the biggest security concern all along since those permissions are asked for at install time. Once installed, the application will be able to access all of things granted without any user's acknowledgement what exactly application does with the permission.

No surprise why there are so many bad guys trying to collect user's personal data through this security weakness and use it in the bad way.

Android team also know this concern. 7 year passed, finally permission system is redesigned. In Android 6.0 Marshmallow, application will not be granted any permission at installation time. Instead, application has to ask user for a permission one-by-one at runtime.

Note: Please note that permission request dialog shown above will not launch automatically. Developer has to call for it manually. In the case that developer try to call some function that requires a permission which user has not granted yet, the function will suddenly throw an Exception which will lead to the application crashing.

What happened to the application that has already been launched?
This new permission system may cause you some panic right now. "Hey ! What's about my application that launched 3 years ago. If it is installed on Android 6.0 device, does this behavior also applied? Will my application also crash?!?"

Don't worry. Android team has already thought about it. If the application's targetSdkVersion is set to less than 23. It will be assumed that application is not tested with new permission system yet and will switch to the same old behavior: user has to accept every single permission at install time and they will be all granted once installed !

As a result, application will run perfectly like previous. Anyway please note that user still can revoke a permission after that ! Although Android 6.0 warn the user when they try to do that but they can revoke anyway.

Very Simple Code Solution:

Manifest.xml: 


<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.myandrioid.abhinaw">
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    <application 
       android:allowBackup="true" 
       android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name" 
       android:supportsRtl="true"  
      android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>



MainActivity.java :

package com.myandrioid.abhinaw;
import android.Manifest;
import android.content.ContentValues;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.net.Uri;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity
{
    private Button buttonRequestPermission;
    private int STORAGE_PERMISSION_CODE = 23;

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

    private  void requestPermisssion()
    {
        buttonRequestPermission = (Button) findViewById(R.id.buttonRequestPermission);
        buttonRequestPermission.setOnClickListener(new View.OnClickListener()
        {
            @Override            public void onClick(View v)
            {
                if(isReadStorageAllowed())
                {
                    Toast.makeText(MainActivity.this,"You already have the permission",Toast.LENGTH_LONG).show();
                    return;
                }
                requestStoragePermission();
            }
        });
    }

    private boolean isReadStorageAllowed()
    {
        int result = ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE);
        if (result == PackageManager.PERMISSION_GRANTED)
            return true;
        return false;
    }

    private void requestStoragePermission()
    {
        if (ActivityCompat.shouldShowRequestPermissionRationale(this,Manifest.permission.READ_EXTERNAL_STORAGE))
        {
           // do nothing
        }
        ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},STORAGE_PERMISSION_CODE);
    }

    @Override    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults)
    {
        if(requestCode == STORAGE_PERMISSION_CODE)
        {
            if(grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED)
            {
                Toast.makeText(this,"Permission granted now you can read the storage",Toast.LENGTH_LONG).show();
            }
            else            {
                Toast.makeText(this,"Oops you just denied the permission",Toast.LENGTH_LONG).show();
            }
        }
    }
}

activity_main.xml :

<Button  
  android:layout_width="match_parent" 
   android:layout_height="wrap_content" 
   android:text="Request Storage Permission"  
  android:id="@+id/buttonRequestPermission"  
  android:layout_centerVertical="true"  
  android:layout_below="@+id/button" />

Result: 


Image





Friday, September 9, 2016

Android Content Provider Tutorial


A content provider manages a shared set of app data. You can store the data in the file system, an SQLite database, on the web, or any other persistent storage location your app can access. Through the content provider, other apps can query or even modify the data (if the content provider allows it).

For example, the Android system provides a content provider that manages the user's contact information. As such, any app with the proper permissions can query part of the content provider (such as ContactsContract.Data) to read and write information about a particular person.

A content provider component supplies data from one application to others on request. Such requests are handled by the methods of the ContentResolver class. A content provider can use different ways to store its data and the data can be stored in a database, in files, or even over a network.
sometimes it is required to share data across applications. This is where content providers become very useful.

Content providers let you centralize content in one place and have many different applications access it as needed. A content provider behaves very much like a database where you can query it, edit its content, as well as add or delete content using insert(), update(), delete(), and query() methods. In most cases this data is stored in an SQlite database.


Image


A content provider is implemented as a subclass of ContentProvider class and must implement a standard set of APIs that enable other applications to perform transactions.

How to Create Content Provider:

This involves number of simple steps to create your own content provider.
First of all you need to create a Content Provider class that extends the ContentProviderbaseclass.
Second, you need to define your content provider URI address which will be used to access the content.

Next you will need to create your own database to keep the content. Usually, Android uses SQLite database and framework needs to override onCreate() method which will use SQLite Open Helper method to create or open the provider's database. When your application is launched, the onCreate() handler of each of its Content Providers is called on the main application thread.

Next you will have to implement Content Provider queries to perform different database specific operations.

Finally register your Content Provider in your activity file using <provider> tag.

CONTENT PROVIDER Call Backs:

onCreate() This method is called when the provider is started.

query() This method receives a request from a client. The result is returned as a Cursor object.

insert()This method inserts a new record into the content provider.

delete() This method deletes an existing record from the content provider.

update() This method updates an existing record from the content provider.

getType() This method returns the MIME type of the data at the given URI.

Image
Let me provide a simple application where you can add records and retrieve records.

MainActivity.java :

import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast; 
 
public class MainActivity extends AppCompatActivity


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


public void onClickAddName(View view) {
ContentValues values = new ContentValues();

values.put(StudentsProvider.NAME, ((EditText)findViewById(R.id.editText2)).getText().toString());
values.put(StudentsProvider.GRADE, ((EditText)findViewById(R.id.editText3)).getText().toString());

Uri uri = getContentResolver().insert(StudentsProvider.CONTENT_URI, values);
Toast.makeText(getBaseContext(), uri.toString(), Toast.LENGTH_LONG).show(); }

public void onClickRetrieveStudents(View view) {

// Retrieve student records String URL = "content://com.myandrioid.provider.College/students";
Uri students = Uri.parse(URL);
Cursor c = managedQuery(students, null, null, null, "name");
if (c.moveToFirst()) {
do {
Toast.makeText(this,
c.getString(c.getColumnIndex(StudentsProvider._ID)) +

", " + c.getString(c.getColumnIndex( StudentsProvider.NAME)) +

", " + c.getString(c.getColumnIndex( StudentsProvider.GRADE)),

Toast.LENGTH_SHORT).show();

}
while (c.moveToNext());

} }

}

activity_main.xml:

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


<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"


xmlns:tools="http://schemas.android.com/tools"


android:layout_width="match_parent"


android:layout_height="match_parent"


android:paddingBottom="@dimen/activity_vertical_margin"


android:paddingLeft="@dimen/activity_horizontal_margin"


android:paddingRight="@dimen/activity_horizontal_margin"


android:paddingTop="@dimen/activity_vertical_margin"


tools:context="com.myandrioid.abhinaw.MainActivity">



<TextView


android:id="@+id/textView1"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="Content provider"

android:layout_alignParentTop="true"

android:layout_centerHorizontal="true"

android:textSize="30dp" />


<TextView

android:id="@+id/textView2"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="Abhinaw Tutorial "

android:textColor="#ff87ff09"

android:textSize="30dp"

android:layout_below="@+id/textView1"

android:layout_centerHorizontal="true" />


<ImageButton

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:id="@+id/imageButton"

android:src="@mipmap/ic_launcher"

android:layout_below="@+id/textView2"

android:layout_centerHorizontal="true" />


<Button

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:id="@+id/button2"

android:text="Add Name"

android:layout_below="@+id/editText3"

android:layout_alignRight="@+id/textView2"

android:layout_alignEnd="@+id/textView2"

android:layout_alignLeft="@+id/textView2"

android:layout_alignStart="@+id/textView2"

android:onClick="onClickAddName"/>


<EditText

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:id="@+id/editText"

android:layout_below="@+id/imageButton"

android:layout_alignRight="@+id/imageButton"

android:layout_alignEnd="@+id/imageButton" />

<EditText

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:id="@+id/editText2"

android:layout_alignTop="@+id/editText"

android:layout_alignLeft="@+id/textView1"

android:layout_alignStart="@+id/textView1"

android:layout_alignRight="@+id/textView1"

android:layout_alignEnd="@+id/textView1"

android:hint="Name"

android:textColorHint="@android:color/holo_blue_light" />

<EditText

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:id="@+id/editText3"

android:layout_below="@+id/editText"

android:layout_alignLeft="@+id/editText2"

android:layout_alignStart="@+id/editText2"

android:layout_alignRight="@+id/editText2"

android:layout_alignEnd="@+id/editText2"

android:hint="Grade"

android:textColorHint="@android:color/holo_blue_bright" />

<Button

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="Retrive student"

android:id="@+id/button"

android:layout_below="@+id/button2"

android:layout_alignRight="@+id/editText3"

android:layout_alignEnd="@+id/editText3"

android:layout_alignLeft="@+id/button2"

android:layout_alignStart="@+id/button2"

android:onClick="onClickRetrieveStudents"/>

</RelativeLayout>

StudentsProvider.java :


import java.util.HashMap;

import android.content.ContentProvider;

import android.content.ContentUris;

import android.content.ContentValues;

import android.content.Context;

import android.content.UriMatcher;

import android.database.Cursor;

import android.database.SQLException;

import android.database.sqlite.SQLiteDatabase;

import android.database.sqlite.SQLiteOpenHelper;

import android.database.sqlite.SQLiteQueryBuilder;

import android.net.Uri;


import android.text.TextUtils;
public class StudentsProvider extends ContentProvider


static final String PROVIDER_NAME = "com.myandrioid.provider.College"; {
static final String URL = "content://" + PROVIDER_NAME + "/students";


static final Uri CONTENT_URI = Uri.parse(URL);


static final String _ID = "_id";


static final String NAME = "name";


static final String GRADE = "grade";


private static HashMap<String, String> STUDENTS_PROJECTION_MAP;


static final int STUDENTS = 1;


static final int STUDENT_ID = 2;


static final UriMatcher uriMatcher;


static {


uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);


uriMatcher.addURI(PROVIDER_NAME, "students", STUDENTS);


uriMatcher.addURI(PROVIDER_NAME, "students/#", STUDENT_ID);


}


/** * Database specific constant declarations */ private SQLiteDatabase db;


static final String DATABASE_NAME = "College";


static final String STUDENTS_TABLE_NAME = "students";


static final int DATABASE_VERSION = 1;


static final String CREATE_DB_TABLE =


" CREATE TABLE " + STUDENTS_TABLE_NAME +


" (_id INTEGER PRIMARY KEY AUTOINCREMENT, " +


" name TEXT NOT NULL, " +


" grade TEXT NOT NULL);";


/** * Helper class that actually creates and manages * the provider's underlying data repository. */ private static class DatabaseHelper extends SQLiteOpenHelper {


DatabaseHelper(Context context){


super(context, DATABASE_NAME, null, DATABASE_VERSION);


}


@Override public void onCreate(SQLiteDatabase db) {


db.execSQL(CREATE_DB_TABLE);


}


@Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {


db.execSQL("DROP TABLE IF EXISTS " + STUDENTS_TABLE_NAME);


onCreate(db); } }


@Override public boolean onCreate() {


Context context = getContext();


DatabaseHelper dbHelper = new DatabaseHelper(context);


/** * Create a write able database which will trigger its * creation if it doesn't already exist. */ db = dbHelper.getWritableDatabase();


return (db == null)? false:true;


}


@Override public Uri insert(Uri uri, ContentValues values) {


/** * Add a new student record */ long rowID = db.insert( STUDENTS_TABLE_NAME, "", values);


/** * If record is added successfully */


if (rowID > 0)


{


Uri _uri = ContentUris.withAppendedId(CONTENT_URI, rowID);


getContext().getContentResolver().notifyChange(_uri, null);


return _uri;


}


throw new SQLException("Failed to add a record into " + uri); }


@Override public Cursor query(Uri uri, String[] projection, String selection,String[] selectionArgs, String sortOrder) {


SQLiteQueryBuilder qb = new SQLiteQueryBuilder();


qb.setTables(STUDENTS_TABLE_NAME);


switch (uriMatcher.match(uri)) {


case STUDENTS:


qb.setProjectionMap(STUDENTS_PROJECTION_MAP);


break;


case STUDENT_ID:


qb.appendWhere( _ID + "=" + uri.getPathSegments().get(1));


break;


default:


throw new IllegalArgumentException("Unknown URI " + uri);


}


if (sortOrder == null || sortOrder == "")


{


/** * By default sort on student names */ sortOrder = NAME;


}


Cursor c = qb.query(db, projection, selection, selectionArgs,null, null, sortOrder);


/** * register to watch a content URI for changes */ c.setNotificationUri(getContext().getContentResolver(), uri);


return c;


}


@Override public int delete(Uri uri, String selection, String[] selectionArgs) {


int count = 0;


switch (uriMatcher.match(uri)) {


case STUDENTS:


count = db.delete(STUDENTS_TABLE_NAME, selection, selectionArgs);


break;


case STUDENT_ID:


String id = uri.getPathSegments().get(1);


count = db.delete( STUDENTS_TABLE_NAME, _ID + " = " + id +


(!TextUtils.isEmpty(selection) ? " AND (" + selection + ')' : ""), selectionArgs);


break;


default:


throw new IllegalArgumentException("Unknown URI " + uri);


}


getContext().getContentResolver().notifyChange(uri, null);


return count; }


@Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {


int count = 0;


switch (uriMatcher.match(uri)){


case STUDENTS:


count = db.update(STUDENTS_TABLE_NAME, values, selection, selectionArgs);


break;


case STUDENT_ID:


count = db.update(STUDENTS_TABLE_NAME, values, _ID + " = " + uri.getPathSegments().get(1) +


(!TextUtils.isEmpty(selection) ? " AND (" +selection + ')' : ""), selectionArgs);


break;


default:


throw new IllegalArgumentException("Unknown URI " + uri );


}


getContext().getContentResolver().notifyChange(uri, null);


return count; }


@Override public String getType(Uri uri) {


switch (uriMatcher.match(uri)) {


/** * Get all student records */


case STUDENTS:


return "vnd.android.cursor.dir/vnd.example.students";


/** * Get a particular student */


case STUDENT_ID:


return "vnd.android.cursor.item/vnd.example.students";


default:


throw new IllegalArgumentException("Unsupported URI: " + uri);


} }


}


manifests.xml :

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


<manifest xmlns:android="http://schemas.android.com/apk/res/android"

package="com.myandrioid.abhinaw">

<application

android:allowBackup="true"

android:icon="@mipmap/ic_launcher"

android:label="@string/app_name"

android:supportsRtl="true"

android:theme="@style/AppTheme">

<activity android:name=".MainActivity">

<intent-filter>

<action android:name="android.intent.action.MAIN" />

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

</intent-filter>

</activity>

<provider android:authorities="com.myandrioid.provider.College"

android:name=".StudentsProvider">

</provider>

</application>

</manifest>

Run and compile the code and you can able to perform the operation like add and retrieve
using content-provider and sqlite database.
So conclusion is,
Content providers are one of the primary building blocks of Android applications,
providing content to applications. They encapsulate data and provide it to applications
through the single ContentResolver interface. A content provider is only required if you
need to share data between multiple applications.


Android Application Best Practice for Performance and its Myths

Best Practices for Performance -

When anybody say you .how  can you code for best performance .we should understand and keep few things in the mind such as

1)Managing App's Memory
2)Performance Tips
3)Layout Improvement
4)Battery Life Optimization
5)Use of Multi-Threading

Each one of them itself very vast topics and very well explained on the Android Developer sites but i would like to add or you can say bring attention of Android App Developer on few topics before you going to develop any app small,large does not matter.

For example, Lets say you have an edit box and whatever you type there will be send to the server over the network.i know all of you can do this.very basic post operation on Android using HTTP connection but if i say the internet connection is very slow or very frequently it breaks.So in that case how would you make sure your app will be always responsive and will give best performance even in slow or breaking network.

So, what we need to do is, get the data insert it in preference if primitive type data or insert it in local database if Object or JSON Data and from there get data or query data and send it to the server in background So that your app will responsive always and will sync data whenever it comes in network i mean to say it will work in offline and online mode .you dont have to worry about it.

Likewise you can keep several things in the mind while developing android app.There are basically only two rules :

1)Don't do work that you don't need to do
2)Don't allocate memory if you can avoid it

So basically you should avoid creating unnecessary objects when you can avoid it because it will be  an expensive task for you.As you allocate more objects in your app, you will force a periodic garbage collection, creating little "hiccups" in the user experience.Thus, you should avoid creating object instances you don't need to.

for example: 

1)If you have a method returning a string, and you know that its result will always be appended to a StringBuffer anyway, change your signature and implementation so that the function does the append directly, instead of creating a short-lived temporary object.

2)When extracting strings from a set of input data, try to return a sub-string of the original data, instead of creating a copy.

3)An array of ints is a much better than an array of Integer objects, but this also generalizes to the fact that two parallel arrays of ints are also a lot more efficient than an array of (int,int) objects. The same goes for any combination of primitive types.

4)Prefer Static Over Virtual -- If you don't need to access an object's fields, make your method static. Invocations will be about 15%-20% faster. It's also good practice, because you can tell from the method signature that calling the method can't alter the object's state.

5)Avoid Internal Getters/Setters--it's common practice to use getters (i = getCount()) instead of accessing the field directly (i = mCount). is often practiced in object oriented languages .because the compiler can usually inline the access, and if you need to restrict or debug field access you can add the code at any time.However, this is a bad idea on Android.Without a JIT, direct field access is about 3x faster than invoking a trivial getter. With the JIT (where direct field access is as cheap as accessing a local), direct field access is about 7x faster than invoking a trivial getter.

6)Avoid using Floating points- As a rule of thumb, floating-point is about 2x slower than integer on Android-powered devices.

7)Optimizing Layout Hierarchies
8)Re-using Layouts with <include/>
9)Loading Views On Demand- Use kind of ViewStub and all.

10)Making ListView Scrolling Smooth-using worker thread and ViewHolder


So,all these small steps will make your application fast,reliable,less bug prone,optimized and performance will be very good.


What is the best approach to download thousands of images over the Network(in Parallel or Queue Worker Threads) in Android?

Let me be more specific on it,interviewer asked me this question,if you have to download many images like 1000 thousands.how will you do that?i said, i would use Universal Image Loader,Picasso third party library then he further asked No,we do not want that.we want you to create your own Parallel or Queue thread whatever you are thinking,It should be efficient.

Now, Lets understand first what is Lazy Loading?

A little introduction of lazy loading is,  it is a design pattern to defer the initialization of an object until the point at which it is needed. In simple words create objects when it is needed. Further,object on demand.

So what is the challenges in loading lots of images in ListView or GridView or RecyclerView.

1) Scrolling Blocked or Interrupted – Downloading images from server OR loading from device local storage is heavy task and it may take some time. If you load  images directly in getView() method of Adapter then it blocks the UI thread and your ListView scroll will be interrupted and not smooth. You  need a mechanism to load images in a worker (separate) thread and show a place holder image until the image in not downloaded and placed in memory for fast access. Remember accessing images from Hard disk may also takes some time.

2)App Heap Memory can Overflow– If we load many images in memory for faster access by ListView / Adapter, then memory (heap memory) allocated to the application might overflow and app will crash with Out of Memory (OOM) error.

3)Have to work on Recycling View can be tricky: 

When image is  downloaded  we need to  decide when to set a particular image in its ImageView of that row it is meant for.  It may be possible that the ImageView object will recycle and it  is given to another image and we end up showing wrong image.

So, downloading lots image lead lots of carefulness but i would suggest create Parallel Worker Thread which will perform this task.Let me give more clarity on it. If you ask me how will you do that in Android regards ,i would say use intent service and create worker threads from thread pool and let thread executor handle the worker thread.Now the whole task will happen in queue. i mean to say lets assume you have started 9 worker threads from Thread Pool,so paralleled 9 threads are executing their task and all of threads are in Thread Pool in queue .

And yes there are many other ways also to do that but if you see third party Library you will understand they are also performing this kind of task in Parallel Worker Threads.

Thursday, September 8, 2016

What is the difference between Started Service and Bound Service in Android?

Very frequent interview question , What is the difference between Started Service and Bound Service?

Ans: Let's first understand what is started Service and Bound Service?.

Started Service: When you wants to perform a long running task in background means without UI(User Interface) work such as sending data to server ,performing network operations such as get and post,Playing Musics etc. then you can use started service So,question is why not Bound Service?.Lets leave bound service at the moment.But let me clear here only that It is not advisable to use bound service here,it is not a best practice in Android.Lets look at the call backs of started Service.

Lets start Service you will do something like this in the Activity:
startService(new Intent(this, FirstService.class));
Now lets watch the call backs of it:

Image

It is clearly visible that it will stop itself once the task is done or would be stopped by the client.There is nothing extra callbacks there to update anything else.What i mean to say is:    The service then runs indefinitely and must stop itself by calling stopSelf().So,When a service is started, it   has a life-cycle that's independent of the component that started it and the service can run in the background definitely, even if the component that started it is destroyed.  So,if you want to perform a long running task which is related with the UI then how will you update the UI, When the component that started it is being destroyed by the Android Operating System.There bound services comes into the picture.                                                                                                                                                       Now , Lets see what is Bound Service and if you can see in the picture, there  are some extra call back methods are specially in bound services which itself explains many thing.                                                                                                                                                                               
A service is "bound" when an application component binds to it by calling bindService(). A bound service offers a client-server interface that allows components to interact with the service, send requests, get results, and even do so across processes with inter-process communication (IPC).           A bound service runs only as long as another application component is bound to it. Multiple components can bind to the service at once, but when all of them unbind, the service is destroyed.

You should create a bound service when you want to interact with the service from activities and other components in your application or to expose some of your application's functionality to other applications, through inter-process communication (IPC).                                                                       So,it clear that when you want to do some task which is related with UI or you want to create some thing which other components can use of your application then in that case you can use bind service instead of using started service.So this is the major difference between started and bound services.

  
                                                              






Thursday, August 11, 2016

Beacons Android Integration Code Example continue....

For this you need to understand few major things

1)Estimote Beacon Library
2)App Id and Token Id
3)Need to give reference the library in the gradle file
4)The default beacon id is B9407F30-F5F8-466E-AFF9-25556B57FE6D

Manifest.xml:

<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android"    package="com.beacon.testing">

    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <application 
       android:name=".MyApplication"
        android:allowBackup="true"  
      android:icon="@drawable/becon"   
     android:label="@string/app_name" 
       android:supportsRtl="true"   
     android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

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

</manifest>


BeaconID.java :

import com.estimote.sdk.Region;
import java.util.UUID;

public class BeaconID
{

    private UUID proximityUUID;
    private int major;
    private int minor;

    public BeaconID(UUID proximityUUID, int major, int minor) {
        this.proximityUUID = proximityUUID;
        this.major = major;
        this.minor = minor;
    }

    public BeaconID(String UUIDString, int major, int minor) {
        this(UUID.fromString(UUIDString), major, minor);
    }

    public UUID getProximityUUID() {
        return proximityUUID;
    }

    public int getMajor() {
        return major;
    }

    public int getMinor() {
        return minor;
    }

    public Region toBeaconRegion() {
        return new Region(toString(), getProximityUUID(), getMajor(), getMinor());
    }

    public String toString() {
        return getProximityUUID().toString() + ":" + getMajor() + ":" + getMinor();
    }

    @Override    public int hashCode() {
        return toString().hashCode();
    }

    @Override    public boolean equals(Object o) {
        if (o == null) {
            return false;
        }

        if (o == this) {
            return true;
        }

        if (getClass() != o.getClass()) {
            return super.equals(o);
        }

        BeaconID other = (BeaconID) o;

        return getProximityUUID().equals(other.getProximityUUID())
                && getMajor() == other.getMajor()
                && getMinor() == other.getMinor();
    }
}

BeaconNotificationsManager.java :

import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.support.v4.app.NotificationCompat;
import android.util.Log;
import android.widget.Toast;
import com.estimote.sdk.Beacon;
import com.estimote.sdk.BeaconManager;
import com.estimote.sdk.Region;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
public class BeaconNotificationsManager{

    private static final String TAG = "BeaconNotifications";

    private BeaconManager beaconManager;

    private List<Region> regionsToMonitor = new ArrayList<>();
    private HashMap<String, String> enterMessages = new HashMap<>();
    private HashMap<String, String> exitMessages = new HashMap<>();
    private Context context;
    private int notificationID = 0;

    public BeaconNotificationsManager(final Context context) {
        this.context = context;
        beaconManager = new BeaconManager(context);
        beaconManager.setMonitoringListener(new BeaconManager.MonitoringListener() {
            @Override            public void onEnteredRegion(Region region, List<Beacon> list) {
                Log.d(TAG, "onEnteredRegion: " + region.getIdentifier());
                Toast.makeText(context,"onEnteredRegion"+ region.getIdentifier(),Toast.LENGTH_LONG).show();
                MyApplication.identifier=""+region.getIdentifier();
                MyApplication.major=""+region.getMajor();
                MyApplication.minor=""+region.getMinor();
                MyApplication.proximity=""+region.getProximityUUID();
                Log.v(TAG,MyApplication.identifier+":"+ MyApplication.major+":"+ MyApplication.minor+":"+MyApplication.proximity);
                String message = enterMessages.get(region.getIdentifier());
                if (message != null) {
                    showNotification(message);
                }
            }

            @Override            public void onExitedRegion(Region region) {
                Log.d(TAG, "onExitedRegion: " + region.getIdentifier());
                String message = exitMessages.get(region.getIdentifier());
                if (message != null) {
                    showNotification(message);

                }
            }
        });
    }

    public void addNotification(BeaconID beaconID, String enterMessage, String exitMessage) {
        Region region = beaconID.toBeaconRegion();
        enterMessages.put(region.getIdentifier(), enterMessage);
        exitMessages.put(region.getIdentifier(), exitMessage);
        regionsToMonitor.add(region);
    }

    public void startMonitoring() {
        beaconManager.connect(new BeaconManager.ServiceReadyCallback() {
            @Override            public void onServiceReady() {
                for (Region region : regionsToMonitor) {
                    beaconManager.startMonitoring(region);
                }
            }
        });
    }

    private void showNotification(String message)
    {
        Toast.makeText(context,message,Toast.LENGTH_LONG).show();

        Log.v("BeaconNotificationManager","Message is: "+ message);
        Intent resultIntent = new Intent(context, MainActivity.class);
        PendingIntent resultPendingIntent = PendingIntent.getActivity(context, 0, resultIntent, PendingIntent.FLAG_CANCEL_CURRENT);
        NotificationCompat.Builder builder = new NotificationCompat.Builder(context)
                .setSmallIcon(android.R.drawable.ic_dialog_info)
                .setContentTitle("Beacon Notifications")
                .setContentText(message)
                .setDefaults(NotificationCompat.DEFAULT_ALL)
                .setPriority(NotificationCompat.PRIORITY_HIGH)
                .setContentIntent(resultPendingIntent);
        NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
        notificationManager.notify(notificationID++, builder.build());
    }

}

MainActivity.java :

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import com.estimote.sdk.SystemRequirementsChecker;

public class MainActivity extends AppCompatActivity
{
    private TextView tvDevice,tvDetails;
    private ImageView iv_becon;
    private static final String TAG = "MainActivity";

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

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

    private void initView()
    {
        tvDevice = (TextView) findViewById(R.id.textView);
        iv_becon = (ImageView) findViewById(R.id.iv_becon);
        tvDetails=(TextView)findViewById(R.id.tvBeaconDetails);
    }

    private void startSearching()
    {
                MyApplication app = (MyApplication) getApplication();
                if (!SystemRequirementsChecker.checkWithDefaultDialogs(MainActivity.this))
                {
                    Log.e(TAG, "Can't scan for beacons, some pre-conditions were not met");
                    Log.e(TAG, "Read more about what's required at: http://estimote.github.io/Android-SDK/JavaDocs/com/estimote/sdk/SystemRequirementsChecker.html");
                    Log.e(TAG, "If this is fixable, you should see a popup on the app's screen right now, asking to enable what's necessary");
                }
                else if (!app.isBeaconNotificationsEnabled())
                {
                    Log.d(TAG, "Enabling beacon notifications");
                    app.enableBeaconNotifications();
                }
    }

    private void setTextDetails()
    {
        tvDevice.setText("Becon Found");
        iv_becon.setVisibility(View.VISIBLE);
        tvDetails.setText("Major:: "+MyApplication.major + "\n" + "Minor:: " +MyApplication.minor + "\n" + "Proximity:: " +MyApplication.proximity +"\n" + "Identifier:: " +MyApplication.identifier);
    }

}

MyApplication.java :

import android.app.Application;
import com.estimote.sdk.EstimoteSDK;

public class MyApplication extends Application
{
    private boolean beaconNotificationsEnabled = false;
    public static String identifier="";
    public static String major="";
    public static String minor="";
    public static String proximity="";

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

        // TODO: put your App ID and App Token here        // You can get them by adding your app on https://cloud.estimote.com/#/apps        EstimoteSDK.initialize(getApplicationContext(), "notificationestimote-ksu", "a74e58eacb5007271a789d6aa3f5197c");

        // uncomment to enable debug-level logging        // it's usually only a good idea when troubleshooting issues with the Estimote SDK        EstimoteSDK.enableDebugLogging(true);
    }

    public void enableBeaconNotifications() {
        if (beaconNotificationsEnabled) { return; }

        BeaconNotificationsManager beaconNotificationsManager = new BeaconNotificationsManager(this);

        beaconNotificationsManager.addNotification(
                // TODO: replace with UUID, major and minor of your own beacon                new BeaconID("B9407F30-F5F8-466E-AFF9-25556B57FE6D", 60454, 28798),
                "I am found by Application.",
                "Goodbye, world.");
        beaconNotificationsManager.startMonitoring();
        beaconNotificationsEnabled = true;
    }

    public boolean isBeaconNotificationsEnabled() {
        return beaconNotificationsEnabled;
    }
}


gradle file: 


apply plugin: 'com.android.application'
android {
    compileSdkVersion 24 
   buildToolsVersion "24.0.0"
    defaultConfig {
        applicationId "com.beacon.testing" 
       minSdkVersion 15 
       targetSdkVersion 24
        versionCode 1 
       versionName "1.0" 
   }
    buildTypes {
        release {
            minifyEnabled false    
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'        }
    }
}

dependencies {
    compile fileTree(include: ['*.jar'], dir: 'libs')
    testCompile 'junit:junit:4.12' 
   compile 'com.android.support:appcompat-v7:24.0.0'  
  compile files('libs/estimote-sdk-javadoc.jar')
    compile 'com.estimote:sdk:0.11.0@aar' 
   compile 'com.google.android.gms:play-services-appindexing:8.1.0'}


activity_main.xml

<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:paddingBottom="@dimen/activity_vertical_margin"    android:paddingLeft="@dimen/activity_horizontal_margin"    android:paddingRight="@dimen/activity_horizontal_margin"    android:paddingTop="@dimen/activity_vertical_margin"    tools:context="com.beacon.testing.MainActivity"    android:background="@drawable/backgrpound"    >
    <TextView       
 android:id="@+id/textView"  
      android:layout_width="wrap_content"  
      android:layout_height="wrap_content" 
       android:layout_alignParentBottom="true"  
      android:layout_centerHorizontal="true"   
     android:textStyle="bold"  
      android:textSize="20dp"     
   android:text="Searching..." />

    <ImageView  
      android:id="@+id/iv_becon"   
     android:layout_width="80dp"   
     android:layout_height="60dp"    
    android:background="@drawable/becon"  
      android:layout_centerInParent="true" 
       android:layout_alignParentEnd="true"  
      android:visibility="gone"       
 android:layout_alignParentRight="true" />

    <TextView 
       android:id="@+id/tvBeaconInfo" 
       android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"  
      android:layout_marginTop="10dp"
        android:textStyle="bold"  
      android:textSize="21dp"    
    android:textColor="@android:color/holo_red_light"  
      android:text="Beacon Information" />
    <TextView   
     android:id="@+id/tvBeaconDetails" 
       android:layout_width="wrap_content" 
       android:layout_height="wrap_content" 
      android:layout_below="@+id/tvBeaconInfo" 
       android:layout_centerHorizontal="true" 
       android:layout_marginTop="10dp"
        android:textColor="@android:color/holo_blue_dark" 
       android:textStyle="normal" 
       android:textSize="15dp"  
      android:text="Beacon Details" />


</RelativeLayout>

Output Should look like this...

Image