Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
MANDALS
K.M.C COLLEGE, KHOPOLI
DEPARTMENT OF COMPUTER SCIENCE
KHOPOLI-410203
A
PROJECT REPORT
ON
Call Recorder
UNDER THE GUIDANCE
OF
UNIVERSITY OF MUMBAI
BY
Mr. KAMBLE PRATIK RAMESH.
M.SC.Part-II (COMPUTER SCIENCE)
2014-2015
Acknowledgement
My accomplishment would be incomplete without mentioning the efforts
taken by all my mentors. I am grateful to them for their continual support, cooperation and guidance which have encouraged me to complete my project
successfully and in due time. I hereby take opportunity to express my gratitude
for their invaluable guidance and support.
Mr.
Kamble Pratik R.
INDEX
INDEX
Sr. No
1.
Description
PRELIMINARY INVESTIGATION
2.
3.
Event Table
Use Case Diagram
Activity Diagram
Class Diagram
Sequence Diagram
State Diagram
Test Cases
Program Listing
1)
2)
3)
4)
1)
2)
3)
4)
5)
6)
7)
1) Forms Designing
2) Forms Designing With Their Code
Page no.
6-16
17-25
26-49
4.
Future Enhancement
50
5.
51
Preliminary
5
Investigation
DISCRIPTION
This is Call Recorder application. It is a fully developed in Android
Studio. When one person call to another person automatically call
will be recorded. Only one thing we have to do, just enable check
mark of the Records calls. So in an entire day whatever outgoing call
we make or we get incoming call, All conversation will be recorded.
Many android phone does not support this facility, and those
who have ,first they must have to click record option, then call will be
recorded.
There is an menu of audio source type, by clicking that we get
a different option like mic, voice_call, voice_uplink, voice_downlink.
So we can choose one of them, by default mice option is selected.
There is another menu for recording file format such as, Mp4,
3Gp and amr. So we can choose one of them. By default mp4 is
selected. These menus are present in preference button.
And all recorded call will be save in call log. When we click on call
log button we get a list of recorded call.
It is best use to make security.
LIMITATION
There is memory problem will cause due to save large amount of call
recording .
If we not enable the check mark of records calls, then calls will not be
recorded.
1)
PROPOSED SYSTEM
This is Call Recorder application. It is a fully developed in Android
Studio. When one person call to another person automatically call
will be recorded. Only one think we have to do, just enable check
mark of the Records calls. So in an entire day whatever outgoing call
we make or we get incoming call. All conversation will be recorded.
There is an menu of audio source type, by clicking that we get
a different option like mic, voice_call, voice_uplink, voice_downlink.
So we can choose one of them, by default mice option is selected.
There is another menu for recording file format such as, Mp4,
3Gp and amr. So we can choose one of them. By default mp4 is
selected. These menus are present in preference button.
And all recorded call will be save in call log. When we click on call
log button we get a list of recorded call.
It is best use to make security.
Some Methods
onCreate():This is the first callback and called when the activity is first
created.
onStart():This callback is called when the activity becomes visible to the
user.
onResume():This is called when the user starts interacting with the
application.
onPause():The paused activity does not receive user input and cannot
execute any code and called when the current activity is being paused and
the previous activity is being resumed.
onStop():This callback is called when the activity is no longer visible.
onDestroy():This callback is called before the activity is destroyed by the
system.
onRestart():This callback is called when the activity restarts after
stopping it
onStartCommand():The system calls this method when another
component, such as an activity, requests that the service be started, by
calling
startService():If you implement this method, it is your responsibility to
stop the service when its work is done, by calling stopSelf() or
stopService() methods.
onBind():The system calls this method when another component wants
to bind with the service by calling
bindService(): If you implement this method, you must provide an
interface that
clients use to communicate with the service, by returning an IBinder
object. You must always implement this method, but if you don't want to
allow binding, then you should return null.
onUnbind():The system calls this method when all clients have
disconnected from a
particular interface published by the service.
onRebind():The system calls this method when new clients have
connected to the service, after it had previously been notified that all had
disconnected in its onUnbind(Intent)
onCreate():The system calls this method when the service is first created
using onStartCommand() or onBind(). This call is required to perform onetime setup.
onDestroy():The system calls this method when the service is no longer
used and is being destroyed. Your service should implement this to clean
up any resources such as threads, registered listeners, receivers, etc.
10
onClick():OnClickListener()
This is called when the user either clicks or touches or focuses upon
any widget like button, text, image etc. You will use onClick() event
handler to handle such event.
onLongClick():OnLongClickListener()
This is called when the user either clicks or touches or focuses upon any
widget like button, text, image etc. for one or more seconds.You will use
onLongClick() event handler to handle such event.
onFocusChange():OnFocusChangeListener()
This is called when the widget looses its focus ie. user goes away from
the view item. You will use onFocusChange() event handler to handle
such event.
onKey():OnFocusChangeListener()
This is called when the user is focused on the item and presses or releases
a hardware key on the device. You will use onKey() event handler to
handle such event.
onTouch():OnTouchListener()
This is called when the user presses the key, releases the key, or any
movement gesture on the screen. You will use onTouch() event handler to
handle such event.
SQLite:This open-source relational database engine is designed to be embedded in devices.
11
ADVANTAGES
1) It is best use for security purpose .
2) Even caller does not know that his call is recording.
3) All recording process happens in background, so it is safe.
12
DISADVANTAGES
There is memory problem will cause due to save large amount of call
recording.
If we not enable the check mark of records calls, then calls will not be
recorded.
13
Hardware:
Utility
Software:
Operating System
Supported Software
Front End
:
Windows XP,Windows 7,windows 8.
: JDK 1.7,1.8,Android SDK
: Android studio.
14
TESTING METHODOLOGY
For testing purpose we have used white - box method - a widely used
Technique in which path of logic are tested to determine how well they
produce predictable results . With this commonly used tested technique,
We have examined the internal structure of the object.
With the help of white box testing we have tested the source code without
taking into account the external description for that source code. Because of
the use of this testing method we came to know about the unintentional
items such as infinite loops, path through the code which should be allowed
but
which cannot be executed and dead (unreachable) code.
15
The key points that we have considered in white box technique are as
follows
Path Testing :
In this we have tested every possible path in the code i.e. all condition to assure that
Every line of code is working properly.
Condition Testing:
In this we have tested for errors in condition ( Boolean, Arithmetic / Relational errors)
Loop Testing:
In this we have checked the validity of the loop constructs.
16
SYSTEM
ANALYSIS
17
EVENT TABLE
The Event includes row and columns, representing events and
their details effectively. Each row in the table records information
about each event. Each column in the table represents key
information about that event.
EVENT
TRIGGER
SOURCE
ACTIVITY
RESPONSE
DESTINATION
Person
make a
outgoing
call
Person
make a
outgoing
call
Person
receive
call
calling
Person
Recording
call
Call is
recorded
On person device
calling
Person
Buzy tone
Call is not
recorded
On person device
Receive call
Person
Recording
call
Call is
recorded
On person device
18
Make a call
Ringing
Recording started
Person
Person
Device
End call
19
Activity Diagram
Person
Make a outgoing
call
Receiver
Ringing
Check available
NO
YES
Start recording on
person device
End call
Stop Recording
Save recording
20
Class Diagram
AudioPlayerControl
CallBroadcastReceiver
pause()
start()
destroy()
seekTo(int pos)
isPlaying()
getDuration()
onReceive()
getAction()
CallLog
CallPlayer
clear()
moveToFirst()
loadRecordingsFromDir()
1
onCreate()
onStart()
onRestart()
onResume()
playFile(String fName)
onDestroy()
getIntent()
onDestroy()
onPrepared(MediaPlayer mp)
setMediaPlayer(aplayer)
onCompletion(MediaPlayer mp)
PlayService
CallRecorder
onCreate(Bundle
savedInstanceState)
getTabHost()
setText(label)
onCreate()
reset()
setAudioStreamType()
onDestroy()
onBind()
onRebind
21
Sequence Diagram
Preferences
onCreate(Bundle
savedInstanceStat
: Receiver
e)
: Caller Person
person
22
State Diagram
End call
Check
Availablity
Yes
Start Recording
If End call
No
Still recording a
call
23
Yes
Test Cases:
Stop
recording
and save
Test ID
:-01
:- Unit Testing
Test Type
Purpose Of Test
Testing Objects
:- Preference Button
Focus of Testing
Start Condition
Initiation
Attributes
24
25
26
27
28
29
Coding:
Android manifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.talentcodeworks.callrecorder"
android:versionCode="1"
android:versionName="1.0">
<uses-sdk android:minSdkVersion="4"/>
<uses-permission
android:name="android.permission.PROCESS_OUTGOING_CALLS"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<application android:label="@string/app_name" android:icon="@drawable/icon">
<provider android:name=".RecordingProvider"
android:authorities="com.talentcodeworks.callrecorder" />
<receiver android:name=".CallBroadcastReceiver"
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" />
<!-- <category android:name="android.intent.category.LAUNCHER" /> -->
</intent-filter></receiver>
<activity android:name=".CallRecorder"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter> </activity>
<activity android:name=".CallLog"
android:label="CallLog">
</activity>
<activity android:name=".CallPlayer"
30
android:label="CallPlayer">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<data android:mimeType="audio/*" />
</intent-filter>
</activity> <activity android:name=".Preferences">
<intent-filter>
<action
android:name="com.talentcodeworks.callrecorder.ACTION_USER_PREFERENCE" />
</intent-filter></activity>
<service android:name=".RecordService">
</service> <service android:name=".PlayService"></service></application></manifest>
AudioPlaye Control.java
package com.talentcodeworks.callrecorder;
import android.media.MediaPlayer;
import android.widget.MediaController;
import android.net.Uri;
import android.util.Log;
import android.widget.LinearLayout;
class AudioPlayerControl
implements MediaController.MediaPlayerControl
{
private static final String TAG = "CallRecorder";
private MediaPlayer player = null;
private String path = null;
public AudioPlayerControl(String path, CallPlayer listenerActivity)
throws java.io.IOException
{
Log.i(TAG, "AudioPlayerControl constructed with path " + path);
this.path = path;
player = new MediaPlayer();
player.setDataSource(path);
player.setOnPreparedListener(listenerActivity);
player.setOnInfoListener(listenerActivity);
player.setOnErrorListener(listenerActivity);
player.setOnCompletionListener(listenerActivity);
player.prepareAsync();
}
public boolean canPause() { return true; }
public boolean canSeekBackward() { return true; }
public boolean canSeekForward() { return true; }
@Override
public int getAudioSessionId() {
return 0;
}
public int getBufferPercentage() {
Log.d(TAG, "AudioPlayerControl::getBufferPercentage returning 100");
return 100;
31
}
public int getCurrentPosition() {
int pos = player.getCurrentPosition();
Log.d(TAG, "AudioPlayerControl::getCurrentPosition returning " + pos);
return pos;
}
public int getDuration() {
int duration = player.getDuration();
Log.d(TAG, "AudioPlayerControl::getDuration returning " + duration);
return duration;
}
public boolean isPlaying() {
boolean isp = player.isPlaying();
Log.d(TAG, "AudioPlayerControl::isPlaying returning " + isp);
return isp;
}
public void pause() {
Log.d(TAG, "AudioPlayerControl::pause");
player.pause();
}
public void seekTo(int pos) {
Log.d(TAG, "AudioPlayerControl::seekTo " + pos);
player.seekTo(pos);
}
public void start() {
Log.d(TAG, "AudioPlayerControl::start");
player.start();
}
public void destroy() {
Log.i(TAG, "AudioPlayerControll::destroy shutting down player");
if (player != null) {
player.reset();
player.release();
player = null;
}
}
}
CallLog.java
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;
import android.app.Activity;
import android.content.SharedPreferences;
import android.content.Intent;
import android.content.Context;
import android.content.SharedPreferences.Editor;
32
import android.content.ComponentName;
import android.content.ContentResolver;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.View;
import android.widget.ListView;
import android.widget.MediaController;
import android.widget.ArrayAdapter;
import android.widget.AdapterView;
public class CallLog
extends Activity
{
private final String TAG = "CallRecorder";
private ListView fileList = null;
private ArrayAdapter<String> fAdapter = null;
private ArrayList<String> recordingNames = null;
private MediaController controller = null;
private void loadRecordingsFromProvider()
{
fAdapter.clear();
ContentResolver cr = getContentResolver();
Cursor c = cr.query(RecordingProvider.CONTENT_URI, null, null, null, null);
String[] names = new String[c.getCount()];
int i = 0;
if (c.moveToFirst()) {
do {
fAdapter.add(c.getString(RecordingProvider.DETAILS_COLUMN));
i++;
} while (c.moveToNext());
}
fAdapter.notifyDataSetChanged();
}
private void loadRecordingsFromDir()
{
fAdapter.clear();
File dir = new File(RecordService.DEFAULT_STORAGE_LOCATION);
String[] dlist = dir.list();
for (int i=0; i<dlist.length; i++) {
fAdapter.add(dlist[i]);
}
fAdapter.notifyDataSetChanged();
}
33
}
private void playFile(String fName) {
Log.i(TAG, "playFile: " + fName);
Context context = getApplicationContext();
Intent playIntent = new Intent(context, PlayService.class);
playIntent.putExtra(PlayService.EXTRA_FILENAME,
RecordService.DEFAULT_STORAGE_LOCATION + "/" + fName);
ComponentName name = context.startService(playIntent);
if (null == name) {
Log.w(TAG, "CallLog unable to start PlayService with intent: " +
playIntent.toString());
} else {
Log.i(TAG, "CallLog started service: " + name);
}
}
public void onDestroy() {
Context context = getApplicationContext();
Intent playIntent = new Intent(context, PlayService.class);
context.stopService(playIntent);
super.onDestroy();
}
}
CallPlayer.java
import java.io.File;
import android.app.Activity;
import android.content.SharedPreferences;
import android.content.Intent;
import android.content.Context;
import android.content.SharedPreferences.Editor;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.database.Cursor;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.MediaController;
import android.widget.Toast;
public class CallPlayer
extends Activity
implements MediaPlayer.OnPreparedListener, MediaPlayer.OnInfoListener,
MediaPlayer.OnErrorListener, MediaPlayer.OnCompletionListener
{
private static final String TAG = "CallRecorder";
35
PlayService.java
import java.io.File;
import java.io.IOException;
import java.lang.Exception;
import android.os.IBinder;
import android.app.Service;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.widget.Toast;
import android.util.Log;
38
import java.io.InputStream;
import java.io.FileInputStream;
import java.util.Iterator;
public class PlayService
extends Service
implements MediaPlayer.OnCompletionListener, MediaPlayer.OnInfoListener,
MediaPlayer.OnErrorListener
{
private static String TAG = "CallRecorder";
public static final String EXTRA_FILENAME = "filename";
private MediaPlayer player = null;
private boolean isPlaying = false;
private String recording = null;
public void onCreate()
{
super.onCreate();
player = new MediaPlayer();
player.setOnCompletionListener(this);
player.setOnInfoListener(this);
player.setOnErrorListener(this);
Log.i(TAG, "PlayService::onCreate created MediaPlayer object");
}
public void onStart(Intent intent, int startId) {
Log.i(TAG, "PlayService::onStart called while isPlaying:" + isPlaying);
if (isPlaying) return;
Context c = getApplicationContext();
recording = intent.getStringExtra(EXTRA_FILENAME);
if (recording == null) {
Log.w(TAG, "PlayService::onStart recording == null, returning");
return;
}
Log.i(TAG, "PlayService will play " + recording);
try {
player.reset();
player.setAudioStreamType(AudioManager.STREAM_VOICE_CALL);
player.setDataSource(recording);
player.setLooping(false);
player.prepare();
Log.d(TAG, "PlayService player.prepare() returned");
player.start();
isPlaying = true;
Log.i(TAG, "player.start() returned");
} catch (java.io.IOException e) {
Log.e(TAG, "PlayService::onStart() IOException attempting player.prepare()\n");
Toast t = Toast.makeText(getApplicationContext(), "PlayService was unable to start
playing recording: " + e, Toast.LENGTH_LONG);
t.show();
return;
} catch (java.lang.Exception e) {
39
Preferences.java
40
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceActivity;
public class Preferences extends PreferenceActivity
{
static public final String PREF_RECORD_CALLS = "PREF_RECORD_CALLS";
static public final String PREF_AUDIO_SOURCE = "PREF_AUDIO_SOURCE";
static public final String PREF_AUDIO_FORMAT = "PREF_AUDIO_FORMAT";
SharedPreferences prefs;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.userpreferences);
}
}
RecordService.java
import java.io.File;
import java.io.IOException;
import java.lang.Exception;
import java.util.Date;
import java.text.SimpleDateFormat;
import android.os.IBinder;
import android.app.Service;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.preference.PreferenceManager;
import android.content.SharedPreferences;
import android.content.Context;
import android.content.Intent;
import android.media.MediaRecorder;
import android.widget.Toast;
import android.util.Log;
import java.io.InputStream;
import java.io.FileInputStream;
import java.util.Iterator;
public class RecordService
extends Service
implements MediaRecorder.OnInfoListener, MediaRecorder.OnErrorListener
{
private static final String TAG = "CallRecorder";
public static final String DEFAULT_STORAGE_LOCATION = "/sdcard/callrecorder";
41
} catch (IOException e) {
Log.e("CallRecorder", "RecordService::makeOutputFile unable to create temp file in
" + dir + ": " + e);
Toast t = Toast.makeText(getApplicationContext(), "CallRecorder was unable to
create temp file in " + dir + ": " + e, Toast.LENGTH_LONG);
t.show();
return null;
}
}
public void onCreate()
{
super.onCreate();
recorder = new MediaRecorder();
Log.i("CallRecorder", "onCreate created MediaRecorder object");
}
public void onStart(Intent intent, int startId) {
Log.i("CallRecorder", "RecordService::onStartCommand called while isRecording:" +
isRecording);
if (isRecording) return;
Context c = getApplicationContext();
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(c);
Boolean shouldRecord = prefs.getBoolean(Preferences.PREF_RECORD_CALLS,
false);
if (!shouldRecord) {
Log.i("CallRecord", "RecordService::onStartCommand with
PREF_RECORD_CALLS false, not recording");
return;
}
int audiosource =
Integer.parseInt(prefs.getString(Preferences.PREF_AUDIO_SOURCE, "1"));
int audioformat =
Integer.parseInt(prefs.getString(Preferences.PREF_AUDIO_FORMAT, "1"));
recording = makeOutputFile(prefs);
if (recording == null) {
recorder = null;
return; //return 0;
}
Log.i("CallRecorder", "RecordService will config MediaRecorder with audiosource: " +
audiosource + " audioformat: " + audioformat);
try {
recorder.reset();
recorder.setAudioSource(audiosource);
Log.d("CallRecorder", "set audiosource " + audiosource);
recorder.setOutputFormat(audioformat);
Log.d("CallRecorder", "set output " + audioformat);
recorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);
43
44
45
android:layout_height="fill_parent" />
</LinearLayout>
Preferences.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/recording_enabled_prompt"/>
<CheckBox android:id="@+id/check_recording_enabled"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/audio_source_prompt"/>
<Spinner android:id="@+id/spinner_audio_source"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:drawSelectorOnTop="true"/>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/audio_format_prompt"/>
<Spinner android:id="@+id/spinner_audio_format"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:drawSelectorOnTop="true"/>
<Button android:id="@+id/save_prefs"
android:text="Save"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</RelativeLayout> Tab_indicator.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="0px"
android:layout_height="wrap_content"
android:layout_weight="1">
<TextView android:id="@+id/tab_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hmm"
47
android:layout_centerInParent="true" />
</RelativeLayout>
Values
Arrays.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="audio_source_options">
<item>MIC</item>
<item>VOICE_CALL</item>
<item>VOICE_UPLINK</item>
<item>VOICE_DOWNLINK</item>
</string-array>
<string-array name="audio_source_values">
<item>1</item>
<item>4</item>
<item>2</item>
<item>3</item>
</string-array>
<string-array name="audio_format_options">
<item>MPEG_4</item>
<item>RAW_AMR</item>
<item>THREE_GPP</item>
</string-array>
<string-array name="audio_format_values">
<item>2</item>
<item>3</item>
<item>1</item>
</string-array>
</resources>
Strings.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">CallRecorder</string>
<string name="recording_enabled_prompt">Record during calls</string>
<string name="audio_source_prompt">Audio source</string>
<string name="audio_format_prompt">Audio format</string>
</resources>
Xml
Userpreferences.xml
<?xml version="1.0" encoding="utf-8"?>
48
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android">
<CheckBoxPreference
android:key="PREF_RECORD_CALLS"
android:title="Record calls"
android:summary="Select to turn on recording of all calls"
android:defaultValue="true" />
<ListPreference
android:key="PREF_AUDIO_SOURCE"
android:title="Audio source"
android:summary="Select the audio source to record from during calls"
android:entries="@array/audio_source_options"
android:entryValues="@array/audio_source_values"
android:dialogTitle="Audio source"
android:defaultValue="1" />
<ListPreference
android:key="PREF_AUDIO_FORMAT"
android:title="Recording file format"
android:summary="Select the file format to use for call recordings"
android:entries="@array/audio_format_options"
android:entryValues="@array/audio_format_values"
android:dialogTitle="Audio format"
android:defaultValue="1" />
</PreferenceScreen>
Callrecorder-master.iml
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="android" name="Android">
<configuration />
</facet>
</component>
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/gen" isTestSource="false"
generated="true"/>
</content>
<orderEntry type="jdk" jdkName="Android API 21 Platform" jdkType="Android SDK" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
49
Future Enhancements
Number of call records will be unlimited to be stored in the mobile or can
be able to upload in cloud.
GUI can be increase to look more attractive.
50
Web sites:
www.tutorialspoint.com
www.google.com
51