From 95bdfe6e4dc73eaa3d395e6073f78ee6495c7dc2 Mon Sep 17 00:00:00 2001 From: chatea Date: Sat, 2 Apr 2016 00:36:58 +0800 Subject: [PATCH 1/2] ServiceCarema with recording status and start/stop method Because BroadcastReciver via PhoneCall need use start/stop recording feature with Service, So Service add start/stop methods Update gitignore and remove untracking files Ignore all files in .idea/ folder Add callback to recieve recording result Also show some Toast to notify the recording state. Support start/stop recording feature MyVideoList init --- .gitignore | 16 ++- .idea/.name | 1 - .idea/compiler.xml | 23 ---- .idea/copyright/profiles_settings.xml | 3 - .idea/encodings.xml | 5 - .idea/gradle.xml | 19 --- .idea/misc.xml | 10 -- .idea/modules.xml | 10 -- .idea/scopes/scope_settings.xml | 5 - .idea/vcs.xml | 7 -- README.txt => README.md | 4 +- ServiceCamera.iml | 19 --- app/app.iml | 90 -------------- app/build.gradle | 1 + app/src/main/AndroidManifest.xml | 13 +- .../chatea/servicecamera/CameraService.java | 114 ++++++++++++++---- .../chatea/servicecamera/MainActivity.java | 71 ++++++++++- .../chatea/servicecamera/myVideoList.java | 24 ++++ app/src/main/res/layout/activity_main.xml | 10 +- .../res/layout/activity_my_video_list.xml | 26 ++++ .../main/res/layout/my_video_list_item.xml | 16 +++ app/src/main/res/values/strings.xml | 3 + 22 files changed, 256 insertions(+), 234 deletions(-) delete mode 100644 .idea/.name delete mode 100644 .idea/compiler.xml delete mode 100644 .idea/copyright/profiles_settings.xml delete mode 100644 .idea/encodings.xml delete mode 100644 .idea/gradle.xml delete mode 100644 .idea/misc.xml delete mode 100644 .idea/modules.xml delete mode 100644 .idea/scopes/scope_settings.xml delete mode 100644 .idea/vcs.xml rename README.txt => README.md (58%) delete mode 100644 ServiceCamera.iml delete mode 100644 app/app.iml create mode 100644 app/src/main/java/example/chatea/servicecamera/myVideoList.java create mode 100644 app/src/main/res/layout/activity_my_video_list.xml create mode 100644 app/src/main/res/layout/my_video_list_item.xml diff --git a/.gitignore b/.gitignore index afbdab3..70fd93f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,16 @@ +*.iml +*.apk .gradle +/build +/captures /local.properties -/.idea/workspace.xml -/.idea/libraries + +# Intellij IDEA +/.idea + +# Windows +Thumbs.db + +# OS X .DS_Store -/build + diff --git a/.idea/.name b/.idea/.name deleted file mode 100644 index 4d3d4b8..0000000 --- a/.idea/.name +++ /dev/null @@ -1 +0,0 @@ -ServiceCamera \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml deleted file mode 100644 index 217af47..0000000 --- a/.idea/compiler.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml deleted file mode 100644 index e7bedf3..0000000 --- a/.idea/copyright/profiles_settings.xml +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml deleted file mode 100644 index e206d70..0000000 --- a/.idea/encodings.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/.idea/gradle.xml b/.idea/gradle.xml deleted file mode 100644 index fe865d3..0000000 --- a/.idea/gradle.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - diff --git a/.idea/misc.xml b/.idea/misc.xml deleted file mode 100644 index 59436c9..0000000 --- a/.idea/misc.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/.idea/modules.xml b/.idea/modules.xml deleted file mode 100644 index 4beef45..0000000 --- a/.idea/modules.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/.idea/scopes/scope_settings.xml b/.idea/scopes/scope_settings.xml deleted file mode 100644 index 922003b..0000000 --- a/.idea/scopes/scope_settings.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index def6a6a..0000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/README.txt b/README.md similarity index 58% rename from README.txt rename to README.md index 1619bcd..6d589fa 100644 --- a/README.txt +++ b/README.md @@ -1,3 +1,5 @@ +# ServiceCamera + The recorded video will store in /sdcard/Pictures/MyCameraApp/*.mp4 -The states only show on ADB LOG but not UI. +Now support Start/Stop button. diff --git a/ServiceCamera.iml b/ServiceCamera.iml deleted file mode 100644 index 0bb6048..0000000 --- a/ServiceCamera.iml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - - - - - - - - - diff --git a/app/app.iml b/app/app.iml deleted file mode 100644 index 65f1a32..0000000 --- a/app/app.iml +++ /dev/null @@ -1,90 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/build.gradle b/app/build.gradle index 8b28422..d2f767e 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -21,4 +21,5 @@ android { dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) + compile 'com.android.support:appcompat-v7:21.0.3' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index efd0fa2..001b597 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,8 +1,9 @@ + package="example.chatea.servicecamera"> + @@ -12,10 +13,10 @@ + android:label="@string/app_name"> + android:label="@string/app_name"> @@ -25,9 +26,9 @@ - + android:enabled="true"> + - + \ No newline at end of file diff --git a/app/src/main/java/example/chatea/servicecamera/CameraService.java b/app/src/main/java/example/chatea/servicecamera/CameraService.java index 3f3ec24..a8438c0 100644 --- a/app/src/main/java/example/chatea/servicecamera/CameraService.java +++ b/app/src/main/java/example/chatea/servicecamera/CameraService.java @@ -7,8 +7,9 @@ import android.hardware.Camera; import android.media.CamcorderProfile; import android.media.MediaRecorder; -import android.os.Handler; +import android.os.Bundle; import android.os.IBinder; +import android.os.ResultReceiver; import android.util.Log; import android.view.SurfaceHolder; import android.view.SurfaceView; @@ -21,13 +22,45 @@ import java.util.List; public class CameraService extends Service { + private static final String TAG = CameraService.class.getSimpleName(); + + public static final String RESULT_RECEIVER = "resultReceiver"; + public static final String VIDEO_PATH = "recordedVideoPath"; + + public static final int RECORD_RESULT_OK = 0; + public static final int RECORD_RESULT_DEVICE_NO_CAMERA= 1; + public static final int RECORD_RESULT_GET_CAMERA_FAILED = 2; + public static final int RECORD_RESULT_ALREADY_RECORDING = 3; + public static final int RECORD_RESULT_NOT_RECORDING = 4; + + private static final String START_SERVICE_COMMAND = "startServiceCommands"; + private static final int COMMAND_NONE = -1; + private static final int COMMAND_START_RECORDING = 0; + private static final int COMMAND_STOP_RECORDING = 1; private Camera mCamera; private MediaRecorder mMediaRecorder; + private boolean mRecording = false; + private String mRecordingPath = null; + public CameraService() { } + public static void startToStartRecording(Context context, ResultReceiver resultReceiver) { + Intent intent = new Intent(context, CameraService.class); + intent.putExtra(START_SERVICE_COMMAND, COMMAND_START_RECORDING); + intent.putExtra(RESULT_RECEIVER, resultReceiver); + context.startService(intent); + } + + public static void startToStopRecording(Context context, ResultReceiver resultReceiver) { + Intent intent = new Intent(context, CameraService.class); + intent.putExtra(START_SERVICE_COMMAND, COMMAND_STOP_RECORDING); + intent.putExtra(RESULT_RECEIVER, resultReceiver); + context.startService(intent); + } + /** * Used to take picture. */ @@ -52,8 +85,29 @@ public void onPictureTaken(byte[] data, Camera camera) { @Override public int onStartCommand(Intent intent, int flags, int startId) { + switch (intent.getIntExtra(START_SERVICE_COMMAND, COMMAND_NONE)) { + case COMMAND_START_RECORDING: + handleStartRecordingCommand(intent); + break; + case COMMAND_STOP_RECORDING: + handleStopRecordingCommand(intent); + break; + default: + throw new UnsupportedOperationException("Cannot start service with illegal commands"); + } + + return START_STICKY; + } + + private void handleStartRecordingCommand(Intent intent) { + final ResultReceiver resultReceiver = intent.getParcelableExtra(RESULT_RECEIVER); - Log.d("TAG", "======= service in onStartCommand"); + if (mRecording) { + // Already recording + resultReceiver.send(RECORD_RESULT_ALREADY_RECORDING, null); + return; + } + mRecording = true; if (Util.checkCameraHardware(this)) { mCamera = Util.getCameraInstance(); @@ -66,13 +120,11 @@ public int onStartCommand(Intent intent, int flags, int startId) { WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH, PixelFormat.TRANSLUCENT); - SurfaceHolder sh = sv.getHolder(); sv.setZOrderOnTop(true); sh.setFormat(PixelFormat.TRANSPARENT); - sh.addCallback(new SurfaceHolder.Callback() { @Override public void surfaceCreated(SurfaceHolder holder) { @@ -101,7 +153,6 @@ public void surfaceCreated(SurfaceHolder holder) { e.printStackTrace(); } mCamera.startPreview(); -// mCamera.takePicture(null, null, mPicture); // used to takePicture. mCamera.unlock(); @@ -113,30 +164,22 @@ public void surfaceCreated(SurfaceHolder holder) { mMediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH)); - mMediaRecorder.setOutputFile(Util.getOutputMediaFile(Util.MEDIA_TYPE_VIDEO).getPath()); + mRecordingPath = Util.getOutputMediaFile(Util.MEDIA_TYPE_VIDEO).getPath(); + mMediaRecorder.setOutputFile(mRecordingPath); mMediaRecorder.setPreviewDisplay(holder.getSurface()); try { mMediaRecorder.prepare(); } catch (IllegalStateException e) { - Log.d("TAG", "====== IllegalStateException preparing MediaRecorder: " + e.getMessage()); + Log.d(TAG, "IllegalStateException when preparing MediaRecorder: " + e.getMessage()); } catch (IOException e) { - Log.d("TAG", "====== IOException preparing MediaRecorder: " + e.getMessage()); + Log.d(TAG, "IOException when preparing MediaRecorder: " + e.getMessage()); } mMediaRecorder.start(); - Log.d("TAG", "========= recording start"); - - new Handler().postDelayed(new Runnable() { - @Override - public void run() { - mMediaRecorder.stop(); - mMediaRecorder.release(); - mCamera.stopPreview(); - mCamera.release(); - Log.d("TAG", "========== recording finished."); - } - }, 10000); + + resultReceiver.send(RECORD_RESULT_OK, null); + Log.d(TAG, "Recording is started"); } @Override @@ -152,13 +195,38 @@ public void surfaceDestroyed(SurfaceHolder holder) { wm.addView(sv, params); } else { - Log.d("TAG", "==== get Camera from service failed"); + Log.d(TAG, "Get Camera from service failed"); + resultReceiver.send(RECORD_RESULT_GET_CAMERA_FAILED, null); } } else { - Log.d("TAG", "==== There is no camera hardware on device."); + Log.d(TAG, "There is no camera hardware on device."); + resultReceiver.send(RECORD_RESULT_DEVICE_NO_CAMERA, null); + } + } + + private void handleStopRecordingCommand(Intent intent) { + ResultReceiver resultReceiver = intent.getParcelableExtra(RESULT_RECEIVER); + + if (!mRecording) { + // have not recorded + resultReceiver.send(RECORD_RESULT_NOT_RECORDING, null); + return; } - return super.onStartCommand(intent, flags, startId); + mMediaRecorder.stop(); + mMediaRecorder.release(); + mCamera.stopPreview(); + mCamera.release(); + + Bundle b = new Bundle(); + b.putString(VIDEO_PATH, mRecordingPath); + + mRecordingPath = null; + + resultReceiver.send(RECORD_RESULT_OK, b); + + mRecording = false; + Log.d(TAG, "recording is finished."); } @Override diff --git a/app/src/main/java/example/chatea/servicecamera/MainActivity.java b/app/src/main/java/example/chatea/servicecamera/MainActivity.java index 42e7552..76a41c9 100644 --- a/app/src/main/java/example/chatea/servicecamera/MainActivity.java +++ b/app/src/main/java/example/chatea/servicecamera/MainActivity.java @@ -1,14 +1,20 @@ package example.chatea.servicecamera; import android.app.Activity; -import android.content.Intent; import android.os.Bundle; +import android.os.Handler; +import android.os.ResultReceiver; import android.view.View; import android.widget.Button; +import android.widget.Toast; - +/** + * TODO add keyguard when recording. (Cannot leave app when it is recording) + */ public class MainActivity extends Activity { + private boolean mRecording; + private Button bt_recordingButton; @Override @@ -20,13 +26,68 @@ protected void onCreate(Bundle savedInstanceState) { bt_recordingButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - startRecording(); + if (mRecording) { + stopRecording(); + } else { + startRecording(); + } } }); } private void startRecording() { - Intent intent = new Intent(this, CameraService.class); - startService(intent); + setRecording(true); + + ResultReceiver receiver = new ResultReceiver(new Handler()) { + @Override + protected void onReceiveResult(int resultCode, Bundle resultData) { + handleStartRecordingResult(resultCode, resultData); + } + }; + + CameraService.startToStartRecording(this, receiver); + } + + private void stopRecording() { + setRecording(false); + + ResultReceiver receiver = new ResultReceiver(new Handler()) { + @Override + protected void onReceiveResult(int resultCode, Bundle resultData) { + handleStopRecordingResult(resultCode, resultData); + } + }; + + CameraService.startToStopRecording(this, receiver); + } + + private void setRecording(boolean recording) { + if (recording) { + mRecording = true; + bt_recordingButton.setText(R.string.stop_recording); + } else { + mRecording = false; + bt_recordingButton.setText(R.string.start_recording); + } + } + + private void handleStartRecordingResult(int resultCode, Bundle resultData) { + if (resultCode == CameraService.RECORD_RESULT_OK) { + Toast.makeText(this, "Start recording...", Toast.LENGTH_SHORT).show(); + } else { + // start recording failed. + Toast.makeText(this, "Start recording failed...", Toast.LENGTH_SHORT).show(); + setRecording(false); + } + } + + private void handleStopRecordingResult(int resultCode, Bundle resultData) { + if (resultCode == CameraService.RECORD_RESULT_OK) { + String videoPath = resultData.getString(CameraService.VIDEO_PATH); + Toast.makeText(this, "Record succeed, file saved in " + videoPath, + Toast.LENGTH_LONG).show(); + } else { + Toast.makeText(this, "Record failed...", Toast.LENGTH_SHORT).show(); + } } } diff --git a/app/src/main/java/example/chatea/servicecamera/myVideoList.java b/app/src/main/java/example/chatea/servicecamera/myVideoList.java new file mode 100644 index 0000000..8b3d48e --- /dev/null +++ b/app/src/main/java/example/chatea/servicecamera/myVideoList.java @@ -0,0 +1,24 @@ +package example.chatea.servicecamera; + +import android.support.v7.app.ActionBarActivity; +import android.os.Bundle; +import android.widget.ListAdapter; +import android.widget.ListView; +import android.widget.SimpleAdapter; + +public class myVideoList extends ActionBarActivity { + + private ListView lv_myVideoList; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_my_video_list); + lv_myVideoList = (ListView) findViewById(R.id.my_video_listview); + ListAdapter adapter = new SimpleAdapter( + this, myVideoList, + R.layout.my_video_list_item, new String[] { PreferSet.TAG_CALLED_RECORD_NUMBER, PreferSet.TAG_CALLED_RECORDS_TIME} + , new int[] { R.id.my_videoview_item}); + lv_myVideoList.setAdapter(adapter); + } +} diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 7174930..19f60e6 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -1,7 +1,8 @@ - + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/start_recording" /> - + diff --git a/app/src/main/res/layout/activity_my_video_list.xml b/app/src/main/res/layout/activity_my_video_list.xml new file mode 100644 index 0000000..a8a2ecb --- /dev/null +++ b/app/src/main/res/layout/activity_my_video_list.xml @@ -0,0 +1,26 @@ + + + + + + + diff --git a/app/src/main/res/layout/my_video_list_item.xml b/app/src/main/res/layout/my_video_list_item.xml new file mode 100644 index 0000000..1f3272a --- /dev/null +++ b/app/src/main/res/layout/my_video_list_item.xml @@ -0,0 +1,16 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index e485277..bf3e0c8 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -3,4 +3,7 @@ Hello world! Settings + + Start Recording + Stop Recording From 952b2d8119fb1c6b741fdb861bbb1989366d49a2 Mon Sep 17 00:00:00 2001 From: Ymow Wu Date: Mon, 11 Apr 2016 19:49:25 +0800 Subject: [PATCH 2/2] add PhoneCall BroadcastReceiver with ServiceCarema Recording merge start/stop recording feature during Incoming and OutGoing PhoneCall State. PhoneCallReceiver will trigger the ServiceCarema recording. After recording is finished, send loca Push Notification. add VideoPlayer after click local push notification When phone call finish will let media recording` finsh and send push notification, click the item will make PhoneCall video play again. issue:When ServiceCarema get onStartCommand probably crash onStartCommand is execute by startToStartRecording, means some condition make context of PhoneCall is Null. Update gitignore and remove untracking files Ignore all files in .idea/ folder remote conflicts ff --- app/src/main/AndroidManifest.xml | 12 +- .../chatea/servicecamera/CameraService.java | 48 +++++- .../chatea/servicecamera/MainActivity.java | 2 +- .../servicecamera/PhoneCallVideoPlayer.java | 29 ++++ .../servicecamera/PhonecallReceiver.java | 156 ++++++++++++++++++ .../chatea/servicecamera/myVideoList.java | 24 --- .../main/res/layout/my_video_list_item.xml | 16 -- ...o_list.xml => phone_call_video_player.xml} | 6 +- gradle/wrapper/gradle-wrapper.properties | 4 +- 9 files changed, 248 insertions(+), 49 deletions(-) create mode 100644 app/src/main/java/example/chatea/servicecamera/PhoneCallVideoPlayer.java create mode 100644 app/src/main/java/example/chatea/servicecamera/PhonecallReceiver.java delete mode 100644 app/src/main/java/example/chatea/servicecamera/myVideoList.java delete mode 100644 app/src/main/res/layout/my_video_list_item.xml rename app/src/main/res/layout/{activity_my_video_list.xml => phone_call_video_player.xml} (88%) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 001b597..245b11f 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -24,11 +24,21 @@ + + + - + + + + + + + \ No newline at end of file diff --git a/app/src/main/java/example/chatea/servicecamera/CameraService.java b/app/src/main/java/example/chatea/servicecamera/CameraService.java index a8438c0..7e10af8 100644 --- a/app/src/main/java/example/chatea/servicecamera/CameraService.java +++ b/app/src/main/java/example/chatea/servicecamera/CameraService.java @@ -1,15 +1,22 @@ package example.chatea.servicecamera; +import android.app.Notification; +import android.app.NotificationManager; +import android.app.PendingIntent; import android.app.Service; import android.content.Context; import android.content.Intent; + +import android.graphics.BitmapFactory; import android.graphics.PixelFormat; import android.hardware.Camera; import android.media.CamcorderProfile; import android.media.MediaRecorder; + import android.os.Bundle; import android.os.IBinder; import android.os.ResultReceiver; + import android.util.Log; import android.view.SurfaceHolder; import android.view.SurfaceView; @@ -28,7 +35,7 @@ public class CameraService extends Service { public static final String VIDEO_PATH = "recordedVideoPath"; public static final int RECORD_RESULT_OK = 0; - public static final int RECORD_RESULT_DEVICE_NO_CAMERA= 1; + public static final int RECORD_RESULT_DEVICE_NO_CAMERA = 1; public static final int RECORD_RESULT_GET_CAMERA_FAILED = 2; public static final int RECORD_RESULT_ALREADY_RECORDING = 3; public static final int RECORD_RESULT_NOT_RECORDING = 4; @@ -38,11 +45,13 @@ public class CameraService extends Service { private static final int COMMAND_START_RECORDING = 0; private static final int COMMAND_STOP_RECORDING = 1; + private int i = 1; private Camera mCamera; private MediaRecorder mMediaRecorder; private boolean mRecording = false; private String mRecordingPath = null; + private String mRecordingPathCache = null; public CameraService() { } @@ -86,6 +95,7 @@ public void onPictureTaken(byte[] data, Camera camera) { @Override public int onStartCommand(Intent intent, int flags, int startId) { switch (intent.getIntExtra(START_SERVICE_COMMAND, COMMAND_NONE)) { + //TODO bug:Sometime intent.getIntExtra is Null case COMMAND_START_RECORDING: handleStartRecordingCommand(intent); break; @@ -95,7 +105,6 @@ public int onStartCommand(Intent intent, int flags, int startId) { default: throw new UnsupportedOperationException("Cannot start service with illegal commands"); } - return START_STICKY; } @@ -221,12 +230,46 @@ private void handleStopRecordingCommand(Intent intent) { Bundle b = new Bundle(); b.putString(VIDEO_PATH, mRecordingPath); + mRecordingPathCache = mRecordingPath; mRecordingPath = null; resultReceiver.send(RECORD_RESULT_OK, b); mRecording = false; Log.d(TAG, "recording is finished."); + + //Send locall Notification + newHaloMovieReminder(); + } + + private void newHaloMovieReminder() { + try { + NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); + Notification.Builder builder = new Notification.Builder(this); + Intent intent = new Intent(this, PhoneCallVideoPlayer.class); + intent.putExtra(VIDEO_PATH, mRecordingPathCache); + intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); + PendingIntent contentIndent = PendingIntent.getActivity( + this, 0, intent, + PendingIntent.FLAG_ONE_SHOT); + builder.setContentIntent(contentIndent) + .setSmallIcon(R.mipmap.ic_launcher) + .setLargeIcon( + BitmapFactory.decodeResource(this.getResources(), + R.mipmap.ic_launcher)) + .setTicker("Halo | PhoneCall Movie") + .setWhen(System.currentTimeMillis()) + .setAutoCancel(true) + .setContentTitle("Halo") + .setContentText("get new PhoneCall Movie"); + Notification notification = builder.getNotification(); + notification.defaults |= Notification.DEFAULT_SOUND; + notification.defaults |= Notification.DEFAULT_LIGHTS; + notificationManager.notify(1, notification); + i++; // for multiple Notification lines + } catch (Exception e) { + Log.d(TAG, "Notification something wrong"); + } } @Override @@ -234,4 +277,5 @@ public IBinder onBind(Intent intent) { // TODO: Return the communication channel to the service. throw new UnsupportedOperationException("Not yet implemented"); } + } diff --git a/app/src/main/java/example/chatea/servicecamera/MainActivity.java b/app/src/main/java/example/chatea/servicecamera/MainActivity.java index 76a41c9..491ef61 100644 --- a/app/src/main/java/example/chatea/servicecamera/MainActivity.java +++ b/app/src/main/java/example/chatea/servicecamera/MainActivity.java @@ -90,4 +90,4 @@ private void handleStopRecordingResult(int resultCode, Bundle resultData) { Toast.makeText(this, "Record failed...", Toast.LENGTH_SHORT).show(); } } -} +} \ No newline at end of file diff --git a/app/src/main/java/example/chatea/servicecamera/PhoneCallVideoPlayer.java b/app/src/main/java/example/chatea/servicecamera/PhoneCallVideoPlayer.java new file mode 100644 index 0000000..805b991 --- /dev/null +++ b/app/src/main/java/example/chatea/servicecamera/PhoneCallVideoPlayer.java @@ -0,0 +1,29 @@ +package example.chatea.servicecamera; + +import android.content.Intent; +import android.net.Uri; +import android.support.v7.app.ActionBarActivity; +import android.os.Bundle; +import android.util.Log; +import android.widget.MediaController; +import android.widget.VideoView; + +public class PhoneCallVideoPlayer extends ActionBarActivity { + + private VideoView mVideoView; + private static final String TAG = PhoneCallVideoPlayer.class.getSimpleName();; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.phone_call_video_player); + mVideoView = (VideoView) findViewById(R.id.my_videoview); + Intent intent = this.getIntent(); + String mRecordingPath = intent.getStringExtra(CameraService.VIDEO_PATH); + Log.i(TAG, mRecordingPath); + mVideoView.setVideoURI(Uri.parse(mRecordingPath)); + mVideoView.setMediaController(new MediaController(this)); + mVideoView.requestFocus(); + mVideoView.start(); + } +} diff --git a/app/src/main/java/example/chatea/servicecamera/PhonecallReceiver.java b/app/src/main/java/example/chatea/servicecamera/PhonecallReceiver.java new file mode 100644 index 0000000..c1354a7 --- /dev/null +++ b/app/src/main/java/example/chatea/servicecamera/PhonecallReceiver.java @@ -0,0 +1,156 @@ +package example.chatea.servicecamera; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.os.Handler; +import android.os.ResultReceiver; +import android.telephony.TelephonyManager; +import android.util.Log; +import android.widget.Toast; + +import java.util.Date; + +public class PhoneCallReceiver extends BroadcastReceiver { + + //The receiver will be recreated whenever android feels like it. We need a static variable to remember data between instantiations + + private static int lastState = TelephonyManager.CALL_STATE_IDLE; + private static Date callStartTime; + private static boolean isIncoming; + private static String savedNumber; //because the passed incoming is only valid in ringing + private static String TAG = "PhoneCallReceiver"; + private boolean mRecording; + + + @Override + public void onReceive(Context context, Intent intent) { + + //We listen to two intents. The new outgoing call only tells us of an outgoing call. We use it to get the number. + if (intent.getAction().equals("android.intent.action.NEW_OUTGOING_CALL")) { + savedNumber = intent.getExtras().getString("android.intent.extra.PHONE_NUMBER"); + Log.d(TAG, "NEW_OUTGOING_CALL"); + } else { + String stateStr = intent.getExtras().getString(TelephonyManager.EXTRA_STATE); + String number = intent.getExtras().getString(TelephonyManager.EXTRA_INCOMING_NUMBER); + Log.d(TAG, stateStr + " with " + number); + int state = 0; + if (stateStr.equals(TelephonyManager.EXTRA_STATE_IDLE)) { + state = TelephonyManager.CALL_STATE_IDLE; + } else if (stateStr.equals(TelephonyManager.EXTRA_STATE_OFFHOOK)) { + state = TelephonyManager.CALL_STATE_OFFHOOK; + } else if (stateStr.equals(TelephonyManager.EXTRA_STATE_RINGING)) { + state = TelephonyManager.CALL_STATE_RINGING; + } + onCallStateChanged(context, state, number); + } + } + + //Derived classes should override these to respond to specific events of interest + protected void onIncomingCallStarted(Context ctx, String number, Date start) { + tryToRecording(ctx); + } + + protected void onOutgoingCallStarted(Context ctx, String number, Date start) { + tryToRecording(ctx); + } + + protected void onIncomingCallEnded(Context ctx, String number, Date start, Date end) { + tryToStopRecording(ctx); + } + + protected void onOutgoingCallEnded(Context ctx, String number, Date start, Date end) { + tryToStopRecording(ctx); + } + + protected void onMissedCall(Context ctx, String number, Date start) { + tryToStopRecording(ctx); + } + + //Deals with actual events + + //Incoming call- goes from IDLE to RINGING when it rings, to OFFHOOK when it's answered, to IDLE when its hung up + //Outgoing call- goes from IDLE to OFFHOOK when it dials out, to IDLE when hung up + public void onCallStateChanged(Context context, int state, String number) { + if (lastState == state) { + //No change, debounce extras + return; + } + switch (state) { + case TelephonyManager.CALL_STATE_RINGING: + isIncoming = true; + callStartTime = new Date(); + savedNumber = number; + onIncomingCallStarted(context, number, callStartTime); + Log.d(TAG, "CALL_STATE_RINGING"); + break; + case TelephonyManager.CALL_STATE_OFFHOOK: + //Transition of ringing->offhook are pickups of incoming calls. Nothing done on them + if (lastState != TelephonyManager.CALL_STATE_RINGING) { + isIncoming = false; + callStartTime = new Date(); + onOutgoingCallStarted(context, savedNumber, callStartTime); + Log.d(TAG, "CALL_STATE_OFFHOOK"); + } + break; + case TelephonyManager.CALL_STATE_IDLE: + Log.d(TAG, "CALL_STATE_IDLE"); + //Went to idle- this is the end of a call. What type depends on previous state(s) + if (lastState == TelephonyManager.CALL_STATE_RINGING) { + //Ring but no pickup- a miss + onMissedCall(context, savedNumber, callStartTime); + } else if (isIncoming) { + onIncomingCallEnded(context, savedNumber, callStartTime, new Date()); + } else { + onOutgoingCallEnded(context, savedNumber, callStartTime, new Date()); + } + Log.d("tryToStopRecording", "mRecording =" + String.valueOf(mRecording)); + break; + } + lastState = state; + } + + private void setRecording(boolean recording) { + mRecording = recording; + } + + private void tryToRecording(Context context) { + if (mRecording) { + Toast.makeText(context, "Already recording...", Toast.LENGTH_SHORT).show(); + return; + } + startRecording(context); + } + + private void tryToStopRecording(Context context) { + if (!mRecording) { + stopRecording(context); + Toast.makeText(context, "stop recording...", Toast.LENGTH_SHORT).show(); + } else { + Toast.makeText(context, "recording?" + String.valueOf(mRecording), Toast.LENGTH_SHORT).show(); + } + } + + private void startRecording(Context context) { + setRecording(true); + ResultReceiver receiver = new ResultReceiver(new Handler()) { + @Override + protected void onReceiveResult(int resultCode, Bundle resultData) { + } + }; + CameraService.startToStartRecording(context, receiver); + } + + private void stopRecording(Context context) { + setRecording(false); + ResultReceiver receiver = new ResultReceiver(new Handler()) { + @Override + protected void onReceiveResult(int resultCode, Bundle resultData) { + } + }; + CameraService.startToStopRecording(context, receiver); + } + + +} \ No newline at end of file diff --git a/app/src/main/java/example/chatea/servicecamera/myVideoList.java b/app/src/main/java/example/chatea/servicecamera/myVideoList.java deleted file mode 100644 index 8b3d48e..0000000 --- a/app/src/main/java/example/chatea/servicecamera/myVideoList.java +++ /dev/null @@ -1,24 +0,0 @@ -package example.chatea.servicecamera; - -import android.support.v7.app.ActionBarActivity; -import android.os.Bundle; -import android.widget.ListAdapter; -import android.widget.ListView; -import android.widget.SimpleAdapter; - -public class myVideoList extends ActionBarActivity { - - private ListView lv_myVideoList; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_my_video_list); - lv_myVideoList = (ListView) findViewById(R.id.my_video_listview); - ListAdapter adapter = new SimpleAdapter( - this, myVideoList, - R.layout.my_video_list_item, new String[] { PreferSet.TAG_CALLED_RECORD_NUMBER, PreferSet.TAG_CALLED_RECORDS_TIME} - , new int[] { R.id.my_videoview_item}); - lv_myVideoList.setAdapter(adapter); - } -} diff --git a/app/src/main/res/layout/my_video_list_item.xml b/app/src/main/res/layout/my_video_list_item.xml deleted file mode 100644 index 1f3272a..0000000 --- a/app/src/main/res/layout/my_video_list_item.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/activity_my_video_list.xml b/app/src/main/res/layout/phone_call_video_player.xml similarity index 88% rename from app/src/main/res/layout/activity_my_video_list.xml rename to app/src/main/res/layout/phone_call_video_player.xml index a8a2ecb..4f480ca 100644 --- a/app/src/main/res/layout/activity_my_video_list.xml +++ b/app/src/main/res/layout/phone_call_video_player.xml @@ -7,11 +7,11 @@ android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" - tools:context="example.chatea.servicecamera.myVideoList"> + tools:context="example.chatea.servicecamera.PhoneCallVideoPlayer"> -