diff --git a/Android.mk b/Android.mk index 7ba73d6507d0cf354905ec5224ed627d65916563..a08bbc192070abf84233e7903f43c3a5ababcbbb 100644 --- a/Android.mk +++ b/Android.mk @@ -17,4 +17,6 @@ LOCAL_PATH := $(LOCAL_DIR_PATH) include $(LOCAL_PATH)/fmapp/Android.mk LOCAL_PATH := $(LOCAL_DIR_PATH) include $(LOCAL_PATH)/fmapp2/Android.mk +LOCAL_PATH := $(LOCAL_DIR_PATH) +include $(LOCAL_PATH)/FMRecord/Android.mk endif # is-vendor-board-platform diff --git a/FMRecord/Android.mk b/FMRecord/Android.mk new file mode 100644 index 0000000000000000000000000000000000000000..00837f03f3e1abfcc1f4a4e49427d16e9bcd504b --- /dev/null +++ b/FMRecord/Android.mk @@ -0,0 +1,14 @@ +ifeq ($(call is-vendor-board-platform,QCOM),true) +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := optional + +LOCAL_SRC_FILES := $(call all-java-files-under, src/com/codeaurora/fmrecording/) + +LOCAL_PACKAGE_NAME := FMRecord +LOCAL_CERTIFICATE := platform +LOCAL_PROGUARD_ENABLED := disabled +include $(BUILD_PACKAGE) + +endif diff --git a/FMRecord/AndroidManifest.xml b/FMRecord/AndroidManifest.xml new file mode 100644 index 0000000000000000000000000000000000000000..beb0cf7ec29d995ef695a293014822a2283931ea --- /dev/null +++ b/FMRecord/AndroidManifest.xml @@ -0,0 +1,47 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of The Linux Foundation nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.codeaurora.fmrecording" > + <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" /> + <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> + <uses-permission android:name="android.permission.RECORD_AUDIO" /> + <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL"/> + <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" /> + +<application> + +<receiver android:name="FMRecordingReceiver"> + <intent-filter> + <action android:name="codeaurora.intent.action.FM" /> + </intent-filter> +</receiver> + +<service android:name="com.codeaurora.fmrecording.FMRecordingService"></service> +</application> +</manifest> diff --git a/FMRecord/res/values/strings.xml b/FMRecord/res/values/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..59f14ad48e07298cb8c5547afd5aadac6dbeb203 --- /dev/null +++ b/FMRecord/res/values/strings.xml @@ -0,0 +1,49 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + * Copyright (c) 2009-2013, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of The Linux Foundation nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--> +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- alert to the user that USB storage must be available before using FM recording [CHAR LIMIT=NONE] --> + <string name="no_storage">Mount SD card before start recording.</string> + <!-- alert to the user that the USB storage is being disk-checked [CHAR LIMIT=30] --> + <string name="preparing_sd">Preparing SD card</string> + <!-- alert to the user that the FM fails to read or write the USB storage. [CHAR LIMIT=NONE] --> + <string name="access_sd_fail">Couldn\'t access SD card.</string> + <!-- Low-memory dialog message [CHAR LIMT=NONE] --> + <string name="spaceIsLow_content">Your SD card storage is running out of space. Change the quality setting or delete some images or other files.</string> + <!-- The messsage shown when FM record reaches size limit. --> + <string name="FMRecording_reach_size_limit">Size limit reached.</string> + <!-- the name under which recordings will be visible in the media database is formatted like this --> + <string name="audio_db_title_format"><xliff:g id="format">yyyy-MM-dd HH:mm:ss</xliff:g></string> + <!-- all recordings will show up in the media database with this 'artist' name --> + <string name="audio_db_artist_name">My FM recordings</string> + <!-- all recordings will show up in the media database with this 'album' name --> + <string name="audio_db_album_name">FM recordings</string> + <!-- all recordings will show up in the media database in a playlist with this name --> + <string name="audio_db_playlist_name">FM recordings</string> + <string name="save_record_file">FM Recorded file saved to "<xliff:g id="record_file">%1$s</xliff:g>"</string> +</resources> diff --git a/FMRecord/src/com/codeaurora/fmrecording/FMRecordingReceiver.java b/FMRecord/src/com/codeaurora/fmrecording/FMRecordingReceiver.java new file mode 100644 index 0000000000000000000000000000000000000000..9389f10bcbf621fd4dff669ddd3a1d704164f699 --- /dev/null +++ b/FMRecord/src/com/codeaurora/fmrecording/FMRecordingReceiver.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of The Linux Foundation nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.codeaurora.fmrecording; + +import android.content.Intent; +import android.content.BroadcastReceiver; +import android.content.pm.PackageManager; +import android.content.Context; +import android.content.ComponentName; +import android.util.Log; +import java.lang.String; + + +public class FMRecordingReceiver extends BroadcastReceiver { + + private static final String TAG = "FMRecordingReceiver"; + public static final String ACTION_FM = + "codeaurora.intent.action.FM"; + @Override + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + Log.d(TAG, "Received intent: " + action); + if((action != null) && action.equals(ACTION_FM)) { + Log.d(TAG, "FM intent received"); + Intent in = new Intent(); + in.putExtras(intent); + in.setClass(context, FMRecordingService.class); + int state = intent.getIntExtra("state", 0); + boolean startService = true; + + if (state == 1) { + Log.d(TAG, "FM ON intent received"); + startService = true; + context.startService(in); + } else if(state == 0){ + Log.d(TAG, "FM OFF intent received"); + startService = false; + context.stopService(in); + } + } + } +} diff --git a/FMRecord/src/com/codeaurora/fmrecording/FMRecordingService.java b/FMRecord/src/com/codeaurora/fmrecording/FMRecordingService.java new file mode 100644 index 0000000000000000000000000000000000000000..2b0d00a1458def80b2162820388ac0c46f3630c3 --- /dev/null +++ b/FMRecord/src/com/codeaurora/fmrecording/FMRecordingService.java @@ -0,0 +1,476 @@ +/* + * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of The Linux Foundation nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.codeaurora.fmrecording; + +import java.util.*; +import android.app.Service; +import java.io.IOException; +import java.lang.ref.WeakReference; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.BroadcastReceiver; +import android.media.AudioManager; +import android.media.AudioManager.OnAudioFocusChangeListener; +import android.media.AudioSystem; +import android.media.MediaRecorder; +import android.os.Environment; +import android.os.Handler; +import android.os.IBinder; +import android.os.Message; +import android.util.Log; +import java.util.Date; +import java.text.SimpleDateFormat; +import android.provider.MediaStore; +import android.content.ContentResolver; +import android.content.ContentValues; +import android.database.Cursor; +import java.io.File; +import android.widget.Toast; +import android.os.UserHandle; +import android.net.Uri; +import android.content.res.Resources; +import android.os.StatFs; + +public class FMRecordingService extends Service { + private static final String TAG = "FMRecordingService"; + private BroadcastReceiver mFmRecordingReceiver = null; + private BroadcastReceiver mSdcardUnmountReceiver = null; + public static final long UNAVAILABLE = -1L; + public static final long PREPARING = -2L; + public static final long UNKNOWN_SIZE = -3L; + public static final long LOW_STORAGE_THRESHOLD = 50000000; + private long mStorageSpace; + private boolean mFmRecordingOn = false; + public static final String ACTION_FM_RECORDING = + "codeaurora.intent.action.FM_Recording"; + public static final String ACTION_FM_RECORDING_STATUS = + "codeaurora.intent.action.FM.Recording.Status"; + + private File mSampleFile = null; + private MediaRecorder mRecorder = null; + long mSampleStart = 0; + static final int START = 1; + static final int STOP = 0; + + public void onCreate() { + + super.onCreate(); + Log.d(TAG, "FMRecording Service onCreate"); + registerRecordingListner(); + registerExternalStorageListener(); + } + + public int onStartCommand(Intent intent, int flags, int startId) { + + Log.d(TAG, "FMRecording Service onCreate"); + return START_NOT_STICKY; + } + + public void onDestroy() { + Log.d(TAG, "FMRecording Service onDestroy"); + if (mFmRecordingOn == true) { + Log.d(TAG, "Still recording on progress, Stoping it"); + stopRecord(); + } + unregisterBroadCastReceiver(mFmRecordingReceiver); + unregisterBroadCastReceiver(mSdcardUnmountReceiver); + super.onDestroy(); + } + + public IBinder onBind(Intent intent) { + Log.v(TAG, "FMRecording Service onBind"); + return null; + } + + private void unregisterBroadCastReceiver(BroadcastReceiver myreceiver) { + + if (myreceiver != null) { + unregisterReceiver(myreceiver); + myreceiver = null; + } + } + /** + * Registers an intent to listen for ACTION_MEDIA_UNMOUNTED notifications. + * The intent will call closeExternalStorageFiles() if the external media + * is going to be ejected, so applications can clean up. + */ + private void registerExternalStorageListener() { + if (mSdcardUnmountReceiver == null) { + mSdcardUnmountReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + if ((action.equals(Intent.ACTION_MEDIA_UNMOUNTED)) + || (action.equals(Intent.ACTION_MEDIA_EJECT))) { + + Log.d(TAG, "ACTION_MEDIA_UNMOUNTED Intent received"); + if (mFmRecordingOn == true) { + try { + stopRecord(); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + } + }; + IntentFilter iFilter = new IntentFilter(); + iFilter.addAction(Intent.ACTION_MEDIA_UNMOUNTED); + iFilter.addAction(Intent.ACTION_MEDIA_EJECT); + iFilter.addDataScheme("file"); + registerReceiver(mSdcardUnmountReceiver, iFilter); + } + } + + private static long getAvailableSpace() { + String state = Environment.getExternalStorageState(); + Log.d(TAG, "External storage state=" + state); + if (Environment.MEDIA_CHECKING.equals(state)) { + return PREPARING; + } + if (!Environment.MEDIA_MOUNTED.equals(state)) { + return UNAVAILABLE; + } + + try { + File sampleDir = Environment.getExternalStorageDirectory(); + StatFs stat = new StatFs(sampleDir.getAbsolutePath()); + return stat.getAvailableBlocks() * (long) stat.getBlockSize(); + } catch (Exception e) { + Log.i(TAG, "Fail to access external storage", e); + } + return UNKNOWN_SIZE; + } + + private boolean updateAndShowStorageHint() { + mStorageSpace = getAvailableSpace(); + return showStorageHint(); + } + + private boolean showStorageHint() { + String errorMessage = null; + if (mStorageSpace == UNAVAILABLE) { + errorMessage = getString(R.string.no_storage); + } else if (mStorageSpace == PREPARING) { + errorMessage = getString(R.string.preparing_sd); + } else if (mStorageSpace == UNKNOWN_SIZE) { + errorMessage = getString(R.string.access_sd_fail); + } else if (mStorageSpace < LOW_STORAGE_THRESHOLD) { + errorMessage = getString(R.string.spaceIsLow_content); + } + + if (errorMessage != null) { + Toast.makeText(this, errorMessage, + Toast.LENGTH_LONG).show(); + return false; + } + return true; + } + + private void sendRecordingStatusIntent(int status) { + Intent intent = new Intent(ACTION_FM_RECORDING_STATUS); + intent.putExtra("state", status); + Log.d(TAG, "posting intent for FM Recording status as = " +status); + getApplicationContext().sendBroadcastAsUser(intent, UserHandle.ALL); + } + private boolean startRecord() { + + Log.d(TAG, "Enter startRecord"); + if (mRecorder != null) { /* Stop existing recording if any */ + Log.d(TAG, "Stopping existing record"); + try { + mRecorder.stop(); + mRecorder.reset(); + mRecorder.release(); + mRecorder = null; + } catch(Exception e) { + e.printStackTrace(); + } + } + if (!updateAndShowStorageHint()) + return false; + long maxFileSize = mStorageSpace - LOW_STORAGE_THRESHOLD; + mRecorder = new MediaRecorder(); + try { + mRecorder.setMaxFileSize(maxFileSize); + } catch (RuntimeException exception) { + + } + mSampleFile = null; + File sampleDir = Environment.getExternalStorageDirectory(); + + try { + mSampleFile = File.createTempFile("FMRecording", ".3gpp", sampleDir); + } catch (IOException e) { + Log.e(TAG, "Not able to access SD Card"); + Toast.makeText(this, "Not able to access SD Card", Toast.LENGTH_SHORT).show(); + } + try { + Log.d(TAG, "AudioSource.FM_RX" +MediaRecorder.AudioSource.FM_RX); + mRecorder.setAudioSource(MediaRecorder.AudioSource.FM_RX); + mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP); + mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC); + } catch (RuntimeException exception) { + Log.d(TAG, "RuntimeException while settings"); + mRecorder.reset(); + mRecorder.release(); + mRecorder = null; + return false; + } + Log.d(TAG, "setOutputFile"); + mRecorder.setOutputFile(mSampleFile.getAbsolutePath()); + try { + mRecorder.prepare(); + Log.d(TAG, "start"); + mRecorder.start(); + } catch (IOException e) { + Log.d(TAG, "IOException while start"); + mRecorder.reset(); + mRecorder.release(); + mRecorder = null; + return false; + } catch (RuntimeException e) { + Log.d(TAG, "RuntimeException while start"); + mRecorder.reset(); + mRecorder.release(); + mRecorder = null; + return false; + } + mFmRecordingOn = true; + Log.d(TAG, "mSampleFile.getAbsolutePath() " +mSampleFile.getAbsolutePath()); + mRecorder.setOnInfoListener(new MediaRecorder.OnInfoListener() { + public void onInfo(MediaRecorder mr, int what, int extra) { + if ((what == MediaRecorder.MEDIA_RECORDER_INFO_MAX_DURATION_REACHED) || + (what == MediaRecorder.MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED)) { + if (mFmRecordingOn) { + Log.d(TAG, "Maximum file size/duration reached, stopping the recording"); + stopRecord(); + } + // Show the toast. + Toast.makeText(FMRecordingService.this, R.string.FMRecording_reach_size_limit, + Toast.LENGTH_LONG).show(); + } + } + // from MediaRecorder.OnErrorListener + public void onError(MediaRecorder mr, int what, int extra) { + Log.e(TAG, "MediaRecorder error. what=" + what + ". extra=" + extra); + if (what == MediaRecorder.MEDIA_RECORDER_ERROR_UNKNOWN) { + // We may have run out of space on the sdcard. + if (mFmRecordingOn) { + stopRecord(); + } + updateAndShowStorageHint(); + } + } + }); + mSampleStart = System.currentTimeMillis(); + sendRecordingStatusIntent(START); + return true; + } + + private void stopRecord() { + Log.d(TAG, "Enter stopRecord"); + mFmRecordingOn = false; + if (mRecorder == null) + return; + try { + mRecorder.stop(); + mRecorder.reset(); + mRecorder.release(); + mRecorder = null; + } catch(Exception e) { + e.printStackTrace(); + } + + sendRecordingStatusIntent(STOP); + saveFile(); + } + + private void saveFile() { + int sampleLength = (int)((System.currentTimeMillis() - mSampleStart)/1000 ); + Log.d(TAG, "Enter saveFile"); + if (sampleLength == 0) + return; + String state = Environment.getExternalStorageState(); + Log.d(TAG, "storage state is " + state); + + if (Environment.MEDIA_MOUNTED.equals(state)) { + try { + this.addToMediaDB(mSampleFile); + Toast.makeText(this,getString(R.string.save_record_file, + mSampleFile.getAbsolutePath( )), + Toast.LENGTH_LONG).show(); + } catch(Exception e) { + e.printStackTrace(); + } + } else { + Log.e(TAG, "SD card must have removed during recording. "); + Toast.makeText(this, "Recording aborted", Toast.LENGTH_SHORT).show(); + } + return; + } + + /* + * Adds file and returns content uri. + */ + private Uri addToMediaDB(File file) { + Log.d(TAG, "In addToMediaDB"); + Resources res = getResources(); + ContentValues cv = new ContentValues(); + long current = System.currentTimeMillis(); + long modDate = file.lastModified(); + Date date = new Date(current); + SimpleDateFormat formatter = new SimpleDateFormat( + res.getString(R.string.audio_db_title_format)); + String title = formatter.format(date); + + // Lets label the recorded audio file as NON-MUSIC so that the file + // won't be displayed automatically, except for in the playlist. + cv.put(MediaStore.Audio.Media.IS_MUSIC, "1"); + cv.put(MediaStore.Audio.Media.TITLE, title); + cv.put(MediaStore.Audio.Media.DATA, file.getAbsolutePath()); + cv.put(MediaStore.Audio.Media.DATE_ADDED, (int) (current / 1000)); + cv.put(MediaStore.Audio.Media.DATE_MODIFIED, (int) (modDate / 1000)); + cv.put(MediaStore.Audio.Media.MIME_TYPE, "AUDIO_AAC_MP4"); + cv.put(MediaStore.Audio.Media.ARTIST, + res.getString(R.string.audio_db_artist_name)); + cv.put(MediaStore.Audio.Media.ALBUM, + res.getString(R.string.audio_db_album_name)); + Log.d(TAG, "Inserting audio record: " + cv.toString()); + ContentResolver resolver = getContentResolver(); + Uri base = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI; + Log.d(TAG, "ContentURI: " + base); + Uri result = resolver.insert(base, cv); + if (result == null) { + Toast.makeText(this, "Unable to save recorded audio", Toast.LENGTH_SHORT).show(); + return null; + } + if (getPlaylistId(res) == -1) { + createPlaylist(res, resolver); + } + int audioId = Integer.valueOf(result.getLastPathSegment()); + addToPlaylist(resolver, audioId, getPlaylistId(res)); + + // Notify those applications such as Music listening to the + // scanner events that a recorded audio file just created. + sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, result)); + return result; + } + + private int getPlaylistId(Resources res) { + Uri uri = MediaStore.Audio.Playlists.getContentUri("external"); + final String[] ids = new String[] { MediaStore.Audio.Playlists._ID }; + final String where = MediaStore.Audio.Playlists.NAME + "=?"; + final String[] args = new String[] { res.getString(R.string.audio_db_playlist_name) }; + Cursor cursor = query(uri, ids, where, args, null); + if (cursor == null) { + Log.v(TAG, "query returns null"); + } + int id = -1; + if (cursor != null) { + cursor.moveToFirst(); + if (!cursor.isAfterLast()) { + id = cursor.getInt(0); + } + cursor.close(); + } + return id; + } + + private Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { + try { + ContentResolver resolver = getContentResolver(); + if (resolver == null) { + return null; + } + return resolver.query(uri, projection, selection, selectionArgs, sortOrder); + } catch (UnsupportedOperationException ex) { + return null; + } + } + + private Uri createPlaylist(Resources res, ContentResolver resolver) { + ContentValues cv = new ContentValues(); + cv.put(MediaStore.Audio.Playlists.NAME, res.getString(R.string.audio_db_playlist_name)); + Uri uri = resolver.insert(MediaStore.Audio.Playlists.getContentUri("external"), cv); + if (uri == null) { + Toast.makeText(this, "Unable to save recorded audio", Toast.LENGTH_SHORT).show(); + } + return uri; + } + + private void addToPlaylist(ContentResolver resolver, int audioId, long playlistId) { + String[] cols = new String[] { + "count(*)" + }; + Uri uri = MediaStore.Audio.Playlists.Members.getContentUri("external", playlistId); + Cursor cur = resolver.query(uri, cols, null, null, null); + final int base; + if (cur != null) { + cur.moveToFirst(); + base = cur.getInt(0); + cur.close(); + } else { + base = 0; + } + ContentValues values = new ContentValues(); + values.put(MediaStore.Audio.Playlists.Members.PLAY_ORDER, Integer.valueOf(base + audioId)); + values.put(MediaStore.Audio.Playlists.Members.AUDIO_ID, audioId); + resolver.insert(uri, values); + } + + private void registerRecordingListner() { + if (mFmRecordingReceiver == null) { + mFmRecordingReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + Log.d(TAG, "Received intent " +intent); + String action = intent.getAction(); + Log.d(TAG, " action = " +action); + if (action.equals(ACTION_FM_RECORDING)) { + int state = intent.getIntExtra("state", STOP); + Log.d(TAG, "ACTION_FM_RECORDING Intent received" +state); + if (state == START) { + Log.d(TAG, "Recording start"); + startRecord(); + } else if (state == STOP) { + Log.d(TAG, "Stop recording"); + stopRecord(); + } + } + } + }; + IntentFilter iFilter = new IntentFilter(); + iFilter.addAction(ACTION_FM_RECORDING); + registerReceiver(mFmRecordingReceiver, iFilter); + } + } + +} diff --git a/fmapp/AndroidManifest.xml b/fmapp/AndroidManifest.xml index d0232bcdc9d1179ae16a240b061fd33fbd76882a..6c0f4f87014d844186c875cbd3ce34675b809ebd 100644 --- a/fmapp/AndroidManifest.xml +++ b/fmapp/AndroidManifest.xml @@ -41,6 +41,8 @@ <uses-permission android:name="android.permission.RECORD_AUDIO" /> <uses-permission android:name="android.permission.CHANGE_COMPONENT_ENABLED_STATE"/> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/> + <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL"/> + <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" /> <application android:icon="@drawable/ic_launcher_fmradio" diff --git a/fmapp/src/com/codeaurora/fmradio/FMRadio.java b/fmapp/src/com/codeaurora/fmradio/FMRadio.java index d592bc243ee6744a47930033d40d4e205d1a9568..408cf0457c545d4bfe9200eafd7f8ea5998ef0e7 100644 --- a/fmapp/src/com/codeaurora/fmradio/FMRadio.java +++ b/fmapp/src/com/codeaurora/fmradio/FMRadio.java @@ -2139,20 +2139,20 @@ public class FMRadio extends Activity { try { - mRecording = mService.startRecording(); + mService.startRecording(); } catch (RemoteException e) { e.printStackTrace(); } - //Initiate record timer thread here - if( mRecording == true ) { - int durationInMins = FmSharedPreferences.getRecordDuration(); - Log.e(LOGTAG, " Fected duration:" + durationInMins ); - initiateRecordDurationTimer( durationInMins ); - } } } + private void startRecordingTimer() { + mRecording = true; + int durationInMins = FmSharedPreferences.getRecordDuration(); + Log.e(LOGTAG, " Fected duration:" + durationInMins ); + initiateRecordDurationTimer( durationInMins ); + } private void stopRecording() { mRecording = false; DebugToasts("Stopped Recording", Toast.LENGTH_SHORT); @@ -3591,5 +3591,10 @@ public class FMRadio extends Activity Log.d(LOGTAG, "mServiceCallbacks.onRecordingStopped:"); stopRecording(); } + public void onRecordingStarted() + { + Log.d(LOGTAG, "mServiceCallbacks.onRecordingStarted:"); + startRecordingTimer(); + } }; } diff --git a/fmapp/src/com/codeaurora/fmradio/FMRadioService.java b/fmapp/src/com/codeaurora/fmradio/FMRadioService.java index d467162b50149f3e1ed84bb38104c761fd2654aa..e15117d8fa2a060b8e4bc7d9c284613c95e3c2cb 100644 --- a/fmapp/src/com/codeaurora/fmradio/FMRadioService.java +++ b/fmapp/src/com/codeaurora/fmradio/FMRadioService.java @@ -78,6 +78,10 @@ import android.media.AudioManager; import android.content.ComponentName; import android.os.StatFs; import android.os.SystemClock; +import android.content.Intent; +import android.content.IntentFilter; +import android.app.IntentService; +import android.os.UserHandle; /** * Provides "background" FM Radio (that uses the hardware) capabilities, @@ -160,6 +164,16 @@ public class FMRadioService extends Service private static final String SLEEP_EXPIRED_ACTION = "com.codeaurora.fmradio.SLEEP_EXPIRED"; private static final String RECORD_EXPIRED_ACTION = "com.codeaurora.fmradio.RECORD_TIMEOUT"; private static final String SERVICE_DELAYED_STOP_ACTION = "com.codeaurora.fmradio.SERVICE_STOP"; + public static final String ACTION_FM = + "codeaurora.intent.action.FM"; + public static final String ACTION_FM_RECORDING = + "codeaurora.intent.action.FM_Recording"; + public static final String ACTION_FM_RECORDING_STATUS = + "codeaurora.intent.action.FM.Recording.Status"; + private String mFilePath = ""; + private BroadcastReceiver mFmRecordingStatus = null; + static final int RECORD_START = 1; + static final int RECORD_STOP = 0; public FMRadioService() { } @@ -184,7 +198,7 @@ public class FMRadioService extends Service registerSleepExpired(); registerRecordTimeout(); registerDelayedServiceStop(); - registerExternalStorageListener(); + registerFMRecordingStatus(); // registering media button receiver seperately as we need to set // different priority for receiving media events registerFmMediaButtonReceiver(); @@ -233,10 +247,6 @@ public class FMRadioService extends Service unregisterReceiver(mHeadsetReceiver); mHeadsetReceiver = null; } - if( mSdcardUnmountReceiver != null ) { - unregisterReceiver(mSdcardUnmountReceiver); - mSdcardUnmountReceiver = null; - } if( mMusicCommandListener != null ) { unregisterReceiver(mMusicCommandListener); mMusicCommandListener = null; @@ -257,6 +267,10 @@ public class FMRadioService extends Service unregisterReceiver(mDelayedServiceStopListener); mDelayedServiceStopListener = null; } + if (mFmRecordingStatus != null ) { + unregisterReceiver(mFmRecordingStatus); + mFmRecordingStatus = null; + } /* Since the service is closing, disable the receiver */ fmOff(); @@ -270,38 +284,46 @@ public class FMRadioService extends Service super.onDestroy(); } -/** - * Registers an intent to listen for ACTION_MEDIA_UNMOUNTED notifications. - * The intent will call closeExternalStorageFiles() if the external media - * is going to be ejected, so applications can clean up. - */ - public void registerExternalStorageListener() { - if (mSdcardUnmountReceiver == null) { - mSdcardUnmountReceiver = new BroadcastReceiver() { + public void registerFMRecordingStatus() { + if (mFmRecordingStatus == null) { + mFmRecordingStatus = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { + Log.d(LOGTAG, "received intent " +intent); String action = intent.getAction(); - if ((action.equals(Intent.ACTION_MEDIA_UNMOUNTED)) - || (action.equals(Intent.ACTION_MEDIA_EJECT))) { - Log.d(LOGTAG, "ACTION_MEDIA_UNMOUNTED Intent received"); - if (mFmRecordingOn == true) { + if (action.equals(ACTION_FM_RECORDING_STATUS)) { + Log.d(LOGTAG, "ACTION_FM_RECORDING_STATUS Intent received"); + int state = intent.getIntExtra("state", 0); + if (state == RECORD_START) { + Log.d(LOGTAG, "FM Recording started"); + mFmRecordingOn = true; try { - stopRecording(); - } catch (Exception e) { + if ((mServiceInUse) && (mCallbacks != null) ) { + Log.d(LOGTAG, "start recording thread"); + mCallbacks.onRecordingStarted(); + } + } catch (RemoteException e) { e.printStackTrace(); } - } + } else if (state == RECORD_STOP) { + Log.d(LOGTAG, "FM Recording stopped"); + mFmRecordingOn = false; + try { + if ((mServiceInUse) && (mCallbacks != null) ) { + mCallbacks.onRecordingStopped(); + } + } catch (RemoteException e) { + e.printStackTrace(); + } + } } } }; IntentFilter iFilter = new IntentFilter(); - iFilter.addAction(Intent.ACTION_MEDIA_UNMOUNTED); - iFilter.addAction(Intent.ACTION_MEDIA_EJECT); - iFilter.addDataScheme("file"); - registerReceiver(mSdcardUnmountReceiver, iFilter); + iFilter.addAction(ACTION_FM_RECORDING_STATUS); + registerReceiver(mFmRecordingStatus , iFilter); } - } - + } /** * Registers an intent to listen for ACTION_HEADSET_PLUG @@ -666,6 +688,20 @@ public class FMRadioService extends Service return true; } + private void sendRecordIntent(int action) { + Intent intent = new Intent(ACTION_FM_RECORDING); + intent.putExtra("state", action); + Log.d(LOGTAG, "Sending Recording intent for = " +action); + getApplicationContext().sendBroadcast(intent); + } + + private void sendRecordServiceIntent(int action) { + Intent intent = new Intent(ACTION_FM); + intent.putExtra("state", action); + Log.d(LOGTAG, "Sending Recording intent for = " +action); + getApplicationContext().sendBroadcast(intent); + } + private void startFM(){ Log.d(LOGTAG, "In startFM"); if(true == mAppShutdown) { // not to send intent to AudioManager in Shutdown @@ -703,6 +739,7 @@ public class FMRadioService extends Service } AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_FM, AudioSystem.DEVICE_STATE_AVAILABLE, ""); + sendRecordServiceIntent(RECORD_START); } mPlaybackInProgress = true; } @@ -716,6 +753,7 @@ public class FMRadioService extends Service Log.d(LOGTAG, "FMRadio: Requesting to stop FM"); AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_FM, AudioSystem.DEVICE_STATE_UNAVAILABLE, ""); + sendRecordServiceIntent(RECORD_STOP); } mPlaybackInProgress = false; } @@ -729,105 +767,23 @@ public class FMRadioService extends Service Log.d(LOGTAG, "FMRadio: Requesting to stop FM"); AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_FM, AudioSystem.DEVICE_STATE_UNAVAILABLE, ""); + sendRecordServiceIntent(RECORD_STOP); } mPlaybackInProgress = false; } - public boolean startRecording() { - Log.d(LOGTAG, "In startRecording of Recorder"); - if( (true == mSingleRecordingInstanceSupported) && - (true == mOverA2DP )) { - Toast.makeText( this, - "playback on BT in progress,can't record now", - Toast.LENGTH_SHORT).show(); - return false; - } - stopRecording(); - - if (!updateAndShowStorageHint()) - return false; - long maxFileSize = mStorageSpace - LOW_STORAGE_THRESHOLD; - mRecorder = new MediaRecorder(); - try { - mRecorder.setMaxFileSize(maxFileSize); - } catch (RuntimeException exception) { - - } + public void startRecording() { - mSampleFile = null; - File sampleDir = Environment.getExternalStorageDirectory(); - if (!sampleDir.canWrite()) // Workaround for broken sdcard support on - // the device. - sampleDir = new File("/sdcard/sdcard"); - try { - mSampleFile = File - .createTempFile("FMRecording", ".3gpp", sampleDir); - } catch (IOException e) { - Log.e(LOGTAG, "Not able to access SD Card"); - Toast.makeText(this, "Not able to access SD Card", Toast.LENGTH_SHORT).show(); - return false; - } - if (mRecorder == null) { - Toast.makeText(this,"MediaRecorder failed to create an instance", - Toast.LENGTH_SHORT).show(); - return false; - } - - try { - mRecorder.setAudioSource(MediaRecorder.AudioSource.FM_RX); - mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP); - mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC); - } catch (RuntimeException exception) { - mRecorder.reset(); - mRecorder.release(); - mRecorder = null; - return false; - } - mRecorder.setOutputFile(mSampleFile.getAbsolutePath()); - try { - mRecorder.prepare(); - mRecorder.start(); - } catch (IOException e) { - mRecorder.reset(); - mRecorder.release(); - mRecorder = null; - return false; - } catch (RuntimeException e) { - mRecorder.reset(); - mRecorder.release(); - mRecorder = null; - return false; - } - mFmRecordingOn = true; - mRecorder.setOnInfoListener(new MediaRecorder.OnInfoListener() { - public void onInfo(MediaRecorder mr, int what, int extra) { - if ((what == MediaRecorder.MEDIA_RECORDER_INFO_MAX_DURATION_REACHED) || - (what == MediaRecorder.MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED)) { - if (mFmRecordingOn) { - Log.d(LOGTAG, "Maximum file size/duration reached, stopping the recording"); - stopRecording(); - } - // Show the toast. - Toast.makeText(FMRadioService.this, R.string.FMRecording_reach_size_limit, - Toast.LENGTH_LONG).show(); - } - } - // from MediaRecorder.OnErrorListener - public void onError(MediaRecorder mr, int what, int extra) { - Log.e(LOGTAG, "MediaRecorder error. what=" + what + ". extra=" + extra); - if (what == MediaRecorder.MEDIA_RECORDER_ERROR_UNKNOWN) { - // We may have run out of space on the sdcard. - if (mFmRecordingOn) { - stopRecording(); - } - updateAndShowStorageHint(); - } - } - }); - - mSampleStart = System.currentTimeMillis(); - return true; - } + Log.d(LOGTAG, "In startRecording of Recorder"); + if ((true == mSingleRecordingInstanceSupported) && + (true == mOverA2DP )) { + Toast.makeText( this, + "playback on BT in progress,can't record now", + Toast.LENGTH_SHORT).show(); + return; + } + sendRecordIntent(RECORD_START); + } public boolean startA2dpPlayback() { Log.d(LOGTAG, "In startA2dpPlayback"); @@ -925,197 +881,13 @@ public class FMRadioService extends Service return; } - private void resetRecording() { - - Log.v(LOGTAG, "resetRecording()"); - - mFmRecordingOn = false; - if (mRecorder == null) - return; - - // Send Intent for IOBUSY VOTE, because MediaRecorder.stop - // gets Activity context which might not be always available - // and would thus fail to send the intent. - Intent ioBusyUnVoteIntent = new Intent(IOBUSY_UNVOTE); - // Remove vote for io_is_busy to be turned off. - ioBusyUnVoteIntent.putExtra("com.android.server.CpuGovernorService.voteType", 0); - sendBroadcast(ioBusyUnVoteIntent); - - mRecorder.stop(); - - mRecorder.reset(); - mRecorder.release(); - mRecorder = null; - int sampleLength = (int)((System.currentTimeMillis() - mSampleStart)/1000 ); - if (sampleLength == 0) - return; - String state = Environment.getExternalStorageState(); - Log.d(LOGTAG, "storage state is " + state); - - if (Environment.MEDIA_MOUNTED.equals(state)) { - this.addToMediaDB(mSampleFile); - } - else{ - Log.e(LOGTAG, "SD card must have removed during recording. "); - Toast.makeText(this, "Recording aborted", Toast.LENGTH_SHORT).show(); - } - return; - } - public void stopRecording() { - mFmRecordingOn = false; - if (mRecorder == null) - return; - try { - mRecorder.stop(); - mRecorder.reset(); - mRecorder.release(); - mRecorder = null; - } catch(Exception e) { - e.printStackTrace(); - } - int sampleLength = (int)((System.currentTimeMillis() - mSampleStart)/1000 ); - if (sampleLength == 0) + if (!mFmRecordingOn) return; - String state = Environment.getExternalStorageState(); - Log.d(LOGTAG, "storage state is " + state); - - if (Environment.MEDIA_MOUNTED.equals(state)) { - try { - this.addToMediaDB(mSampleFile); - Toast.makeText(this,getString(R.string.save_record_file, mSampleFile.getAbsolutePath()), - Toast.LENGTH_LONG).show(); - } - catch(Exception e) { - e.printStackTrace(); - } - } - else{ - Log.e(LOGTAG, "SD card must have removed during recording. "); - Toast.makeText(this, "Recording aborted", Toast.LENGTH_SHORT).show(); - } - try - { - if((mServiceInUse) && (mCallbacks != null) ) { - mCallbacks.onRecordingStopped(); - } - } catch (RemoteException e) - { - e.printStackTrace(); - } + sendRecordIntent(RECORD_STOP); return; } - /* - * Adds file and returns content uri. - */ - private Uri addToMediaDB(File file) { - Log.d(LOGTAG, "In addToMediaDB"); - Resources res = getResources(); - ContentValues cv = new ContentValues(); - long current = System.currentTimeMillis(); - long modDate = file.lastModified(); - Date date = new Date(current); - SimpleDateFormat formatter = new SimpleDateFormat( - res.getString(R.string.audio_db_title_format)); - String title = formatter.format(date); - - // Lets label the recorded audio file as NON-MUSIC so that the file - // won't be displayed automatically, except for in the playlist. - cv.put(MediaStore.Audio.Media.IS_MUSIC, "1"); - - cv.put(MediaStore.Audio.Media.TITLE, title); - cv.put(MediaStore.Audio.Media.DATA, file.getAbsolutePath()); - cv.put(MediaStore.Audio.Media.DATE_ADDED, (int) (current / 1000)); - cv.put(MediaStore.Audio.Media.DATE_MODIFIED, (int) (modDate / 1000)); - cv.put(MediaStore.Audio.Media.MIME_TYPE, "AUDIO_AAC_MP4"); - cv.put(MediaStore.Audio.Media.ARTIST, - res.getString(R.string.audio_db_artist_name)); - cv.put(MediaStore.Audio.Media.ALBUM, - res.getString(R.string.audio_db_album_name)); - Log.d(LOGTAG, "Inserting audio record: " + cv.toString()); - ContentResolver resolver = getContentResolver(); - Uri base = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI; - Log.d(LOGTAG, "ContentURI: " + base); - Uri result = resolver.insert(base, cv); - if (result == null) { - Toast.makeText(this, "Unable to save recorded audio", Toast.LENGTH_SHORT).show(); - return null; - } - if (getPlaylistId(res) == -1) { - createPlaylist(res, resolver); - } - int audioId = Integer.valueOf(result.getLastPathSegment()); - addToPlaylist(resolver, audioId, getPlaylistId(res)); - - // Notify those applications such as Music listening to the - // scanner events that a recorded audio file just created. - sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, result)); - return result; - } - - private int getPlaylistId(Resources res) { - Uri uri = MediaStore.Audio.Playlists.getContentUri("external"); - final String[] ids = new String[] { MediaStore.Audio.Playlists._ID }; - final String where = MediaStore.Audio.Playlists.NAME + "=?"; - final String[] args = new String[] { res.getString(R.string.audio_db_playlist_name) }; - Cursor cursor = query(uri, ids, where, args, null); - if (cursor == null) { - Log.v(LOGTAG, "query returns null"); - } - int id = -1; - if (cursor != null) { - cursor.moveToFirst(); - if (!cursor.isAfterLast()) { - id = cursor.getInt(0); - } - cursor.close(); - } - return id; - } - - private Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { - try { - ContentResolver resolver = getContentResolver(); - if (resolver == null) { - return null; - } - return resolver.query(uri, projection, selection, selectionArgs, sortOrder); - } catch (UnsupportedOperationException ex) { - return null; - } - } - - private Uri createPlaylist(Resources res, ContentResolver resolver) { - ContentValues cv = new ContentValues(); - cv.put(MediaStore.Audio.Playlists.NAME, res.getString(R.string.audio_db_playlist_name)); - Uri uri = resolver.insert(MediaStore.Audio.Playlists.getContentUri("external"), cv); - if (uri == null) { - Toast.makeText(this, "Unable to save recorded audio", Toast.LENGTH_SHORT).show(); - } - return uri; - } - - private void addToPlaylist(ContentResolver resolver, int audioId, long playlistId) { - String[] cols = new String[] { - "count(*)" - }; - Uri uri = MediaStore.Audio.Playlists.Members.getContentUri("external", playlistId); - Cursor cur = resolver.query(uri, cols, null, null, null); - final int base; - if (cur != null) { - cur.moveToFirst(); - base = cur.getInt(0); - cur.close(); - } - else { - base = 0; - } - ContentValues values = new ContentValues(); - values.put(MediaStore.Audio.Playlists.Members.PLAY_ORDER, Integer.valueOf(base + audioId)); - values.put(MediaStore.Audio.Playlists.Members.AUDIO_ID, audioId); - resolver.insert(uri, values); - } private void fmActionOnCallState( int state ) { //if Call Status is non IDLE we need to Mute FM as well stop recording if //any. Similarly once call is ended FM should be unmuted. @@ -1480,9 +1252,9 @@ private Runnable mSpeakerDisableTask = new Runnable() { return(mService.get().isMuted()); } - public boolean startRecording() + public void startRecording() { - return(mService.get().startRecording()); + mService.get().startRecording(); } public void stopRecording() @@ -1870,7 +1642,7 @@ private Runnable mSpeakerDisableTask = new Runnable() { if (isFmRecordingOn()) { - resetRecording(); + stopRecording(); } AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE); diff --git a/fmapp/src/com/codeaurora/fmradio/FMStats.java b/fmapp/src/com/codeaurora/fmradio/FMStats.java index 23069075e3a6a8fbf5b0dd16d00d850f2ed55684..a68ccc4a83a011683f6e2b39252d5a0b3936a1b0 100644 --- a/fmapp/src/com/codeaurora/fmradio/FMStats.java +++ b/fmapp/src/com/codeaurora/fmradio/FMStats.java @@ -2062,6 +2062,10 @@ public class FMStats extends Activity { { Log.d(LOGTAG, "mServiceCallbacks.onFinishActivity:"); } + public void onRecordingStarted() + { + Log.d(LOGTAG, "mServiceCallbacks.onRecordingStarted:"); + } }; /* Radio Vars */ final Handler mHandler = new Handler(); diff --git a/fmapp/src/com/codeaurora/fmradio/IFMRadioService.aidl b/fmapp/src/com/codeaurora/fmradio/IFMRadioService.aidl index 79d83f7b3cdb76892a46a7be95a21eaaae60da27..d80c320d2f43323bd12eb14871de9b5d77b6c686 100644 --- a/fmapp/src/com/codeaurora/fmradio/IFMRadioService.aidl +++ b/fmapp/src/com/codeaurora/fmradio/IFMRadioService.aidl @@ -46,7 +46,7 @@ interface IFMRadioService boolean routeAudio(int device); boolean unMute(); boolean isMuted(); - boolean startRecording(); + void startRecording(); void stopRecording(); boolean tune(int frequency); boolean seek(boolean up); diff --git a/fmapp/src/com/codeaurora/fmradio/IFMRadioServiceCallbacks.aidl b/fmapp/src/com/codeaurora/fmradio/IFMRadioServiceCallbacks.aidl index eb782e8e9b246cc8510722c0b230e13232d4be94..4d116ecb13b3b8eef7ba1fd7ef51b9c247663a23 100644 --- a/fmapp/src/com/codeaurora/fmradio/IFMRadioServiceCallbacks.aidl +++ b/fmapp/src/com/codeaurora/fmradio/IFMRadioServiceCallbacks.aidl @@ -45,4 +45,5 @@ interface IFMRadioServiceCallbacks void onStationRDSSupported(boolean bRDSSupported); void onRecordingStopped(); void onExtenRadioTextChanged(); + void onRecordingStarted(); } diff --git a/fmapp2/AndroidManifest.xml b/fmapp2/AndroidManifest.xml index 4cef8c0c1a2aa48493229a210ca0ad2d65370e4e..b377b9d7c2d51f5c96765171f4c03fd188b10868 100644 --- a/fmapp2/AndroidManifest.xml +++ b/fmapp2/AndroidManifest.xml @@ -42,6 +42,8 @@ <uses-permission android:name="android.permission.RECORD_AUDIO" /> <uses-permission android:name="android.permission.CHANGE_COMPONENT_ENABLED_STATE"/> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/> + <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL"/> + <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" /> <application android:icon="@drawable/ic_launcher_fmradio" diff --git a/fmapp2/src/com/caf/fmradio/FMRadio.java b/fmapp2/src/com/caf/fmradio/FMRadio.java index caa9bb2525f9661e3f420fe87dacac7286ee9ebe..631ab40be327370b8f2ddee1b4448e3dd7d46bc5 100644 --- a/fmapp2/src/com/caf/fmradio/FMRadio.java +++ b/fmapp2/src/com/caf/fmradio/FMRadio.java @@ -1768,21 +1768,20 @@ public class FMRadio extends Activity private void startRecording() { if(mService != null) { try { - mRecording = mService.startRecording(); - }catch (RemoteException e) { - e.printStackTrace(); - } - //Initiate record timer thread here - if(mRecording == true) { - mRecordingMsgTV.setCompoundDrawablesWithIntrinsicBounds - (R.drawable.recorder_stop, 0, 0, 0); - int durationInMins = FmSharedPreferences.getRecordDuration(); - Log.e(LOGTAG, "Fected duration: " + durationInMins); - initiateRecordDurationTimer( durationInMins ); + mService.startRecording(); + } catch (RemoteException e) { + e.printStackTrace(); } } } + private void startRecordingTimer() { + mRecording = true; + int durationInMins = FmSharedPreferences.getRecordDuration(); + Log.e(LOGTAG, " Fected duration:" + durationInMins ); + initiateRecordDurationTimer( durationInMins ); + } + private void stopRecording() { mRecording = false; DebugToasts("Stopped Recording", Toast.LENGTH_SHORT); @@ -3033,5 +3032,10 @@ public class FMRadio extends Activity Log.d(LOGTAG, "mServiceCallbacks.onRecordingStopped:"); stopRecording(); } + public void onRecordingStarted() + { + Log.d(LOGTAG, "mServiceCallbacks.onRecordingStarted:"); + startRecordingTimer(); + } }; } diff --git a/fmapp2/src/com/caf/fmradio/FMRadioService.java b/fmapp2/src/com/caf/fmradio/FMRadioService.java index 5d971cfd40d10475d36e7267eda0e84379e4a89e..54b9aed153fa0546e04f06c94abb112fc7e414d1 100644 --- a/fmapp2/src/com/caf/fmradio/FMRadioService.java +++ b/fmapp2/src/com/caf/fmradio/FMRadioService.java @@ -41,6 +41,8 @@ import android.app.Service; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.app.IntentService; +import android.os.UserHandle; import android.content.BroadcastReceiver; import android.media.AudioManager; import android.media.AudioManager.OnAudioFocusChangeListener; @@ -160,6 +162,15 @@ public class FMRadioService extends Service private static final String SLEEP_EXPIRED_ACTION = "com.caf.fmradio.SLEEP_EXPIRED"; private static final String RECORD_EXPIRED_ACTION = "com.caf.fmradio.RECORD_TIMEOUT"; private static final String SERVICE_DELAYED_STOP_ACTION = "com.caf.fmradio.SERVICE_STOP"; + public static final String ACTION_FM = + "codeaurora.intent.action.FM"; + public static final String ACTION_FM_RECORDING = + "codeaurora.intent.action.FM_Recording"; + public static final String ACTION_FM_RECORDING_STATUS = + "codeaurora.intent.action.FM.Recording.Status"; + private BroadcastReceiver mFmRecordingStatus = null; + static final int RECORD_START = 1; + static final int RECORD_STOP = 0; public FMRadioService() { } @@ -184,7 +195,7 @@ public class FMRadioService extends Service registerSleepExpired(); registerRecordTimeout(); registerDelayedServiceStop(); - registerExternalStorageListener(); + registerFMRecordingStatus(); // registering media button receiver seperately as we need to set // different priority for receiving media events registerFmMediaButtonReceiver(); @@ -233,10 +244,6 @@ public class FMRadioService extends Service unregisterReceiver(mHeadsetReceiver); mHeadsetReceiver = null; } - if( mSdcardUnmountReceiver != null ) { - unregisterReceiver(mSdcardUnmountReceiver); - mSdcardUnmountReceiver = null; - } if( mMusicCommandListener != null ) { unregisterReceiver(mMusicCommandListener); mMusicCommandListener = null; @@ -257,6 +264,10 @@ public class FMRadioService extends Service unregisterReceiver(mDelayedServiceStopListener); mDelayedServiceStopListener = null; } + if (mFmRecordingStatus != null ) { + unregisterReceiver(mFmRecordingStatus); + mFmRecordingStatus = null; + } /* Since the service is closing, disable the receiver */ fmOff(); @@ -270,38 +281,46 @@ public class FMRadioService extends Service super.onDestroy(); } -/** - * Registers an intent to listen for ACTION_MEDIA_UNMOUNTED notifications. - * The intent will call closeExternalStorageFiles() if the external media - * is going to be ejected, so applications can clean up. - */ - public void registerExternalStorageListener() { - if (mSdcardUnmountReceiver == null) { - mSdcardUnmountReceiver = new BroadcastReceiver() { + public void registerFMRecordingStatus() { + if (mFmRecordingStatus == null) { + mFmRecordingStatus = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { + Log.d(LOGTAG, "received intent " +intent); String action = intent.getAction(); - if ((action.equals(Intent.ACTION_MEDIA_UNMOUNTED)) - || (action.equals(Intent.ACTION_MEDIA_EJECT))) { - Log.d(LOGTAG, "ACTION_MEDIA_UNMOUNTED Intent received"); - if (mFmRecordingOn == true) { + if (action.equals(ACTION_FM_RECORDING_STATUS)) { + Log.d(LOGTAG, "ACTION_FM_RECORDING_STATUS Intent received"); + int state = intent.getIntExtra("state", 0); + if (state == RECORD_START) { + Log.d(LOGTAG, "FM Recording started"); + mFmRecordingOn = true; + try { + if ((mServiceInUse) && (mCallbacks != null) ) { + Log.d(LOGTAG, "start recording thread"); + mCallbacks.onRecordingStarted(); + } + } catch (RemoteException e) { + e.printStackTrace(); + } + } else if (state == RECORD_STOP) { + Log.d(LOGTAG, "FM Recording stopped"); + mFmRecordingOn = false; try { - stopRecording(); - } catch (Exception e) { + if ((mServiceInUse) && (mCallbacks != null) ) { + mCallbacks.onRecordingStopped(); + } + } catch (RemoteException e) { e.printStackTrace(); } - } + } } } }; IntentFilter iFilter = new IntentFilter(); - iFilter.addAction(Intent.ACTION_MEDIA_UNMOUNTED); - iFilter.addAction(Intent.ACTION_MEDIA_EJECT); - iFilter.addDataScheme("file"); - registerReceiver(mSdcardUnmountReceiver, iFilter); + iFilter.addAction(ACTION_FM_RECORDING_STATUS); + registerReceiver(mFmRecordingStatus , iFilter); } - } - + } /** * Registers an intent to listen for ACTION_HEADSET_PLUG @@ -666,6 +685,20 @@ public class FMRadioService extends Service return true; } + private void sendRecordIntent(int action) { + Intent intent = new Intent(ACTION_FM_RECORDING); + intent.putExtra("state", action); + Log.d(LOGTAG, "Sending Recording intent for = " +action); + getApplicationContext().sendBroadcast(intent); + } + + private void sendRecordServiceIntent(int action) { + Intent intent = new Intent(ACTION_FM); + intent.putExtra("state", action); + Log.d(LOGTAG, "Sending Recording intent for = " +action); + getApplicationContext().sendBroadcast(intent); + } + private void startFM(){ Log.d(LOGTAG, "In startFM"); if(true == mAppShutdown) { // not to send intent to AudioManager in Shutdown @@ -703,6 +736,7 @@ public class FMRadioService extends Service } AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_FM, AudioSystem.DEVICE_STATE_AVAILABLE, ""); + sendRecordServiceIntent(RECORD_START); } mPlaybackInProgress = true; } @@ -716,6 +750,7 @@ public class FMRadioService extends Service Log.d(LOGTAG, "FMRadio: Requesting to stop FM"); AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_FM, AudioSystem.DEVICE_STATE_UNAVAILABLE, ""); + sendRecordServiceIntent(RECORD_STOP); } mPlaybackInProgress = false; } @@ -729,105 +764,23 @@ public class FMRadioService extends Service Log.d(LOGTAG, "FMRadio: Requesting to stop FM"); AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_FM, AudioSystem.DEVICE_STATE_UNAVAILABLE, ""); + sendRecordServiceIntent(RECORD_STOP); } mPlaybackInProgress = false; } - public boolean startRecording() { - Log.d(LOGTAG, "In startRecording of Recorder"); - if( (true == mSingleRecordingInstanceSupported) && - (true == mOverA2DP )) { - Toast.makeText( this, - "playback on BT in progress,can't record now", - Toast.LENGTH_SHORT).show(); - return false; - } - stopRecording(); - - if (!updateAndShowStorageHint()) - return false; - long maxFileSize = mStorageSpace - LOW_STORAGE_THRESHOLD; - mRecorder = new MediaRecorder(); - try { - mRecorder.setMaxFileSize(maxFileSize); - } catch (RuntimeException exception) { - - } - - mSampleFile = null; - File sampleDir = Environment.getExternalStorageDirectory(); - if (!sampleDir.canWrite()) // Workaround for broken sdcard support on - // the device. - sampleDir = new File("/sdcard/sdcard"); - try { - mSampleFile = File - .createTempFile("FMRecording", ".3gpp", sampleDir); - } catch (IOException e) { - Log.e(LOGTAG, "Not able to access SD Card"); - Toast.makeText(this, "Not able to access SD Card", Toast.LENGTH_SHORT).show(); - return false; - } - if (mRecorder == null) { - Toast.makeText(this,"MediaRecorder failed to create an instance", - Toast.LENGTH_SHORT).show(); - return false; - } - - try { - mRecorder.setAudioSource(MediaRecorder.AudioSource.FM_RX); - mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP); - mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC); - } catch (RuntimeException exception) { - mRecorder.reset(); - mRecorder.release(); - mRecorder = null; - return false; - } - mRecorder.setOutputFile(mSampleFile.getAbsolutePath()); - try { - mRecorder.prepare(); - mRecorder.start(); - } catch (IOException e) { - mRecorder.reset(); - mRecorder.release(); - mRecorder = null; - return false; - } catch (RuntimeException e) { - mRecorder.reset(); - mRecorder.release(); - mRecorder = null; - return false; - } - mFmRecordingOn = true; - mRecorder.setOnInfoListener(new MediaRecorder.OnInfoListener() { - public void onInfo(MediaRecorder mr, int what, int extra) { - if ((what == MediaRecorder.MEDIA_RECORDER_INFO_MAX_DURATION_REACHED) || - (what == MediaRecorder.MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED)) { - if (mFmRecordingOn) { - Log.d(LOGTAG, "Maximum file size/duration reached, stopping the recording"); - stopRecording(); - } - // Show the toast. - Toast.makeText(FMRadioService.this, R.string.FMRecording_reach_size_limit, - Toast.LENGTH_LONG).show(); - } - } - // from MediaRecorder.OnErrorListener - public void onError(MediaRecorder mr, int what, int extra) { - Log.e(LOGTAG, "MediaRecorder error. what=" + what + ". extra=" + extra); - if (what == MediaRecorder.MEDIA_RECORDER_ERROR_UNKNOWN) { - // We may have run out of space on the sdcard. - if (mFmRecordingOn) { - stopRecording(); - } - updateAndShowStorageHint(); - } - } - }); + public void startRecording() { - mSampleStart = System.currentTimeMillis(); - return true; - } + Log.d(LOGTAG, "In startRecording of Recorder"); + if ((true == mSingleRecordingInstanceSupported) && + (true == mOverA2DP )) { + Toast.makeText( this, + "playback on BT in progress,can't record now", + Toast.LENGTH_SHORT).show(); + return; + } + sendRecordIntent(RECORD_START); + } public boolean startA2dpPlayback() { Log.d(LOGTAG, "In startA2dpPlayback"); @@ -925,195 +878,13 @@ public class FMRadioService extends Service return; } - private void resetRecording() { - - Log.v(LOGTAG, "resetRecording()"); - - mFmRecordingOn = false; - if (mRecorder == null) - return; - - // Send Intent for IOBUSY VOTE, because MediaRecorder.stop - // gets Activity context which might not be always available - // and would thus fail to send the intent. - Intent ioBusyUnVoteIntent = new Intent(IOBUSY_UNVOTE); - // Remove vote for io_is_busy to be turned off. - ioBusyUnVoteIntent.putExtra("com.android.server.CpuGovernorService.voteType", 0); - sendBroadcast(ioBusyUnVoteIntent); - - mRecorder.stop(); - - mRecorder.reset(); - mRecorder.release(); - mRecorder = null; - int sampleLength = (int)((System.currentTimeMillis() - mSampleStart)/1000 ); - if (sampleLength == 0) - return; - String state = Environment.getExternalStorageState(); - Log.d(LOGTAG, "storage state is " + state); - - if (Environment.MEDIA_MOUNTED.equals(state)) { - this.addToMediaDB(mSampleFile); - } - else{ - Log.e(LOGTAG, "SD card must have removed during recording. "); - Toast.makeText(this, "Recording aborted", Toast.LENGTH_SHORT).show(); - } - return; - } - public void stopRecording() { - mFmRecordingOn = false; - if (mRecorder == null) - return; - try { - mRecorder.stop(); - mRecorder.reset(); - mRecorder.release(); - mRecorder = null; - } catch(Exception e) { - e.printStackTrace(); - } - int sampleLength = (int)((System.currentTimeMillis() - mSampleStart)/1000 ); - if (sampleLength == 0) + if (!mFmRecordingOn) return; - String state = Environment.getExternalStorageState(); - Log.d(LOGTAG, "storage state is " + state); - - if (Environment.MEDIA_MOUNTED.equals(state)) { - try { - this.addToMediaDB(mSampleFile); - } - catch(Exception e) { - e.printStackTrace(); - } - } - else{ - Log.e(LOGTAG, "SD card must have removed during recording. "); - Toast.makeText(this, "Recording aborted", Toast.LENGTH_SHORT).show(); - } - try - { - if((mServiceInUse) && (mCallbacks != null) ) { - mCallbacks.onRecordingStopped(); - } - } catch (RemoteException e) - { - e.printStackTrace(); - } + sendRecordIntent(RECORD_STOP); return; } - /* - * Adds file and returns content uri. - */ - private Uri addToMediaDB(File file) { - Log.d(LOGTAG, "In addToMediaDB"); - Resources res = getResources(); - ContentValues cv = new ContentValues(); - long current = System.currentTimeMillis(); - long modDate = file.lastModified(); - Date date = new Date(current); - SimpleDateFormat formatter = new SimpleDateFormat( - res.getString(R.string.audio_db_title_format)); - String title = formatter.format(date); - - // Lets label the recorded audio file as NON-MUSIC so that the file - // won't be displayed automatically, except for in the playlist. - cv.put(MediaStore.Audio.Media.IS_MUSIC, "1"); - - cv.put(MediaStore.Audio.Media.TITLE, title); - cv.put(MediaStore.Audio.Media.DATA, file.getAbsolutePath()); - cv.put(MediaStore.Audio.Media.DATE_ADDED, (int) (current / 1000)); - cv.put(MediaStore.Audio.Media.DATE_MODIFIED, (int) (modDate / 1000)); - cv.put(MediaStore.Audio.Media.MIME_TYPE, "AUDIO_AAC_MP4"); - cv.put(MediaStore.Audio.Media.ARTIST, - res.getString(R.string.audio_db_artist_name)); - cv.put(MediaStore.Audio.Media.ALBUM, - res.getString(R.string.audio_db_album_name)); - Log.d(LOGTAG, "Inserting audio record: " + cv.toString()); - ContentResolver resolver = getContentResolver(); - Uri base = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI; - Log.d(LOGTAG, "ContentURI: " + base); - Uri result = resolver.insert(base, cv); - if (result == null) { - Toast.makeText(this, "Unable to save recorded audio", Toast.LENGTH_SHORT).show(); - return null; - } - if (getPlaylistId(res) == -1) { - createPlaylist(res, resolver); - } - int audioId = Integer.valueOf(result.getLastPathSegment()); - addToPlaylist(resolver, audioId, getPlaylistId(res)); - - // Notify those applications such as Music listening to the - // scanner events that a recorded audio file just created. - sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, result)); - return result; - } - - private int getPlaylistId(Resources res) { - Uri uri = MediaStore.Audio.Playlists.getContentUri("external"); - final String[] ids = new String[] { MediaStore.Audio.Playlists._ID }; - final String where = MediaStore.Audio.Playlists.NAME + "=?"; - final String[] args = new String[] { res.getString(R.string.audio_db_playlist_name) }; - Cursor cursor = query(uri, ids, where, args, null); - if (cursor == null) { - Log.v(LOGTAG, "query returns null"); - } - int id = -1; - if (cursor != null) { - cursor.moveToFirst(); - if (!cursor.isAfterLast()) { - id = cursor.getInt(0); - } - cursor.close(); - } - return id; - } - - private Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { - try { - ContentResolver resolver = getContentResolver(); - if (resolver == null) { - return null; - } - return resolver.query(uri, projection, selection, selectionArgs, sortOrder); - } catch (UnsupportedOperationException ex) { - return null; - } - } - - private Uri createPlaylist(Resources res, ContentResolver resolver) { - ContentValues cv = new ContentValues(); - cv.put(MediaStore.Audio.Playlists.NAME, res.getString(R.string.audio_db_playlist_name)); - Uri uri = resolver.insert(MediaStore.Audio.Playlists.getContentUri("external"), cv); - if (uri == null) { - Toast.makeText(this, "Unable to save recorded audio", Toast.LENGTH_SHORT).show(); - } - return uri; - } - - private void addToPlaylist(ContentResolver resolver, int audioId, long playlistId) { - String[] cols = new String[] { - "count(*)" - }; - Uri uri = MediaStore.Audio.Playlists.Members.getContentUri("external", playlistId); - Cursor cur = resolver.query(uri, cols, null, null, null); - final int base; - if (cur != null) { - cur.moveToFirst(); - base = cur.getInt(0); - cur.close(); - } - else { - base = 0; - } - ContentValues values = new ContentValues(); - values.put(MediaStore.Audio.Playlists.Members.PLAY_ORDER, Integer.valueOf(base + audioId)); - values.put(MediaStore.Audio.Playlists.Members.AUDIO_ID, audioId); - resolver.insert(uri, values); - } private void fmActionOnCallState( int state ) { //if Call Status is non IDLE we need to Mute FM as well stop recording if //any. Similarly once call is ended FM should be unmuted. @@ -1468,9 +1239,9 @@ public class FMRadioService extends Service return(mService.get().isMuted()); } - public boolean startRecording() + public void startRecording() { - return(mService.get().startRecording()); + mService.get().startRecording(); } public void stopRecording() @@ -1790,7 +1561,7 @@ public class FMRadioService extends Service if (isFmRecordingOn()) { - resetRecording(); + stopRecording(); } AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE); diff --git a/fmapp2/src/com/caf/fmradio/FMStats.java b/fmapp2/src/com/caf/fmradio/FMStats.java index 2afb3011d66a7236e0c0b46c9fe087a311d6fd62..feb6aab69ab70246752771040bf4d9ba18f95770 100644 --- a/fmapp2/src/com/caf/fmradio/FMStats.java +++ b/fmapp2/src/com/caf/fmradio/FMStats.java @@ -1290,6 +1290,10 @@ public class FMStats extends Activity { { Log.d(LOGTAG, "mServiceCallbacks.onFinishActivity:"); } + public void onRecordingStarted() + { + Log.d(LOGTAG, "mServiceCallbacks.onRecordingStarted:"); + } }; /* Radio Vars */ final Handler mHandler = new Handler(); diff --git a/fmapp2/src/com/caf/fmradio/IFMRadioService.aidl b/fmapp2/src/com/caf/fmradio/IFMRadioService.aidl index 73581492203c1b25289bf5cda656123adb2c2524..8e2fe996203a117b134ad6e46ce3d6b3606684e1 100644 --- a/fmapp2/src/com/caf/fmradio/IFMRadioService.aidl +++ b/fmapp2/src/com/caf/fmradio/IFMRadioService.aidl @@ -18,7 +18,7 @@ interface IFMRadioService boolean routeAudio(int device); boolean unMute(); boolean isMuted(); - boolean startRecording(); + void startRecording(); void stopRecording(); boolean tune(int frequency); boolean seek(boolean up); diff --git a/fmapp2/src/com/caf/fmradio/IFMRadioServiceCallbacks.aidl b/fmapp2/src/com/caf/fmradio/IFMRadioServiceCallbacks.aidl index 1926f247ca468f1a54f4abd2827b510e5a1f4904..4b9d2f0df66852336662cea78af098dc8da20ae7 100644 --- a/fmapp2/src/com/caf/fmradio/IFMRadioServiceCallbacks.aidl +++ b/fmapp2/src/com/caf/fmradio/IFMRadioServiceCallbacks.aidl @@ -45,4 +45,5 @@ interface IFMRadioServiceCallbacks void onStationRDSSupported(boolean bRDSSupported); void onRecordingStopped(); void onExtenRadioTextChanged(); + void onRecordingStarted(); }