|
29 | 29 | import android.content.pm.PackageManager; |
30 | 30 | import android.graphics.drawable.Drawable; |
31 | 31 | import android.media.AudioManager; |
| 32 | +import android.media.MediaRecorder; |
32 | 33 | import android.net.Uri; |
33 | 34 | import android.net.sip.SipManager; |
34 | 35 | import android.os.AsyncResult; |
|
65 | 66 | import com.android.internal.telephony.cdma.CdmaConnection; |
66 | 67 | import com.android.internal.telephony.sip.SipPhone; |
67 | 68 |
|
| 69 | +import java.io.File; |
| 70 | +import java.io.IOException; |
| 71 | +import java.text.SimpleDateFormat; |
68 | 72 | import java.util.ArrayList; |
| 73 | +import java.util.Calendar; |
69 | 74 | import java.util.Hashtable; |
70 | 75 | import java.util.Iterator; |
71 | 76 | import java.util.List; |
@@ -98,9 +103,13 @@ public class PhoneUtils { |
98 | 103 | static final int AUDIO_RINGING = 1; /** audio behaviour while ringing */ |
99 | 104 | static final int AUDIO_OFFHOOK = 2; /** audio behaviour while in call. */ |
100 | 105 |
|
| 106 | + private static MediaRecorder recorder = null; |
| 107 | + |
101 | 108 | /** Speaker state, persisting between wired headset connection events */ |
102 | 109 | private static boolean sIsSpeakerEnabled = false; |
103 | 110 |
|
| 111 | + private static boolean sIsFirstCall = true; |
| 112 | + |
104 | 113 | /** Hash table to store mute (Boolean) values based upon the connection.*/ |
105 | 114 | private static Hashtable<Connection, Boolean> sConnectionMuteTable = |
106 | 115 | new Hashtable<Connection, Boolean>(); |
@@ -430,6 +439,10 @@ static boolean keepProximitySensorOn(Context context) { |
430 | 439 | return PreferenceManager.getDefaultSharedPreferences(context) |
431 | 440 | .getBoolean("keep_proximity_sensor_on", false); |
432 | 441 | } |
| 442 | + static boolean callRecordingEnabled(Context context) { |
| 443 | + return PreferenceManager.getDefaultSharedPreferences(context) |
| 444 | + .getBoolean("button_call_recording", false); |
| 445 | + } |
433 | 446 | }; |
434 | 447 |
|
435 | 448 | static boolean hangupRingingCall(Call ringing) { |
@@ -2078,6 +2091,71 @@ static boolean getMute() { |
2078 | 2091 | } |
2079 | 2092 | } |
2080 | 2093 |
|
| 2094 | + private static File createRecordingTempFile(String path) { |
| 2095 | + File dir = new File(path); |
| 2096 | + if (!dir.exists()) { |
| 2097 | + try { |
| 2098 | + dir.mkdirs(); |
| 2099 | + } catch (Exception e) { |
| 2100 | + Log.e("PhoneUtils", "unable to create directory " + dir + ": " + e); |
| 2101 | + return null; |
| 2102 | + } |
| 2103 | + } else if (!dir.canWrite()) { |
| 2104 | + Log.e("PhoneUtils", "no write permission for directory: " + dir); |
| 2105 | + return null; |
| 2106 | + } |
| 2107 | + try { |
| 2108 | + return File.createTempFile("call", ".tmp", dir); |
| 2109 | + } catch (IOException e) { |
| 2110 | + Log.e("PhoneUtils", "unable to create temp file in " + dir + ": " + e); |
| 2111 | + return null; |
| 2112 | + } |
| 2113 | + } |
| 2114 | + |
| 2115 | + static void startRecording(String address, String inOut) { |
| 2116 | + String dirName = "/sdcard/CallRecordings"; |
| 2117 | + log("startRecording"); |
| 2118 | + if (recorder == null) { |
| 2119 | + log("startRecording: create new recorder"); |
| 2120 | + File recording = null; |
| 2121 | + recorder = new MediaRecorder(); |
| 2122 | + recorder.setAudioSource(MediaRecorder.AudioSource.VOICE_RECOGNITION); |
| 2123 | + recorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4); |
| 2124 | + recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC); |
| 2125 | + recording = createRecordingTempFile(dirName); |
| 2126 | + if (recording == null) { |
| 2127 | + recorder.release(); |
| 2128 | + recorder = null; |
| 2129 | + return; |
| 2130 | + } |
| 2131 | + // name recording filename based on call data |
| 2132 | + Calendar cl = Calendar.getInstance(); |
| 2133 | + SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd-HHmmss-("); |
| 2134 | + String newRecordingName = dirName + "/" + sdf.format(cl.getTime()) + address + ")-" + inOut + ".m4a"; |
| 2135 | + recording.renameTo(new File(newRecordingName)); |
| 2136 | + recorder.setOutputFile(newRecordingName); |
| 2137 | + try { |
| 2138 | + recorder.prepare(); |
| 2139 | + recorder.start(); |
| 2140 | + } catch (IOException e) { |
| 2141 | + Log.e("PhoneUtils", "io problems while preparing [" + |
| 2142 | + newRecordingName + "]: " + e.getMessage()); |
| 2143 | + recorder.release(); |
| 2144 | + recorder = null; |
| 2145 | + } |
| 2146 | + } |
| 2147 | + } |
| 2148 | + |
| 2149 | + static void stopRecording() { |
| 2150 | + log("stopRecording"); |
| 2151 | + if (recorder != null) { |
| 2152 | + log("stopRecording: release old recorder"); |
| 2153 | + recorder.stop(); |
| 2154 | + recorder.release(); |
| 2155 | + recorder = null; |
| 2156 | + } |
| 2157 | + } |
| 2158 | + |
2081 | 2159 | /* package */ static void setAudioMode() { |
2082 | 2160 | setAudioMode(PhoneApp.getInstance().mCM); |
2083 | 2161 | } |
@@ -2556,7 +2634,16 @@ private static int checkCnapSpecialCases(String n) { |
2556 | 2634 | private static boolean activateSpeakerIfDocked(Phone phone) { |
2557 | 2635 | if (DBG) log("activateSpeakerIfDocked()..."); |
2558 | 2636 |
|
| 2637 | + /* TODO: hack for Defy+ libaudio on Milestone (first call is mute), |
| 2638 | + should be removed when a proper fix is ready */ |
| 2639 | + if (sIsFirstCall) { |
| 2640 | + sIsFirstCall = false; |
| 2641 | + turnOnSpeaker(phone.getContext(), true, false); |
| 2642 | + restoreSpeakerMode(phone.getContext()); |
| 2643 | + } |
| 2644 | + |
2559 | 2645 | boolean activated = false; |
| 2646 | + |
2560 | 2647 | if (PhoneApp.mDockState != Intent.EXTRA_DOCK_STATE_UNDOCKED) { |
2561 | 2648 | if (DBG) log("activateSpeakerIfDocked(): In a dock -> may need to turn on speaker."); |
2562 | 2649 | PhoneApp app = PhoneApp.getInstance(); |
|
0 commit comments