Android Realm Database Tutorial

Hi Guys,

Is there an alternative to SQlite database? Sure there is one… Realm Database.

Realm Database can be used for offline syncing much like SQlite but in an much more efficient way.

You can take a look at this link for more details.

Download LinkAndroid Realm Database Tutorial

Demo Video

build.gradle


dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.android.support:appcompat-v7:25.2.0'
compile 'io.realm:realm-android:0.84.1'
compile 'com.android.support:recyclerview-v7:25.2.0'
compile 'com.android.support:design:25.2.0'
compile 'com.android.support:cardview-v7:25.2.0'
compile 'com.squareup.picasso:picasso:2.5.2'
testCompile 'junit:junit:4.12'
}

This is how the build.gradle file looks like in my case.

Now First the Realm configuration file is created and named as MainApplication.java.

MainApplication.java


public class MainApplication extends Application {

@Override
public void onCreate() {
super.onCreate();
RealmConfiguration config=new RealmConfiguration.Builder(this)
.schemaVersion(4)
.deleteRealmIfMigrationNeeded()
.build();
Realm.setDefaultConfiguration(config);
}
}

Basically this file acts as a configuration file. Then this MainApplication file must be
set in the manifest file.

AndroidManifest.xml


<application 
android:name=".MainApplication" 
android:allowBackup="true" 
android:icon="@drawable/cozycodes" 
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>

Next is the Sample java class where all the data models are created. This can be done by extending
the RealmObject base class.

Here Primary key annotation can be set and in this case String name is used which
I would not recommend it is always good to use integer as Primary Key.
Sample.java

public class Sample extends RealmObject{

 @PrimaryKey
 private String name;
 private String address;
 private String age;
 private String image;

 public String getName(){
 return name;
 }

 public void setName(String name){
 this.name = name;
 }

 public String getAddress(){
 return address;
 }

 public void setAddress(String address){
 this.address = address;
 }

 public String getAge(){
 return age;
 }

 public void setAge(String age){
 this.age = age;
 }

 public String getImage(){
 return image;
 }

 public void setImage(String image){
 this.image = image;
 }
}

RealmConnect class is a helper class which has all the methods for the Realm Database methods.
RealmConnect is a Singleton Class. To know much more about Singleton class visit this link.

RealmConnect.java

public class RealmConnect {

    Realm realm;
    RealmResults<Sample> sample;
    Boolean add=null;
    private static RealmConnect instance;

    public RealmConnect(Application application) {
        realm = Realm.getDefaultInstance();
    }

    public RealmConnect(Realm realm) {
        this.realm = realm;
    }


    public Boolean add(final Sample sample)
    {
        if(sample == null)
        {
            add = false;
        }else
        {
            realm.executeTransaction(new Realm.Transaction() {
                @Override
                public void execute(Realm realm) {

                    try
                    {
                        Sample val = realm.copyToRealm(sample);
                        add = true;

                    }catch (RealmException e)
                    {
                        e.printStackTrace();
                        add = false;
                    }
                }
            });
        }

        return add;
    }


    public void selectDB()
    {
        sample = realm.where(Sample.class).findAll();
    }


    public ArrayList<Sample> dataReload()
    {
        ArrayList<Sample> latest=new ArrayList<>();
        for(Sample s : sample)
        {
            latest.add(s);
        }

        return latest;
    }



    public static RealmConnect getInstance() {

        return instance;
    }

    public Realm getRealm() {

        return realm;
    }

    public static RealmConnect with(Activity activity) {

        if (instance == null) {
            instance = new RealmConnect(activity.getApplication());
        }
        return instance;
    }


}

 

Then we have a Recyclerview for the Main Activity named as SampleAdapter.
SampleAdapter has the action functions such long press for delete and tap for editind the Realm database items.

SampleAdapter.java

public class SampleAdapter extends RecyclerView.Adapter<SampleAdapter.MyHolder> {
 List<Sample> wishes = new ArrayList<>();
 Sample val;
 private Realm realm;
 Context mContext;
 ArrayList<Sample> sample;
 private LayoutInflater inflater;

 public SampleAdapter(Context context, ArrayList<Sample> sample) {
 this.mContext = context;
 this.sample = sample;
 }

 @Override
 public MyHolder onCreateViewHolder(ViewGroup parent, int viewType) {
 View v= LayoutInflater.from(mContext).inflate(R.layout.listing,parent,false);
 return new MyHolder(v);
 }

 @Override
 public void onBindViewHolder(final MyHolder holder, final int position) {

 realm = RealmConnect.getInstance().getRealm();
 val = sample.get(position);

 holder.in_name.setText(val.getName());
 holder.in_address.setText(val.getAddress());
 holder.in_age.setText(val.getAge());

 String imageUrl = val.getImage().replace("https","http");

 LoadImage.downloadImage(mContext,imageUrl,holder.profile_img);

 // Long Press to delete item
 holder.cardview.setOnLongClickListener(new View.OnLongClickListener() {
 @Override
 public boolean onLongClick(View v) {
 AlertDialog.Builder builder = new AlertDialog.Builder(v.getContext());
 builder.setTitle("Delete User");
 builder.setMessage("Are you sure?");
 builder.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
 @Override
 public void onClick(DialogInterface dialog, int which) {
 RealmResults<Sample> results = realm.where(Sample.class).findAll();

 realm.beginTransaction();
 results.remove(position);
 realm.commitTransaction();

 }
 });
 builder.setNegativeButton("No", null);
 builder.show();

 return false;
 }
 });

 // Click to Edit item values
 holder.cardview.setOnClickListener(new View.OnClickListener() {

 @Override
 public void onClick(View v) {

 inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
 View content = inflater.inflate(R.layout.edit_listing, null);
 final EditText editTitle = (EditText) content.findViewById(R.id.Et_name);
 final EditText editAuthor = (EditText) content.findViewById(R.id.Et_address);
 final EditText editThumbnail = (EditText) content.findViewById(R.id.Et_age);
 final EditText editUrl = (EditText) content.findViewById(R.id.Et_url);

 editTitle.setText(sample.get(position).getName());
 editAuthor.setText(sample.get(position).getAddress());
 editThumbnail.setText(sample.get(position).getAge());
 editUrl.setText(sample.get(position).getImage());

// Toast.makeText(mContext, sample.get(position).getName() , Toast.LENGTH_SHORT).show();
 AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
 builder.setView(content)
 .setTitle("Edit User")
 .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
 @Override
 public void onClick(DialogInterface dialog, int which) {

 RealmResults<Sample> results = realm.where(Sample.class).findAll();

 realm.beginTransaction();
 results.get(position).setAddress(editAuthor.getText().toString());
 results.get(position).setName(editTitle.getText().toString());
 results.get(position).setAge(editThumbnail.getText().toString());
 results.get(position).setImage(editUrl.getText().toString());

 realm.commitTransaction();

// notifyDataSetChanged();
 dialog.dismiss();
 }
 })
 .setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {

 @Override
 public void onClick(DialogInterface dialog, int which) {
 dialog.dismiss();
 }
 });
 AlertDialog dialog = builder.create();
 dialog.show();
 }
 });

 }

 @Override
 public int getItemCount() {
 return sample.size();
 }


 public class MyHolder extends RecyclerView.ViewHolder {

 TextView in_name,in_address,in_age;
 ImageView profile_img;
 CardView cardview;

 public MyHolder(View itemView) {
 super(itemView);

 in_name= (TextView) itemView.findViewById(R.id.in_name);
 in_address= (TextView) itemView.findViewById(R.id.in_address);
 in_age= (TextView) itemView.findViewById(R.id.in_age);
 profile_img= (ImageView) itemView.findViewById(R.id.profile_img);
 cardview = (CardView) itemView.findViewById(R.id.cardview);
 }
 }

}

 

Finally the MainActivity,

MainActivity.java

public class MainActivity extends AppCompatActivity {

 Realm realm;
 RealmChangeListener realmChangeListener;
 SampleAdapter adapter;
 RecyclerView sample_recyclerview;
 EditText Et_name,Et_address,Et_age,Et_url;
 String name, address, age, image_url;

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

 sample_recyclerview= (RecyclerView) findViewById(R.id.sample_recycler);
 sample_recyclerview.setLayoutManager(new LinearLayoutManager(this));

 this.realm = RealmConnect.with(this).getRealm();

 final RealmConnect connect = new RealmConnect(realm);
 connect.selectDB();

 adapter=new SampleAdapter(this,connect.dataReload());
 sample_recyclerview.setAdapter(adapter);

 realmChangeListener=new RealmChangeListener() {
 @Override
 public void onChange() {

 adapter=new SampleAdapter(MainActivity.this,connect.dataReload());
 sample_recyclerview.setAdapter(adapter);
 }
 };

 realm.addChangeListener(realmChangeListener);

 FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
 fab.setOnClickListener(new View.OnClickListener() {
 @Override
 public void onClick(View view) {
 addNewUser();
 }
 });
 }


 @Override
 protected void onDestroy() {
 super.onDestroy();
 // data changes are informed on the view
 realm.removeChangeListener(realmChangeListener);
 realm.close();
 }

 //Function to add new user
 private void addNewUser()
 {
 Dialog alert = new Dialog(this);
 alert.setTitle("New User");
 alert.setContentView(R.layout.input_dialog);

 Et_name = (EditText) alert.findViewById(R.id.Et_name);
 Et_address = (EditText) alert.findViewById(R.id.Et_address);
 Et_age = (EditText) alert.findViewById(R.id.Et_age);
 Et_url = (EditText) alert.findViewById(R.id.Et_url);
 Button addBtn = (Button) alert.findViewById(R.id.addBtn);


 addBtn.setOnClickListener(new View.OnClickListener() {
 @Override
 public void onClick(View v) {

 name = Et_name.getText().toString();
 address = Et_address.getText().toString();
 age = Et_age.getText().toString();
 image_url = Et_url.getText().toString();

 if(name != null && name.length()>0)
 {

 Sample sample = new Sample();
 sample.setName(name);
 sample.setAddress(address);
 sample.setAge(age);
 sample.setImage(image_url);

 RealmConnect connect = new RealmConnect(realm);

 if(connect.add(sample))
 {
 Et_name.setText("");
 Et_address.setText("");
 Et_age.setText("");
 Et_url.setText("");

 }else {
 Toast.makeText(MainActivity.this, "Invalid", Toast.LENGTH_SHORT).show();
 }

 }else {
 Toast.makeText(MainActivity.this, "Field Cannot be Empty", Toast.LENGTH_SHORT).show();
 }

 }
 });

 alert.show();

 }
}

The MainActivity class has the major items declared in it such as RecyclerView, Adpater changes and
RealmController instantiation. There is a listener placed in the MainActivity which informs the adapter about any
data changes and no separate function such as notifyDataSetChanged() needs to be called.

sample_recyclerview= (RecyclerView) findViewById(R.id.sample_recycler);
 sample_recyclerview.setLayoutManager(new LinearLayoutManager(this));

 this.realm = RealmConnect.with(this).getRealm();

 final RealmConnect connect = new RealmConnect(realm);
 connect.selectDB();

 adapter=new SampleAdapter(this,connect.dataReload());
 sample_recyclerview.setAdapter(adapter);

 realmChangeListener=new RealmChangeListener() {
 @Override
 public void onChange() {

 adapter=new SampleAdapter(MainActivity.this,connect.dataReload());
 sample_recyclerview.setAdapter(adapter);
 }
 };

 realm.addChangeListener(realmChangeListener);

Realm Database is a much more efficient way for syncing data to offline.

 

Download LinkAndroid Realm Database Tutorial

Android NFC Phone Call And SMS Sender

Hi Guys, today it’s time to take a look at how to call and send SMS to a mobile number once a NFC tag is detected.
This is basically an Android App to automate mobile device.
Let’s jump into coding.

MainActivity.java

package com.thul.nfc;

import com.thul.nfc.R;

import android.app.Activity;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.IntentFilter.MalformedMimeTypeException;
import android.net.Uri;
import android.nfc.NfcAdapter;
import android.nfc.Tag;
import android.nfc.tech.NfcA;
import android.os.Bundle;
import android.telephony.SmsManager;
import android.util.Log;
import android.view.Menu;
import android.widget.Toast;

public class MainActivity extends Activity {
String phone = "1234567890"; // Replace with your mobile number
String yellow_tag = "04D658B2003E80"; // Replace with your NFC Tag ID
String white_tag = "044C54B2003E80"; // Replace with your NFC Tag ID
String red_tag = "04E25FB2003E80"; // Replace with your NFC Tag ID
String blue_tag = "04385BB2003E80"; // Replace with your NFC Tag ID
String green_tag = "04FC4EB2003E80"; // Replace with your NFC Tag ID

NfcAdapter mAdapter;
IntentFilter[] mFilters;
PendingIntent mPendingIntent;

void resolveIntent(Intent intent) {
Context context = getApplicationContext();
int duration = Toast.LENGTH_LONG;

String action = intent.getAction();

if (NfcAdapter.ACTION_TECH_DISCOVERED.equals(action)) {

Tag tagFromIntent = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
byte[] extraID = tagFromIntent.getId();

StringBuilder sb = new StringBuilder();
for (byte b : extraID) {
sb.append(String.format("%02X", b));
};

String tagID = sb.toString();
Log.e("nfc ID", tagID);

String name;

if (tagID.equals(yellow_tag)){

Intent callIntent = new Intent(Intent.ACTION_CALL);
callIntent.setData(Uri.parse("tel:"+phone));
startActivity(callIntent);
name = "yellow";
}
else if (tagID.equals(white_tag)){

SmsManager sms = SmsManager.getDefault();
sms.sendTextMessage(phone, null, "Hi this is a Test message", null, null);
name = "White";

}
else if (tagID.equals(red_tag)){

name = "Red";

}
else if (tagID.equals(blue_tag)){

name = "Blue";

}
else if (tagID.equals(green_tag)){

name = "Green";

}
else {

name ="Unknown Tag";
}


Toast toast = Toast.makeText(context, name, duration);
toast.show();

};
}



String[][] mTechLists = new String[][] { new String[] { NfcA.class.getName() } };
Intent intent = getIntent();

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

mPendingIntent = PendingIntent.getActivity(this, 0,
new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);

IntentFilter ndef1 = new IntentFilter(NfcAdapter.ACTION_TECH_DISCOVERED);
mFilters = new IntentFilter[] {
ndef1,
};

try {
ndef1.addDataType("*/*");

} catch (MalformedMimeTypeException e) {
throw new RuntimeException("fail", e);
}
mAdapter = NfcAdapter.getDefaultAdapter(this);

if (getIntent() != null){
resolveIntent(getIntent());
}

}

@Override
public boolean onCreateOptionsMenu(Menu menu) {

getMenuInflater().inflate(R.menu.main, menu);
return true;
}

@Override
public void onResume() {
super.onResume();
mAdapter.enableForegroundDispatch(this, mPendingIntent, mFilters, mTechLists);
}

@Override
public void onNewIntent(Intent intent) {
Log.i("Foreground dispatch", "Discovered tag with intent: " + intent);
resolveIntent(intent);
}

@Override
public void onPause() {
super.onPause();
mAdapter.disableForegroundDispatch(this);
}

}

The mobile number and NFC tag IDs must be changed accordingly for your use.

You can find NFC tags in the image link below. Cheers.

Attachments

Android Local Area Map Using GPS

Hi Guys, today it’s time to take a look at how to create location marker of specific spot in an Android Application.

Basically this is an Android App for marking a location in Google maps.

Let’s jump into coding.

Android Local Area Map Using GPS

Location of different places can be added by using exact latitude and longitude of a specific spot.

MapsActivity.java

package com.thul.map;

import android.support.v7.app.ActionBarActivity;
import android.support.v7.app.ActionBar;
import android.support.v4.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.os.Build;
import android.content.IntentSender;
import android.location.Location;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.util.Log;

import com.thul.map.R;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.MarkerOptions;

public class MapsActivity extends FragmentActivity implements
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener ,LocationListener {

private GoogleMap mMap;
private GoogleApiClient mGoogleApiClient;
public static final String TAG = MapsActivity.class.getSimpleName();
private final static int CONNECTION_FAILURE_RESOLUTION_REQUEST = 9000;
private LocationRequest mLocationRequest;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_maps);
setUpMapIfNeeded();
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();

mLocationRequest = LocationRequest.create()
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
.setInterval(10 * 1000)
.setFastestInterval(1000);
}

@Override
protected void onResume() {
super.onResume();
setUpMapIfNeeded();
mGoogleApiClient.connect();
}

@Override
protected void onPause() {
super.onPause();
if (mGoogleApiClient.isConnected()) {
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
mGoogleApiClient.disconnect();
}
}
private void setUpMapIfNeeded() {

if (mMap == null) {

mMap = ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map))
.getMap();

if (mMap != null) {
setUpMap();
mMap.setMyLocationEnabled(true);
}

}
}


private void handleNewLocation(Location location) {
Log.d(TAG, location.toString());

}
private void setUpMap() {
mMap.addMarker(new MarkerOptions().position(new LatLng(0, 0)).title("Marker"));
LatLng latLng = new LatLng(13.111889, 80.184343);
//LatLng latLng = new LatLng(currentLatitude, currentLongitude);
MarkerOptions options = new MarkerOptions()
.position(latLng)
.title("Korattur");
mMap.addMarker(options);
mMap.addMarker(new MarkerOptions().position(new LatLng(13.111889, 80.184343)).title("DCB Bank ATM").snippet("KORATTUR"));
mMap.addMarker(new MarkerOptions().position(new LatLng(13.111889,80.184320)).title("Canara Bank Atm").snippet("KORATTUR"));
mMap.addMarker(new MarkerOptions().position(new LatLng(13.111894, 80.184549)).title("Mary Coffee").snippet("KORATTUR"));
mMap.addMarker(new MarkerOptions().position(new LatLng(13.111454, 80.183970)).title("Axis Bank Atm").snippet("KORATTUR"));
mMap.addMarker(new MarkerOptions().position(new LatLng(13.110241, 80.184175)).title("More Supermarket").snippet("KORATTUR"));
mMap.addMarker(new MarkerOptions().position(new LatLng(13.109835, 80.184144)).title("Veni Supermarket").snippet("KORATTUR"));
mMap.addMarker(new MarkerOptions().position(new LatLng(13.109800, 80.183673)).title("ICICI Atm").snippet("KORATTUR"));
mMap.addMarker(new MarkerOptions().position(new LatLng(13.109262, 80.183143)).title("Bhaktavatsalam Vidhyashram").snippet("KORATTUR"));
mMap.addMarker(new MarkerOptions().position(new LatLng(13.108875,80.183602)).title("Mummy Daddy").snippet("KORATTUR"));
mMap.addMarker(new MarkerOptions().position(new LatLng(13.108115,80.185410)).title("New Saravana's").snippet("KORATTUR"));
mMap.addMarker(new MarkerOptions().position(new LatLng(13.108065, 80.186253)).title("Tnsc Bank").snippet("KORATTUR"));
mMap.addMarker(new MarkerOptions().position(new LatLng(13.107564, 80.186715)).title("Carrie Cakes").snippet("KORATTUR"));
mMap.addMarker(new MarkerOptions().position(new LatLng(13.106996, 80.186680)).title("Kotak Mahindra Bank Atm").snippet("KORATTUR"));
mMap.addMarker(new MarkerOptions().position(new LatLng(13.106444, 80.18661)).title("Green Trends Saloon").snippet("KORATTUR"));
mMap.addMarker(new MarkerOptions().position(new LatLng(13.105768, 80.186535)).title("Ongara Ashram").snippet("KORATTUR"));
mMap.addMarker(new MarkerOptions().position(new LatLng(13.103314, 80.186418)).title("Domino's Pizza").snippet("KORATTUR"));
mMap.moveCamera(CameraUpdateFactory.newLatLng(latLng));

mMap.animateCamera(CameraUpdateFactory.zoomTo(16));
}

@Override
public void onConnected(Bundle bundle) {
Log.i(TAG, "Location services connected.");
Location location = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
if (location == null) {
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
}
else {
handleNewLocation(location);
}
}

@Override
public void onConnectionSuspended(int i) {
Log.i(TAG, "Location services suspended. Please reconnect.");
}

@Override
public void onConnectionFailed(ConnectionResult connectionResult) {
if (connectionResult.hasResolution()) {
try {

connectionResult.startResolutionForResult(this, CONNECTION_FAILURE_RESOLUTION_REQUEST);
} catch (IntentSender.SendIntentException e) {
e.printStackTrace();
}
} else {
Log.i(TAG, "Location services connection failed with code " + connectionResult.getErrorCode());
}
}

@Override
public void onLocationChanged(Location location) {

}
}

 

You must place your own Google maps API key in the Android Manifest file.

AndroidManifest.xml


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

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

 <uses-permission android:name="android.permission.INTERNET" />
 <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
 <uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" />
 <!--
 The ACCESS_COARSE/FINE_LOCATION permissions are not required to use
 Google Maps Android API v2, but are recommended.
 -->
 <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
 <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

 <application
 android:allowBackup="true"
 android:icon="@mipmap/map"
 android:label="@string/app_name"
 android:theme="@style/AppTheme" >
 <meta-data
 android:name="com.google.android.gms.version"
 android:value="@integer/google_play_services_version" />
 <meta-data
 android:name="com.google.android.maps.v2.API_KEY"
 android:value="Replace with your Google Maps API Key" />

 <activity
 android:name="com.thul.map.MapsActivity"
 android:label="@string/title_activity_maps" >
 <intent-filter>
 <action android:name="android.intent.action.MAIN" />

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

</manifest>

 

Attachments

Android Call Recorder Source Code

Hi Guys, today it’s time to take a look at how to record phone call in Android programmatically.

This tutorial or page has Android call recorder app source code.

Let’s jump into coding.

 Android Call Recorder Source Code

MainActivity.java


package com.thul.CallRecorder;

import java.util.ArrayList;
import android.app.NotificationManager;
import android.app.Service;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.Notification;
import android.app.PendingIntent;
import android.app.ActivityManager.RunningServiceInfo;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.support.v4.app.NotificationCompat;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class MainActivity extends Activity {
private static final String TAG = MainActivity.class.getName();

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button b = (Button) findViewById(R.id.btnStartStop);
b.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Log.d(TAG, "start or stop service");
Intent i = new Intent(MainService.ACTION);
if (isServiceRunning()) {
stopService(i);
((NotificationManager) getSystemService(NOTIFICATION_SERVICE))
.cancelAll();

} else {
startService(i);

runAsForeground();

}
updateButtonState((Button)v);
}
});
updateButtonState(b);
}

private void updateButtonState(Button b) {
if (isServiceRunning()) {
b.setText(R.string.stop_record);
} else {
b.setText(R.string.start_record);

}
}

private boolean isServiceRunning() {
ActivityManager myManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
ArrayList<RunningServiceInfo> runningService = (ArrayList<RunningServiceInfo>) myManager
.getRunningServices(30);
for (int i = 0; i < runningService.size(); i++) {
if (runningService.get(i).service.getClassName().equals(
MainService.class.getName())) {
return true;
}
}
return false;
}

private void runAsForeground(){
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent=PendingIntent.getActivity(this, 0,
notificationIntent, Intent.FLAG_ACTIVITY_NEW_TASK);

Notification notification=new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.ic_launcher)
.setContentTitle(getString(R.string.app_name))
.setContentText("Call Record")
.setContentIntent(pendingIntent).build();
NotificationManager notificationManager =
(NotificationManager) getSystemService(NOTIFICATION_SERVICE);
notification.flags = notification.flags
| Notification.FLAG_ONGOING_EVENT;
notification.flags |= Notification.FLAG_AUTO_CANCEL;

notificationManager.notify(0, notification);
}

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

@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.item1:
openFolder();
// Toast.makeText(getApplicationContext(),"Item 1 Selected",Toast.LENGTH_LONG).show();
return true;
default:
return super.onOptionsItemSelected(item);
}
}

public void openFolder()
{
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
Uri uri = Uri.parse(Environment.getExternalStorageDirectory().getPath()
+ "/callrec/");
intent.setDataAndType(uri, "audio/amr");

startActivity(Intent.createChooser(intent, "Open folder"));
}
}

 

MainService.java

package com.thul.CallRecorder;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

import android.app.Service;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.media.MediaRecorder;
import android.net.Uri;
import android.os.Environment;
import android.os.IBinder;
import android.os.PowerManager;
import android.provider.ContactsContract.PhoneLookup;
import android.util.Log;

public class MainService extends Service {
 public static final String ACTION = "com.thul.CallRecorder.CALL_RECORD";
 public static final String STATE = "STATE";
 public static final String START = "START";
 public static final String STORAGE = "STORAGE";
 public static final String INCOMING = "INCOMING";
 public static final String OUTGOING = "OUTGOING";
 public static final String BEGIN = "BEGIN";
 public static final String END = "END";

 protected static final String TAG = MainService.class.getName();
 protected static final boolean DEBUG = false;

 private static final String AMR_DIR = "/callrec/";
 private static final String IDLE = "";
 private static final String INCOMING_CALL_SUFFIX = "_i";
 private static final String OUTGOING_CALL_SUFFIX = "_o";

 private Context cntx;
 private volatile String fileNamePrefix = IDLE;
 private volatile MediaRecorder recorder;
 private volatile PowerManager.WakeLock wakeLock;
 private volatile boolean isMounted = false;
 private volatile boolean isInRecording = false;

 @Override
 public IBinder onBind(Intent i) {
 return null;
 }

 @Override
 public void onCreate() {
 // TODO Auto-generated method stub
 super.onCreate();
 this.cntx = getApplicationContext();
 this.prepareAmrDir();
 log("service create");
 }

 @Override
 public void onDestroy() {
 log("service destory");
 this.stopRecording();
 this.cntx = null;
 super.onDestroy();
 }

 @Override
 public int onStartCommand(Intent intent, int flags, int startId) {
 if (null == intent || !ACTION.equals(intent.getAction())) {
 return super.onStartCommand(intent, flags, startId);
 }
 String state = intent.getStringExtra(STATE);
 String phoneNo = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
 log("state: " + state + " phoneNo: " + phoneNo);
 if (OUTGOING.equals(state)) {
 fileNamePrefix = getContactName(this.getContext(), phoneNo)
 + OUTGOING_CALL_SUFFIX;
 } else if (INCOMING.equals(state)) {
 fileNamePrefix = getContactName(this.getContext(), phoneNo)
 + INCOMING_CALL_SUFFIX;
 } else if (BEGIN.equals(state)) {
 startRecording();
 } else if (END.equals(state)) {
 stopRecording();
 } else if (STORAGE.equals(state)) {
 String mountState = Environment.getExternalStorageState();
 if (Environment.MEDIA_MOUNTED.equals(mountState)) {
 prepareAmrDir();
 } else {
 isMounted = false;
 }
 if (!isInRecording) {
 stopSelf();
 }
 }
 return START_STICKY;
 }

 public Context getContext() {
 return cntx;
 }

 private void stopRecording() {
 if (isInRecording) {
 isInRecording = false;
 recorder.stop();
 recorder.release();
 recorder = null;
 releaseWakeLock();
 stopSelf();
 log("call recording stopped");
 }
 }

 private String getDateTimeString() {
 SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd'_'HHmmss");
 Date now = new Date();
 return sdf.format(now);
 }

 private String getMonthString() {
 SimpleDateFormat sdf = new SimpleDateFormat("yyyyMM");
 Date now = new Date();
 return sdf.format(now);
 }

 private String getDateString() {
 SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
 Date now = new Date();
 return sdf.format(now);
 }

 private String getTimeString() {
 SimpleDateFormat sdf = new SimpleDateFormat("HHmmss");
 Date now = new Date();
 return sdf.format(now);
 }

 private void startRecording() {
 if (!isMounted)
 return;
 stopRecording();
 try {
 File amr = new File(Environment.getExternalStorageDirectory()
 .getAbsolutePath()
 + AMR_DIR
 + getDateTimeString()
 + "_"
 + fileNamePrefix + ".amr");
 log("Prepare recording in " + amr.getAbsolutePath());
 recorder = new MediaRecorder();
 recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
 recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
 recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
 recorder.setOutputFile(amr.getAbsolutePath());
 recorder.prepare();
 recorder.start();
 isInRecording = true;
 acquireWakeLock();
 log("Recording in " + amr.getAbsolutePath());
 } catch (Exception e) {
 Log.w(TAG, e);
 }
 }

 private void prepareAmrDir() {
 isMounted = Environment.getExternalStorageState().equals(
 Environment.MEDIA_MOUNTED);
 if (!isMounted)
 return;
 File amrRoot = new File(Environment.getExternalStorageDirectory()
 .getAbsolutePath() + AMR_DIR);
 if (!amrRoot.isDirectory())
 amrRoot.mkdir();
 }

 private String getContactName(Context cntx, String phoneNo) {
 if (null == phoneNo)
 return "";
 Uri uri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI,
 Uri.encode(phoneNo));
 ContentResolver cr = cntx.getContentResolver();
 Cursor c = cr.query(uri, new String[] { PhoneLookup.DISPLAY_NAME },
 null, null, null);
 if (null == c) {
 log("getContactName: The cursor was null when query phoneNo = "
 + phoneNo);
 return phoneNo;
 }
 try {
 if (c.moveToFirst()) {
 String name = c.getString(0);
 name = name.replaceAll("(\\||\\\\|\\?|\\*|<|:|\"|>)", "");
 log("getContactName: phoneNo: " + phoneNo + " name: " + name);
 return name;
 } else {
 log("getContactName: Contact name of phoneNo = " + phoneNo
 + " was not found.");
 return phoneNo;
 }
 } finally {
 c.close();
 }
 }

 private void log(String info) {
 if (DEBUG && isMounted) {
 File log = new File(Environment.getExternalStorageDirectory()
 .getAbsolutePath()
 + AMR_DIR
 + "log_"
 + getMonthString()
 + ".txt");
 try {
 BufferedWriter out = new BufferedWriter(new FileWriter(log,
 true));
 try {
 synchronized (out) {
 out.write(getDateString()+getTimeString());
 out.write(" ");
 out.write(info);
 out.newLine();
 }
 } finally {
 out.close();
 }
 } catch (IOException e) {
 Log.w(TAG, e);
 }
 }
 }

 private void acquireWakeLock() {
 if (wakeLock == null) {
 log("Acquiring wake lock");
 PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
 wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, this
 .getClass().getCanonicalName());
 wakeLock.acquire();
 }

 }

 private void releaseWakeLock() {
 if (wakeLock != null && wakeLock.isHeld()) {
 wakeLock.release();
 wakeLock = null;
 log("Wake lock released");
 }

 }
}

 

Receiver.java


package com.thul.CallRecorder;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.telephony.TelephonyManager;
import android.util.Log;

public class Receiver extends BroadcastReceiver {
 @Override
 public void onReceive(Context context, Intent intent) {
 if (null == intent)
 return;
 Intent i = new Intent(MainService.ACTION);
 if (Intent.ACTION_NEW_OUTGOING_CALL.equals(intent.getAction())) {
 i.putExtra(MainService.STATE, MainService.OUTGOING);
 i.putExtra(Intent.EXTRA_PHONE_NUMBER,
 intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER));
 } else if (TelephonyManager.ACTION_PHONE_STATE_CHANGED.equals(intent
 .getAction())) {
 String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
 if (TelephonyManager.EXTRA_STATE_RINGING.equals(state)) {
 i.putExtra(MainService.STATE,
 MainService.INCOMING);
 i.putExtra(Intent.EXTRA_PHONE_NUMBER, intent
 .getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER));
 } else if (TelephonyManager.EXTRA_STATE_OFFHOOK.equals(state)) {
 i.putExtra(MainService.STATE, MainService.BEGIN);
 } else if (TelephonyManager.EXTRA_STATE_IDLE.equals(state)) {
 i.putExtra(MainService.STATE, MainService.END);
 }
 } else if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {
 i.putExtra(MainService.STATE, MainService.START);
 } else if (intent.getAction().equals(Intent.ACTION_MEDIA_MOUNTED)
 || intent.getAction().equals(Intent.ACTION_MEDIA_REMOVED)) {
 i.putExtra(MainService.STATE, MainService.STORAGE);
 } else {
 return;
 }
 context.startService(i);
 Log.d(MainService.TAG,
 "AutoRunReceiver startService "
 + i.getStringExtra(MainService.STATE) + ":"
 + i.getStringExtra(Intent.EXTRA_PHONE_NUMBER));
 }
}

 

Layout: Main.xml

<?xml version="1.0" encoding="utf-8"?>
<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/btnStartStop"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:text="@string/start_record" />

</LinearLayout>

 

AndroidManifest.xml

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

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

 <uses-permission android:name="android.permission.READ_PHONE_STATE" />
 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
 <uses-permission android:name="android.permission.RECORD_AUDIO" />
 <uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
 <uses-permission android:name="android.permission.READ_CONTACTS" />
 <uses-permission android:name="android.permission.WAKE_LOCK"/>
 <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

 <application
 android:icon="@drawable/ic_launcher"
 android:label="@string/app_name" >
 <activity
 android:name="com.thul.CallRecorder.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>

 <service android:name="com.thul.CallRecorder.MainService" >
 <intent-filter>
 <action android:name="com.thul.CallRecorder.CALL_RECORD" />
 </intent-filter>
 </service>

 <receiver
 android:name="com.thul.CallRecorder.Receiver"
 android:enabled="true"
 android:exported="true" >
 <intent-filter>
 <action android:name="android.intent.action.NEW_OUTGOING_CALL" />
 <action android:name="android.intent.action.PHONE_STATE" />
 <action android:name="android.intent.action.BOOT_COMPLETED" />
 <action android:name="android.intent.action.MEDIA_MOUNTED" />
 <action android:name="android.intent.action.MEDIA_REMOVED" />
 </intent-filter>
 </receiver>
 </application>

</manifest>