Sei sulla pagina 1di 52

K.T.S.P.

MANDALS
K.M.C COLLEGE, KHOPOLI
DEPARTMENT OF COMPUTER SCIENCE
KHOPOLI-410203
A
PROJECT REPORT
ON

Call Recorder
UNDER THE GUIDANCE
OF

Miss. Shipra Dutta & Miss. Priyanka Sorte


SUBMITTED
TO

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.

This is my first milestone in M.Sc-II Computer Science. I would like


to thank our Principal Mr. N. B. Pawar Sir and Prof. Mr. P. P.
Wadkar (H.O.D. of Computer Science), who helped me throughout
the project.
At the outset, I would like to thank all teachers who help me
throughout the project. I would also especially like to acknowledge the help
and guidance provided by Prof. Miss. Shipra Dutta &
Prof. Miss. Priyanka Sorte in all place during the presentation of this projects
I would like to express my thanks to my family and all my friends who have
encouraged and motivated me throughout the project.
Thanking you.

Mr.
Kamble Pratik R.

M.sc-Part-II (Computer Science)

INDEX

INDEX
Sr. No
1.

Description
PRELIMINARY INVESTIGATION

2.

Description & Limitations


Proposed System
Some Methods, Event listener & Handler
Advantage
Disadvantage
5) System Implementation Hardware and Software
Used
6) Testing Methodology
System Analysis

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.

References And Bibliography

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

Event Listeners & Event Handlers

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 AND SOFTWARE USED

Hardware:
Utility

Samsung laptop, one android phone.

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)

Data Flow Testing:


In this have tested path according to location of definitions and their users .

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

USE CASE DIAGRAM

Make a call

Ringing

Receiver receive a call

Recording started

Person

Person
Device
End call

Recording will stop

Save recording in call log

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

Make a outgoing call


Check availability

If available pickup the call


Start recording conversation
End a call and Stop recording
If not available
End a call without recording

22

State Diagram

Make a outgoing call


No

End call

Check
Availablity
Yes

Start Recording

If End call
No

Still recording a
call

23

Yes

Test Cases:

Stop
recording
and save

--:Preference Button :--

Test ID

:-01

Test Case Name

:- Unit Testing

Test Type

:- Black Box Testing

Purpose Of Test

:- for getting correct output

Testing Objects

:- Preference Button

Focus of Testing

:- to check it is working fine or not


--: Test Process:--

Start Condition

:- call recorder app should be present with


preference button.

Initiation

:- for initiation must be able to do following


thing

Attributes

: - 1)in Record calls must able to mark on checkbox.


2)in audio source tab at least one option
one option should be selected.
3)Recording file format at least one option
should be selected.

24

--: Test Case :-TC1)


1) Preferences Button: check mark Expected in records calls:
If checkmark is enable call will be recorded
Expected Failure:If checkmark is disable call will not be recorded

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 class CallItemClickListener implements AdapterView.OnItemClickListener {


@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id)
{
CharSequence s = (CharSequence)parent.getItemAtPosition(position);
Log.w(TAG, "CallLog just got an item clicked: " + s);
File f = new File(RecordService.DEFAULT_STORAGE_LOCATION + "/" +
s.toString());
boolean useMediaController = true;
if (useMediaController) {
Intent playIntent = new Intent(getApplicationContext(), CallPlayer.class);
Uri uri = Uri.fromFile(f);
playIntent.setData(uri);
startActivity(playIntent);
} else {
playFile(s.toString());
}
}
}
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.call_log);
fileList = (ListView)findViewById(R.id.play_file_list);
Context context = getApplicationContext();
fAdapter = new ArrayAdapter<String>(context, android.R.layout.simple_list_item_1);
fileList.setAdapter(fAdapter);
fileList.setOnItemClickListener(new CallItemClickListener());
}
public void onStart()
{
super.onStart();
Log.i(TAG, "CallLog onStart");
}

public void onRestart()


{
super.onRestart();
Log.i(TAG, "CallLog onRestart");
}
public void onResume()
{
super.onResume();
Log.i(TAG, "CallLog onResume about to load recording list again, does this work?");
loadRecordingsFromDir();
34

}
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

private AudioPlayerControl aplayer = null;


private MediaController controller = null;
private ViewGroup anchor = null;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.player);
anchor = (ViewGroup)findViewById(R.id.playerlayout);
if (aplayer != null) {
Log.i(TAG, "CallPlayer onCreate called with aplayer already allocated, destroying old
one.");
aplayer.destroy();
aplayer = null;
}
if (controller != null) {
Log.i(TAG, "CallPlayer onCreate called with controller already allocated, destroying
old one.");
controller = null;
}
Intent i = getIntent();
String path = i.getData().getEncodedPath();
Log.i(TAG, "CallPlayer onCreate with data: " + path);
try {
aplayer = new AudioPlayerControl(path, this);
} catch (java.io.IOException e) {
Log.e(TAG, "CallPlayer onCreate failed while creating AudioPlayerControl", e);
Toast t = Toast.makeText(this, "CallPlayer received error attempting to create
AudioPlayerControl: " + e, Toast.LENGTH_LONG);
t.show();
finish();
}
}
public void onDestroy() {
Log.i(TAG, "CallPlayer onDestroy");
if (aplayer != null) {
aplayer.destroy();
aplayer = null;
}
super.onDestroy();
}
private class MyMediaController extends MediaController
{
public MyMediaController(Context c, boolean ff) {
super(c, ff);
}
}
public void onPrepared(MediaPlayer mp)
{
Log.i(TAG, "CallPlayer onPrepared about to construct MediaController object");
36

controller = new MediaController(this, true);


controller.setMediaPlayer(aplayer);
controller.setAnchorView(anchor);
controller.setEnabled(true);
controller.show(0); //aplayer.getDuration());
}
public boolean onInfo(MediaPlayer mp, int what, int extra)
{
Log.i(TAG, "CallPlayer onInfo with what " + what + " extra " + extra);
return false;
}
public boolean onError(MediaPlayer mp, int what, int extra)
{
Log.e(TAG, "CallPlayer onError with what " + what + " extra " + extra);
Toast t = Toast.makeText(this, "CallPlayer received error (what:" + what + " extra:" +
extra + ") from MediaPlayer attempting to play ", Toast.LENGTH_LONG);
t.show();
finish();
return true;
}
public void onCompletion(MediaPlayer mp)
{
Log.i(TAG, "CallPlayer onCompletion, finishing activity");
finish();
}
}
CallRecorder.java
import android.app.TabActivity;
import android.os.Bundle;
import android.util.Log;
import android.content.Intent;
import android.view.View;
import android.view.Menu;
import android.content.ComponentName;
import android.content.Context;
import android.view.View;
import android.view.LayoutInflater;
import android.widget.LinearLayout;
import android.widget.TabHost;
import android.widget.TextView;
public class CallRecorder
extends TabActivity
{
private static final int MENU_UPDATE = Menu.FIRST;
private static final int MENU_PREFERENCES = Menu.FIRST+1;
private static final int SHOW_PREFERENCES = 1;
37

private static final String[] TABS = { "Preferences", "CallLog" };


@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
setDefaultTab(0);
TabHost tabs = getTabHost();
for (int i=0; i<TABS.length; i++) {
TabHost.TabSpec tab = tabs.newTabSpec(TABS[i]);
ComponentName n = new ComponentName("com.talentcodeworks.callrecorder",
"com.talentcodeworks.callrecorder." + TABS[i]);
tab.setContent(new Intent().setComponent(n));
tab.setIndicator(TABS[i]);
tabs.addTab(tab);
}
}
public static class MyTabIndicator extends LinearLayout
{
public MyTabIndicator(Context context, String label)
{
super(context);
View tab = LayoutInflater.from(context).inflate(R.layout.tab_indicator, this);
TextView tv = (TextView)tab.findViewById(R.id.tab_label);
tv.setText(label);
}
}
}

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

Toast t = Toast.makeText(getApplicationContext(), "CallRecorder was unable to start


playing recording: " + e, Toast.LENGTH_LONG);
t.show();
Log.e(TAG, "PlayService::onStart caught unexpected exception", e);
}
return;
}
public void onDestroy()
{
if (null != player) {
Log.i(TAG, "PlayService::onDestroy calling player.release()");
isPlaying = false;
player.release();
}
super.onDestroy();
}
public IBinder onBind(Intent intent)
{
return null;
}
public boolean onUnbind(Intent intent)
{
return false;
}
public void onRebind(Intent intent)
{
}
public void onCompletion(MediaPlayer mp)
{
Log.i(TAG, "PlayService got MediaPlayer onCompletion callback");
isPlaying = false;
}
public boolean onInfo(MediaPlayer mp, int what, int extra)
{
Log.i(TAG, "PlayService got MediaPlayer onInfo callback with what: " + what + "
extra: " + extra);
return false;
}
public boolean onError(MediaPlayer mp, int what, int extra)
{
Log.e(TAG, "PlayService got MediaPlayer onError callback with what: " + what + "
extra: " + extra);
isPlaying = false;
mp.reset();
return true;
}
}

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

private static final int RECORDING_NOTIFICATION_ID = 1;


private MediaRecorder recorder = null;
private boolean isRecording = false;
private File recording = null;;
private File makeOutputFile (SharedPreferences prefs)
{
File dir = new File(DEFAULT_STORAGE_LOCATION);
if (!dir.exists()) {
try {
dir.mkdirs();
} catch (Exception e) {
Log.e("CallRecorder", "RecordService::makeOutputFile unable to create directory
" + dir + ": " + e);
Toast t = Toast.makeText(getApplicationContext(), "CallRecorder was unable to
create the directory " + dir + " to store recordings: " + e, Toast.LENGTH_LONG);
t.show();
return null;
}
} else {
if (!dir.canWrite()) {
Log.e(TAG, "RecordService::makeOutputFile does not have write permission for
directory: " + dir);
Toast t = Toast.makeText(getApplicationContext(), "CallRecorder does not have
write permission for the directory directory " + dir + " to store recordings",
Toast.LENGTH_LONG);
t.show();
return null;
}
}
int audiosource =
Integer.parseInt(prefs.getString(Preferences.PREF_AUDIO_SOURCE, "1"));
prefix += "-channel" + audiosource + "-";
String suffix = "";
int audioformat =
Integer.parseInt(prefs.getString(Preferences.PREF_AUDIO_FORMAT, "1"));
switch (audioformat) {
case MediaRecorder.OutputFormat.THREE_GPP:
suffix = ".3gpp";
break;
case MediaRecorder.OutputFormat.MPEG_4:
suffix = ".mpg";
break;
case MediaRecorder.OutputFormat.RAW_AMR:
suffix = ".amr";
break;
}
try {
return File.createTempFile(prefix, suffix, dir);
42

} 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

Log.d("CallRecorder", "set encoder default");


recorder.setOutputFile(recording.getAbsolutePath());
Log.d("CallRecorder", "set file: " + recording);
recorder.setOnInfoListener(this);
recorder.setOnErrorListener(this);
try {
recorder.prepare();
} catch (java.io.IOException e) {
Log.e("CallRecorder", "RecordService::onStart() IOException attempting
recorder.prepare()\n");
Toast t = Toast.makeText(getApplicationContext(), "CallRecorder was unable to
start recording: " + e, Toast.LENGTH_LONG);
t.show();
recorder = null;
return; //return 0; //START_STICKY;
}
Log.d("CallRecorder", "recorder.prepare() returned");
recorder.start();
isRecording = true;
Log.i("CallRecorder", "recorder.start() returned");
updateNotification(true);
} catch (java.lang.Exception e) {
Toast t = Toast.makeText(getApplicationContext(), "CallRecorder was unable to start
recording: " + e, Toast.LENGTH_LONG);
t.show();
Log.e("CallRecorder", "RecordService::onStart caught unexpected exception", e);
recorder = null;
}
return; //return 0; //return START_STICKY;
}
public void onDestroy()
{
super.onDestroy();
if (null != recorder) {
Log.i("CallRecorder", "RecordService::onDestroy calling recorder.release()");
isRecording = false;
recorder.release();
Toast t = Toast.makeText(getApplicationContext(), "CallRecorder finished recording
call to " + recording, Toast.LENGTH_LONG);
t.show();
}
updateNotification(false);
}
public IBinder onBind(Intent intent)
{
return null;
}

44

public boolean onUnbind(Intent intent)


{
return false;
}
public void onRebind(Intent intent) { }
private void updateNotification(Boolean status)
{
Context c = getApplicationContext();
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(c);
String ns = Context.NOTIFICATION_SERVICE;
NotificationManager mNotificationManager = (NotificationManager)
getSystemService(ns);
if (status) {
int icon = R.drawable.rec;
CharSequence tickerText = "Recording call from channel " +
prefs.getString(Preferences.PREF_AUDIO_SOURCE, "1");
long when = System.currentTimeMillis();
Notification notification = new Notification(icon, tickerText, when);
Context context = getApplicationContext();
CharSequence contentTitle = "CallRecorder Status";
CharSequence contentText = "Recording call from channel...";
Intent notificationIntent = new Intent(this, RecordService.class);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
notification.setLatestEventInfo(context, contentTitle, contentText, contentIntent);
mNotificationManager.notify(RECORDING_NOTIFICATION_ID, notification);
} else {
mNotificationManager.cancel(RECORDING_NOTIFICATION_ID);
}
}
public void onInfo(MediaRecorder mr, int what, int extra)
{
Log.i("CallRecorder", "RecordService got MediaRecorder onInfo callback with what: "
+ what + " extra: " + extra);
isRecording = false;
}
public void onError(MediaRecorder mr, int what, int extra)
{
Log.e("CallRecorder", "RecordService got MediaRecorder onError callback with what:
" + what + " extra: " + extra);
isRecording = false;
mr.release();
}
}

Coding for layout design


Call_log.xml

45

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


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:scrollbars="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Select file to play" />
<ListView
android:choiceMode="singleChoice"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/play_file_list" />
</LinearLayout>
Main.xml
<?xml version="1.0" encoding="utf-8"?>
<TabHost xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/tabhost"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<LinearLayout android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<FrameLayout android:id="@android:id/tabcontent"
android:layout_width="fill_parent"
android:layout_height="0px"
android:layout_weight="1"/>
<TabWidget android:id="@android:id/tabs"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
</TabHost>
Player.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/playerlayout"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<MediaController android:id="@+id/playercontroller"
android:layout_width="fill_parent"
46

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

REFERENCES AND BIBLIOGRAPHY


Many projects and books have been referred to develop
this project, but out of those many resources only a few of them
have been very handy in the project development.
A few references are as follows: Android Studio tutorial
Android Application Development FOR DUMmIES
By:- Donn Felker with Joshua Dobbs.

The Busy Coder's Guide to Android Developmen


By:- Mark L. Murphy.

Web sites:

www.tutorialspoint.com
www.google.com

51

Potrebbero piacerti anche