esnyder / callrecorder

Toy Android app to do call recording.
GNU General Public License v3.0
130 stars 92 forks source link

listview does not shows name and number off recorded calls #4

Open crampal7 opened 9 years ago

crampal7 commented 9 years ago

i have downloaded the project and i worked on it, but the listview is not showing the name and number of the recorded calls.

esnyder commented 9 years ago

Hi @crampal7; sorry about that. I haven't touched this project in a few years, and don't have any good ideas for you as to why that's going on. It's pretty much in the "if it breaks you get to keep both pieces" stage.

If you figure out what's going wrong I'm happy to merge a fix in though.

critikaCapoor commented 9 years ago

Hi @crampal7; I have downloaded the project today and when I worked on the project, I got the same issue. Did you solve it? If not, then in java file - "CallLog", please add a "if" loop after " String[] dlist = dir.list(); line" for dir.list() size inside method - "loadRecordingsFromDir()". If size id not empty, then execute for loop. This will solve the problem. I hope it will help you and others too.

esnyder commented 9 years ago

pull requests welcome

On Tue, May 19, 2015 at 5:51 AM, critikaCapoor notifications@github.com wrote:

Hi @crampal7 https://github.com/crampal7; I downloaded the project today and when I run it, I got the same issue. Did you solve it? If not, then in java file - "CallLog", please add a "if" loop after " String[] dlist = dir.list(); line" for dir.list() size inside method - "loadRecordingsFromDir()". If size id not empty, then execute for loop. This will solve the problem. I hope it will help you and others too.

— Reply to this email directly or view it on GitHub https://github.com/esnyder/callrecorder/issues/4#issuecomment-103474230.

crampal7 commented 9 years ago

Hi @critikaCapoor; Could you please give me exact code of the loop.what loop shall i add over there. I tried from my side,but the list view is not showing the name and number of the recorded calls, instead it is showing file path of recorded calls

critikaCapoor commented 9 years ago

Hi @crampal7, I have only fetched number and duration for the recorded call. Sorry yesterday I got the wrong meaning of the question you asked. Below are the files with code that you need to replace with the original working files.

Record Service--- package com.talentcodeworks.callrecorder;

import java.io.File; import java.io.IOException;

import javax.xml.datatype.Duration;

import android.annotation.SuppressLint; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.app.Service; import android.content.Context; import android.content.CursorLoader; import android.content.Intent; import android.content.SharedPreferences; import android.database.Cursor; import android.media.MediaRecorder; import android.os.IBinder; import android.preference.PreferenceManager; import android.provider.CallLog; import android.util.Log; import android.widget.Toast; //import java.security.KeyPairGenerator; //import java.security.KeyPair; //import java.security.Key;

@SuppressLint("NewApi") 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";
private static final int RECORDING_NOTIFICATION_ID = 1;

private MediaRecorder recorder = null;
private boolean isRecording = false;
private File recording = null;
String number, duration;

/*
private static void test() throws java.security.NoSuchAlgorithmException
{
    KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
    kpg.initialize(2048);
    KeyPair kp = kpg.genKeyPair();
    Key publicKey = kp.getPublic();
    Key privateKey = kp.getPrivate();
}
*/

private File makeOutputFile (SharedPreferences prefs)
{
    File dir = new File(DEFAULT_STORAGE_LOCATION);

    // test dir for existence and writeability
    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;
        }
    }

    CursorLoader cursorLoader = new CursorLoader(RecordService.this,
            CallLog.Calls.CONTENT_URI, null, null, null, null);
Cursor managedCursor = cursorLoader.loadInBackground();

int durationIndex = managedCursor.getColumnIndex(CallLog.Calls.DURATION);
int phnNo = managedCursor.getColumnIndex(CallLog.Calls.NUMBER);

managedCursor.moveToLast();

String duration =managedCursor.getString(durationIndex);
String number =managedCursor.getString(phnNo);
System.out.println("duration + number "+ duration + " " + number);

    // test size

    // create filename based on call data
    String prefix = "call";
    //SimpleDateFormat sdf = new SimpleDateFormat("yyyy-mm-dd_HH:MM:SS");
    //prefix = sdf.format(new Date()) + "-callrecording";

    // add info to file name about what audio channel we were recording
    int audiosource = Integer.parseInt(prefs.getString(Preferences.PREF_AUDIO_SOURCE, "1"));
    prefix += "-channel" + audiosource + "-";

    // create suffix based on format
    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;
    }

    suffix += " \n number- "+ number + " duration- " + duration;

    try {
        return File.createTempFile(prefix, suffix, dir);
    } 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::onStart calling through to onStartCommand");
    //onStartCommand(intent, 0, startId);
    //}

    //public int onStartCommand(Intent intent, int flags, 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 START_STICKY;
        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 {
        // These calls will throw exceptions unless you set the 
        // android.permission.RECORD_AUDIO permission for your app
        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);
        Log.d("CallRecorder", "set encoder default");
        recorder.setOutputFile(recording.getAbsolutePath());
        Log.d("CallRecorder", "set file: " + recording);
        //recorder.setMaxDuration(msDuration); //1000); // 1 seconds
        //recorder.setMaxFileSize(bytesMax); //1024*1024); // 1KB

        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;
}

@SuppressLint("NewApi")
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();
        /*
        // encrypt the recording
        String keyfile = "/sdcard/keyring";
        try {
            //PGPPublicKey k = readPublicKey(new FileInputStream(keyfile));
            test();
        } catch (java.security.NoSuchAlgorithmException e) {
            Log.e("CallRecorder", "RecordService::onDestroy crypto test failed: ", e);
        }
        //encrypt(recording);
        */
    }

    updateNotification(false);
}

// methods to handle binding the service

public IBinder onBind(Intent intent)
{
    return null;
}

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);
    }
}

// MediaRecorder.OnInfoListener
public void onInfo(MediaRecorder mr, int what, int extra)
{
    Log.i("CallRecorder", "RecordService got MediaRecorder onInfo callback with what: " + what + " extra: " + extra);
    isRecording = false;
}

// MediaRecorder.OnErrorListener
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();
}

}

CallLog-

package com.talentcodeworks.callrecorder;

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; 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.Gravity; import android.view.View; import android.widget.ListView; import android.widget.MediaController; import android.widget.ArrayAdapter; import android.widget.AdapterView; import android.widget.Toast;

/ Ok, so, in theory this should work. However, the behavior of the android.widget.MediaController leaves something to be desired. Will have to see if we can get this figured out. /

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 {
            // Extract the recording names
            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);
    System.out.println("dir "+dir);
    String[] dlist = dir.list();
    if(dir.list() == null){
        Toast toast = Toast.makeText(getApplicationContext(), "No call logs", Toast.LENGTH_LONG);
        toast.setGravity(Gravity.CENTER, 0, 0);
        toast.show();
    }
    else{
    System.out.println("dlist "+ dlist + " " + dlist.length);

    for (int i=0; i<dlist.length; i++) {
        fAdapter.add(dlist[i]);
    }
    fAdapter.notifyDataSetChanged();
    }
}

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); //Intent.ACTION_VIEW);
            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);

    //recordingNames = new String[0];
    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();
    // Once we switch from path to provider based storage, use this method
    //loadRecordingsFromProvider();
}

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();
}

}

And please do add the below permissions in manifest-

<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.READ_CALL_LOG"/>
<uses-permission android:name="android.permission.WRITE_CALL_LOG"/>

The above code is working fine and the listview will show the recorded call url along with the phone number and duration. I hope it will help you somehow.

crampal7 commented 9 years ago

i updated both the files, but it shows error

11339-11339/com.example.myapplication6.app E/AndroidRuntime﹕ FATAL EXCEPTION: main java.lang.NoClassDefFoundError: android.content.CursorLoader at com.example.myapplication6.app.RecordService.makeOutputFile(RecordService.java:75) at com.example.myapplication6.app.RecordService.onStart(RecordService.java:158) at android.app.Service.onStartCommand(Service.java:428) at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:2043) at android.app.ActivityThread.access$2800(ActivityThread.java:117) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:998) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loop(Looper.java:130) at android.app.ActivityThread.main(ActivityThread.java:3687) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:507) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:867) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:625) at dalvik.system.NativeStart.main(Native Method)

critikaCapoor commented 9 years ago

Hi @crampal7 have you also added the permissions in the manifest? And also please cut and copy the cursor code lines from "RecordService" file and then change the file name of "CallLog" to "CallLogs" and then again paste the cursor code. You got the error because it didn't ask for the android.provider.CallLog, it by default took CallLog for CallLog java file.

pramitb commented 8 years ago

Audio player is not working!! can i get some help please!!