From 3ccdf162809967582bf2ef7e6144a137af28c659 Mon Sep 17 00:00:00 2001 From: Alexey Kulish Date: Wed, 23 Dec 2015 20:11:58 +0300 Subject: [PATCH] Improved audio/video notes plugin --- .../circle_outline_background_normal.xml | 11 + .../circle_outline_background_style.xml | 4 + .../orange_circle_background_normal.xml | 5 + .../orange_circle_background_pressed.xml | 5 + .../orange_circle_background_style.xml | 5 + .../layout-land/recording_note_fragment.xml | 50 +++- OsmAnd/res/layout/recording_note_fragment.xml | 50 +++- .../recording_note_fragment_fullscreen.xml | 169 ++++++++++++ OsmAnd/src/net/osmand/AndroidUtils.java | 17 ++ .../AudioVideoNoteRecordingMenu.java | 158 ++++++++--- ...AudioVideoNoteRecordingMenuFullScreen.java | 83 ++++++ ...eoNoteRecordingMenuFullScreenFragment.java | 63 +++++ .../audionotes/AudioVideoNotesPlugin.java | 261 +++++++++++++----- .../MapContextMenuFragment.java | 20 +- 14 files changed, 767 insertions(+), 134 deletions(-) create mode 100644 OsmAnd/res/drawable/circle_outline_background_normal.xml create mode 100644 OsmAnd/res/drawable/circle_outline_background_style.xml create mode 100644 OsmAnd/res/drawable/orange_circle_background_normal.xml create mode 100644 OsmAnd/res/drawable/orange_circle_background_pressed.xml create mode 100644 OsmAnd/res/drawable/orange_circle_background_style.xml create mode 100644 OsmAnd/res/layout/recording_note_fragment_fullscreen.xml create mode 100644 OsmAnd/src/net/osmand/plus/audionotes/AudioVideoNoteRecordingMenuFullScreen.java create mode 100644 OsmAnd/src/net/osmand/plus/audionotes/AudioVideoNoteRecordingMenuFullScreenFragment.java diff --git a/OsmAnd/res/drawable/circle_outline_background_normal.xml b/OsmAnd/res/drawable/circle_outline_background_normal.xml new file mode 100644 index 0000000000..6081ceab22 --- /dev/null +++ b/OsmAnd/res/drawable/circle_outline_background_normal.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/OsmAnd/res/drawable/circle_outline_background_style.xml b/OsmAnd/res/drawable/circle_outline_background_style.xml new file mode 100644 index 0000000000..3e220e9194 --- /dev/null +++ b/OsmAnd/res/drawable/circle_outline_background_style.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/OsmAnd/res/drawable/orange_circle_background_normal.xml b/OsmAnd/res/drawable/orange_circle_background_normal.xml new file mode 100644 index 0000000000..70ec7cb0b6 --- /dev/null +++ b/OsmAnd/res/drawable/orange_circle_background_normal.xml @@ -0,0 +1,5 @@ + + + \ No newline at end of file diff --git a/OsmAnd/res/drawable/orange_circle_background_pressed.xml b/OsmAnd/res/drawable/orange_circle_background_pressed.xml new file mode 100644 index 0000000000..152de49876 --- /dev/null +++ b/OsmAnd/res/drawable/orange_circle_background_pressed.xml @@ -0,0 +1,5 @@ + + + \ No newline at end of file diff --git a/OsmAnd/res/drawable/orange_circle_background_style.xml b/OsmAnd/res/drawable/orange_circle_background_style.xml new file mode 100644 index 0000000000..d09b811c3d --- /dev/null +++ b/OsmAnd/res/drawable/orange_circle_background_style.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/OsmAnd/res/layout-land/recording_note_fragment.xml b/OsmAnd/res/layout-land/recording_note_fragment.xml index 57593cf2ba..d8e9ff4602 100644 --- a/OsmAnd/res/layout-land/recording_note_fragment.xml +++ b/OsmAnd/res/layout-land/recording_note_fragment.xml @@ -33,7 +33,7 @@ android:orientation="horizontal"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/OsmAnd/src/net/osmand/AndroidUtils.java b/OsmAnd/src/net/osmand/AndroidUtils.java index 73fc807b50..3ddd1c48be 100644 --- a/OsmAnd/src/net/osmand/AndroidUtils.java +++ b/OsmAnd/src/net/osmand/AndroidUtils.java @@ -2,11 +2,13 @@ package net.osmand; import android.annotation.SuppressLint; +import android.app.Activity; import android.content.Context; import android.content.res.Configuration; import android.content.res.Resources; import android.os.Build; import android.text.format.DateFormat; +import android.util.DisplayMetrics; import android.util.TypedValue; import android.view.View; import android.view.ViewParent; @@ -116,4 +118,19 @@ public class AndroidUtils { ); } + public static int getStatusBarHeight(Context ctx) { + int result = 0; + int resourceId = ctx.getResources().getIdentifier("status_bar_height", "dimen", "android"); + if (resourceId > 0) { + result = ctx.getResources().getDimensionPixelSize(resourceId); + } + return result; + } + + public static int getScreenHeight(Activity activity) { + DisplayMetrics dm = new DisplayMetrics(); + activity.getWindowManager().getDefaultDisplay().getMetrics(dm); + return dm.heightPixels; + } + } diff --git a/OsmAnd/src/net/osmand/plus/audionotes/AudioVideoNoteRecordingMenu.java b/OsmAnd/src/net/osmand/plus/audionotes/AudioVideoNoteRecordingMenu.java index 36497cc577..054a028d01 100644 --- a/OsmAnd/src/net/osmand/plus/audionotes/AudioVideoNoteRecordingMenu.java +++ b/OsmAnd/src/net/osmand/plus/audionotes/AudioVideoNoteRecordingMenu.java @@ -1,8 +1,7 @@ package net.osmand.plus.audionotes; -import android.content.res.Resources; import android.os.Handler; -import android.util.TypedValue; +import android.util.DisplayMetrics; import android.view.SurfaceView; import android.view.View; import android.view.ViewGroup; @@ -10,6 +9,7 @@ import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; +import net.osmand.AndroidUtils; import net.osmand.plus.IconsCache; import net.osmand.plus.R; import net.osmand.plus.activities.MapActivity; @@ -21,42 +21,84 @@ import net.osmand.util.Algorithms; import java.util.Timer; import java.util.TimerTask; -import static android.util.TypedValue.COMPLEX_UNIT_DIP; - public class AudioVideoNoteRecordingMenu { - private View view; - private LinearLayout viewfinder; - private AudioVideoNotesPlugin plugin; - private long startTime; - private Handler handler; - private boolean portraitMode; - private boolean largeDevice; - private Timer recTimer; + protected View view; + protected LinearLayout viewfinder; + + protected AudioVideoNotesPlugin plugin; + protected long startTime; + protected Handler handler; + protected boolean portraitMode; + protected boolean largeDevice; + protected Timer recTimer; + + protected double lat; + protected double lon; + + private int screenHeight; + private int buttonsHeight; + private int statusBarHeight; public static boolean showViewfinder = true; - public AudioVideoNoteRecordingMenu(AudioVideoNotesPlugin plugin) { + public AudioVideoNoteRecordingMenu(AudioVideoNotesPlugin plugin, double lat, double lon) { this.plugin = plugin; + this.lat = lat; + this.lon = lon; handler = new Handler(); MapActivity mapActivity = plugin.getMapActivity(); portraitMode = AndroidUiHelper.isOrientationPortrait(mapActivity); largeDevice = AndroidUiHelper.isXLargeDevice(mapActivity); - view = mapActivity.findViewById(R.id.recording_note_layout); + initView(mapActivity); viewfinder = (LinearLayout) view.findViewById(R.id.viewfinder); showViewfinder = true; + screenHeight = AndroidUtils.getScreenHeight(getMapActivity()); + statusBarHeight = AndroidUtils.getStatusBarHeight(getMapActivity()); + buttonsHeight = getMapActivity().getResources().getDimensionPixelSize(R.dimen.map_route_buttons_height); + update(); } + public MapActivity getMapActivity() { + return plugin.getMapActivity(); + } + + protected void initView(MapActivity mapActivity) { + view = mapActivity.findViewById(R.id.recording_note_layout); + } + public SurfaceView prepareSurfaceView() { + return prepareSurfaceView(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); + } + + public SurfaceView prepareSurfaceView(int width, int height) { + int w = width; + int h = height; + if (w != ViewGroup.LayoutParams.MATCH_PARENT && h != ViewGroup.LayoutParams.MATCH_PARENT) { + int vfw = getViewfinderWidth(); + int vfh = getViewfinderHeight(); + float vfRatio = vfw / (float) vfh; + float sourceRatio; + if (vfRatio > 1) { + sourceRatio = width / (float) height; + } else { + sourceRatio = height / (float) width; + } + if (sourceRatio > vfRatio) { + w = vfw; + h = (int) (w / sourceRatio); + } else { + h = vfh; + w = (int) (h * sourceRatio); + } + } viewfinder.removeAllViews(); SurfaceView surfaceView = new SurfaceView(viewfinder.getContext()); - surfaceView.setLayoutParams(new LinearLayout.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.MATCH_PARENT)); + surfaceView.setLayoutParams(new LinearLayout.LayoutParams(w, h)); surfaceView.setZOrderMediaOverlay(true); viewfinder.addView(surfaceView); @@ -85,29 +127,29 @@ public class AudioVideoNoteRecordingMenu { CurrentRecording recording = plugin.getCurrentRecording(); IconsCache iconsCache = plugin.getMapActivity().getMyApplication().getIconsCache(); - ImageView showHideIcon = (ImageView) view.findViewById(R.id.showHideIcon); - View showHideView = view.findViewById(R.id.showHideView); + ImageView leftButtonIcon = (ImageView) view.findViewById(R.id.leftButtonIcon); + View leftButtonView = view.findViewById(R.id.leftButtonView); if (recording.getType() != AVActionType.REC_AUDIO) { - showHideIcon.setImageDrawable(iconsCache.getContentIcon(R.drawable.ic_action_minimize)); - TextView showHideText = (TextView) view.findViewById(R.id.showHideText); + leftButtonIcon.setImageDrawable(iconsCache.getContentIcon(R.drawable.ic_action_minimize)); + TextView showHideText = (TextView) view.findViewById(R.id.leftButtonText); showHideText.setText(showViewfinder ? view.getResources().getString(R.string.shared_string_hide) : view.getResources().getString(R.string.shared_string_show)); - showHideView.setVisibility(View.VISIBLE); + leftButtonView.setVisibility(View.VISIBLE); viewfinder.setVisibility(showViewfinder ? View.VISIBLE : View.GONE); } else { - showHideView.setVisibility(View.INVISIBLE); + leftButtonView.setVisibility(View.INVISIBLE); viewfinder.setVisibility(View.GONE); } - showHideView.setOnClickListener(new View.OnClickListener() { + leftButtonView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { showHideViewfinder(); } }); - View recView = view.findViewById(R.id.recView); - ImageView recIcon = (ImageView) view.findViewById(R.id.recIcon); - TextView recText = (TextView) view.findViewById(R.id.recText); + View centerButtonView = view.findViewById(R.id.centerButtonView); + ImageView recIcon = (ImageView) view.findViewById(R.id.centerButtonIcon); + TextView recText = (TextView) view.findViewById(R.id.centerButtonText); View timeView = view.findViewById(R.id.timeView); switch (recording.getType()) { case REC_AUDIO: @@ -124,7 +166,7 @@ public class AudioVideoNoteRecordingMenu { timeView.setVisibility(View.INVISIBLE); break; } - recView.setOnClickListener(new View.OnClickListener() { + centerButtonView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { rec(plugin.getMapActivity()); @@ -139,7 +181,7 @@ public class AudioVideoNoteRecordingMenu { timeText.setText(Algorithms.formatDuration(duration)); } - private void applyViewfinderVisibility() { + protected void applyViewfinderVisibility() { MapActivity mapActivity = plugin.getMapActivity(); CurrentRecording recording = plugin.getCurrentRecording(); boolean show = showViewfinder && recording != null && recording.getType() != AVActionType.REC_AUDIO; @@ -147,7 +189,7 @@ public class AudioVideoNoteRecordingMenu { int buttonsHeight = view.findViewById(R.id.buttonsContainer).getHeight(); int tileBoxHeight = mapActivity.getMapView().getCurrentRotatedTileBox().getPixHeight(); int h = show ? tileBoxHeight : buttonsHeight; - view.setLayoutParams(new LinearLayout.LayoutParams(dpToPx(320f, mapActivity), h)); + view.setLayoutParams(new LinearLayout.LayoutParams(AndroidUtils.dpToPx(mapActivity, 320f), h)); view.requestLayout(); } viewfinder.setVisibility(show ? View.VISIBLE : View.GONE); @@ -155,17 +197,43 @@ public class AudioVideoNoteRecordingMenu { public void showHideViewfinder() { showViewfinder = !showViewfinder; - TextView showHideText = (TextView) view.findViewById(R.id.showHideText); + TextView showHideText = (TextView) view.findViewById(R.id.leftButtonText); showHideText.setText(showViewfinder ? view.getResources().getString(R.string.shared_string_hide) : view.getResources().getString(R.string.shared_string_show)); applyViewfinderVisibility(); } public int getViewfinderWidth() { - return viewfinder.getWidth(); + int res; + CurrentRecording recording = plugin.getCurrentRecording(); + if (recording.getType() == AVActionType.REC_PHOTO) { + DisplayMetrics dm = new DisplayMetrics(); + getMapActivity().getWindowManager().getDefaultDisplay().getMetrics(dm); + res = dm.widthPixels; + } else { + if (isLandscapeLayout()) { + res = AndroidUtils.dpToPx(getMapActivity(), 320 - 16f); + } else { + res = AndroidUtils.dpToPx(getMapActivity(), 240f); + } + } + return res; } public int getViewfinderHeight() { - return viewfinder.getHeight(); + int res; + CurrentRecording recording = plugin.getCurrentRecording(); + if (recording.getType() == AVActionType.REC_PHOTO) { + DisplayMetrics dm = new DisplayMetrics(); + getMapActivity().getWindowManager().getDefaultDisplay().getMetrics(dm); + res = dm.heightPixels; + } else { + if (isLandscapeLayout()) { + res = screenHeight - statusBarHeight - buttonsHeight; + } else { + res = AndroidUtils.dpToPx(getMapActivity(), 240f); + } + } + return res; } public void rec(final MapActivity mapActivity) { @@ -185,6 +253,21 @@ public class AudioVideoNoteRecordingMenu { }, 200); } + public void recExternal(final MapActivity mapActivity) { + stopCounter(); + handler.postDelayed(new Runnable() { + @Override + public void run() { + CurrentRecording recording = plugin.getCurrentRecording(); + if (recording != null) { + if (recording.getType() == AVActionType.REC_PHOTO) { + plugin.takePhotoExternal(lat, lon, mapActivity); + } + } + } + }, 20); + } + private void startCounter() { startTime = System.currentTimeMillis(); @@ -213,13 +296,4 @@ public class AudioVideoNoteRecordingMenu { recTimer = null; } } - - private int dpToPx(float dp, MapActivity mapActivity) { - Resources r = mapActivity.getResources(); - return (int) TypedValue.applyDimension( - COMPLEX_UNIT_DIP, - dp, - r.getDisplayMetrics() - ); - } } diff --git a/OsmAnd/src/net/osmand/plus/audionotes/AudioVideoNoteRecordingMenuFullScreen.java b/OsmAnd/src/net/osmand/plus/audionotes/AudioVideoNoteRecordingMenuFullScreen.java new file mode 100644 index 0000000000..9103cc6646 --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/audionotes/AudioVideoNoteRecordingMenuFullScreen.java @@ -0,0 +1,83 @@ +package net.osmand.plus.audionotes; + +import android.support.v4.app.Fragment; +import android.view.View; + +import net.osmand.plus.R; +import net.osmand.plus.activities.MapActivity; + +import java.lang.ref.WeakReference; + +public class AudioVideoNoteRecordingMenuFullScreen extends AudioVideoNoteRecordingMenu { + + public AudioVideoNoteRecordingMenuFullScreen(AudioVideoNotesPlugin plugin, double lat, double lon) { + super(plugin, lat, lon); + } + + protected void initView(MapActivity mapActivity) { + mapActivity.getContextMenu().hide(); + AudioVideoNoteRecordingMenuFullScreenFragment.showInstance(this); + WeakReference fragmentRef = findMenuFragment(); + if (fragmentRef != null) { + view = fragmentRef.get().getView(); + } + if (view == null) { + super.initView(mapActivity); + } + } + + @Override + protected void applyViewfinderVisibility() { + } + + public void show() { + } + + public void hide() { + plugin.stopCamera(); + WeakReference fragmentRef = findMenuFragment(); + if (fragmentRef != null) { + fragmentRef.get().dismiss(); + } + } + + public void update() { + View leftButtonView = view.findViewById(R.id.leftButtonView); + leftButtonView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + plugin.shootAgain(); + } + }); + + View centerButtonView = view.findViewById(R.id.centerButtonView); + centerButtonView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + finishRecording(); + } + }); + + View rightButtonView = view.findViewById(R.id.rightButtonView); + rightButtonView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + plugin.finishPhotoRecording(true); + recExternal(plugin.getMapActivity()); + } + }); + } + + public void finishRecording() { + plugin.finishPhotoRecording(false); + } + + public WeakReference findMenuFragment() { + Fragment fragment = getMapActivity().getSupportFragmentManager().findFragmentByTag(AudioVideoNoteRecordingMenuFullScreenFragment.TAG); + if (fragment != null && !fragment.isDetached()) { + return new WeakReference<>((AudioVideoNoteRecordingMenuFullScreenFragment) fragment); + } else { + return null; + } + } +} diff --git a/OsmAnd/src/net/osmand/plus/audionotes/AudioVideoNoteRecordingMenuFullScreenFragment.java b/OsmAnd/src/net/osmand/plus/audionotes/AudioVideoNoteRecordingMenuFullScreenFragment.java new file mode 100644 index 0000000000..ddcbdd7591 --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/audionotes/AudioVideoNoteRecordingMenuFullScreenFragment.java @@ -0,0 +1,63 @@ +package net.osmand.plus.audionotes; + +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentManager; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.WindowManager; + +import net.osmand.plus.R; + +public class AudioVideoNoteRecordingMenuFullScreenFragment extends Fragment { + public static final String TAG = "AudioVideoNoteRecordingMenuFullScreenFragment"; + + private AudioVideoNoteRecordingMenuFullScreen menu; + private boolean dismissing; + + @Nullable + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + return inflater.inflate(R.layout.recording_note_fragment_fullscreen, container, false); + } + + @Override + public void onResume() { + super.onResume(); + getActivity().getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); + } + + @Override + public void onPause() { + super.onPause(); + getActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + if (!dismissing) { + menu.finishRecording(); + } + } + + public static void showInstance(AudioVideoNoteRecordingMenuFullScreen menu) { + + AudioVideoNoteRecordingMenuFullScreenFragment fragment = new AudioVideoNoteRecordingMenuFullScreenFragment(); + fragment.menu = menu; + FragmentManager fragmentManager = menu.getMapActivity().getSupportFragmentManager(); + fragmentManager.beginTransaction() + //.setCustomAnimations(R.anim.abc_fade_in, R.anim.abc_fade_out, R.anim.abc_fade_in, R.anim.abc_fade_out) + .add(R.id.fragmentContainer, fragment, TAG) + .addToBackStack(TAG).commit(); + + fragmentManager.executePendingTransactions(); + } + + public void dismiss() { + dismissing = true; + getActivity().getSupportFragmentManager().popBackStack(); + } +} diff --git a/OsmAnd/src/net/osmand/plus/audionotes/AudioVideoNotesPlugin.java b/OsmAnd/src/net/osmand/plus/audionotes/AudioVideoNotesPlugin.java index 8cde1521b3..c0ae65e7b3 100644 --- a/OsmAnd/src/net/osmand/plus/audionotes/AudioVideoNotesPlugin.java +++ b/OsmAnd/src/net/osmand/plus/audionotes/AudioVideoNotesPlugin.java @@ -151,8 +151,12 @@ public class AudioVideoNotesPlugin extends OsmandPlugin { private static File mediaRecFile; private static MediaRecorder mediaRec; private File lastTakingPhoto; + private byte[] photoRawData; + private Timer photoTimer; private Camera cam; + private List mSupportedPreviewSizes; private int requestedOrientation; + private boolean autofocus; private AudioVideoNoteRecordingMenu recordingMenu; private CurrentRecording currentRecording; @@ -786,7 +790,7 @@ public class AudioVideoNotesPlugin extends OsmandPlugin { public void mapActivityPause(MapActivity activity) { if (isRecording()) { if (currentRecording.getType() == AVActionType.REC_PHOTO) { - recordingMenu.hide(); + finishPhotoRecording(false); } else { activity.getContextMenu().close(); stopRecording(activity); @@ -804,9 +808,13 @@ public class AudioVideoNotesPlugin extends OsmandPlugin { return currentRecording != null; } - private void initRecMenu(AVActionType actionType) { + private void initRecMenu(AVActionType actionType, double lat, double lon) { currentRecording = new CurrentRecording(actionType); - recordingMenu = new AudioVideoNoteRecordingMenu(this); + if (actionType == AVActionType.REC_PHOTO) { + recordingMenu = new AudioVideoNoteRecordingMenuFullScreen(this, lat, lon); + } else { + recordingMenu = new AudioVideoNoteRecordingMenu(this, lat, lon); + } recordingDone = false; lockScreenOrientation(); } @@ -821,7 +829,7 @@ public class AudioVideoNotesPlugin extends OsmandPlugin { == PackageManager.PERMISSION_GRANTED) { openCamera(); if (cam != null) { - initRecMenu(AVActionType.REC_VIDEO); + initRecMenu(AVActionType.REC_VIDEO, lat, lon); recordVideoCamera(lat, lon, mapActivity); } } else { @@ -835,7 +843,29 @@ public class AudioVideoNotesPlugin extends OsmandPlugin { } public void recordVideoCamera(final double lat, final double lon, final MapActivity mapActivity) { - SurfaceView view = recordingMenu.prepareSurfaceView(); + final CamcorderProfile p = CamcorderProfile.get(AV_VIDEO_QUALITY.get()); + final Camera.Size mPreviewSize; + if (mSupportedPreviewSizes != null) { + int width; + int height; + if (recordingMenu.isLandscapeLayout()) { + width = p.videoFrameWidth; + height = p.videoFrameHeight; + } else { + height = p.videoFrameWidth; + width = p.videoFrameHeight; + } + mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width, height); + } else { + mPreviewSize = null; + } + + final SurfaceView view; + if (mPreviewSize != null) { + view = recordingMenu.prepareSurfaceView(mPreviewSize.width, mPreviewSize.height); + } else { + view = recordingMenu.prepareSurfaceView(); + } view.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); view.getHolder().addCallback(new Callback() { @@ -849,9 +879,19 @@ public class AudioVideoNotesPlugin extends OsmandPlugin { MediaRecorder mr = new MediaRecorder(); try { Parameters parameters = cam.getParameters(); + + // camera focus type + List sfm = parameters.getSupportedFocusModes(); + if (sfm.contains("continuous-video")) { + parameters.setFocusMode("continuous-video"); + } + int cameraOrientation = getCamOrientation(mapActivity, Camera.CameraInfo.CAMERA_FACING_BACK); cam.setDisplayOrientation(cameraOrientation); parameters.set("rotation", cameraOrientation); + if (mPreviewSize != null) { + parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height); + } cam.setParameters(parameters); cam.setPreviewDisplay(holder); cam.startPreview(); @@ -885,7 +925,6 @@ public class AudioVideoNotesPlugin extends OsmandPlugin { giveMediaRecorderHintRotatedScreen(mapActivity, mr); //mr.setPreviewDisplay(holder.getSurface()); - CamcorderProfile p = CamcorderProfile.get(AV_VIDEO_QUALITY.get()); mr.setProfile(p); mr.setOutputFile(f.getAbsolutePath()); try { @@ -936,6 +975,9 @@ public class AudioVideoNotesPlugin extends OsmandPlugin { } try { cam = Camera.open(); + if (mSupportedPreviewSizes == null) { + mSupportedPreviewSizes = cam.getParameters().getSupportedPreviewSizes(); + } } catch (Exception e) { logErr(e); } @@ -964,6 +1006,7 @@ public class AudioVideoNotesPlugin extends OsmandPlugin { protected void stopCamera() { try { if (cam != null) { + cam.cancelAutoFocus(); cam.stopPreview(); cam.setPreviewDisplay(null); } @@ -991,7 +1034,7 @@ public class AudioVideoNotesPlugin extends OsmandPlugin { public void recordAudio(double lat, double lon, final MapActivity mapActivity) { if (ActivityCompat.checkSelfPermission(mapActivity, Manifest.permission.RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED) { - initRecMenu(AVActionType.REC_AUDIO); + initRecMenu(AVActionType.REC_AUDIO, lat, lon); MediaRecorder mr = new MediaRecorder(); final File f = getBaseFileName(lat, lon, app, THREEGP_EXTENSION); mr.setAudioSource(MediaRecorder.AudioSource.MIC); @@ -1035,7 +1078,7 @@ public class AudioVideoNotesPlugin extends OsmandPlugin { private void takePhotoInternalOrExternal(double lat, double lon, MapActivity mapActivity) { openCamera(); if (cam != null) { - initRecMenu(AVActionType.REC_PHOTO); + initRecMenu(AVActionType.REC_PHOTO, lat, lon); takePhotoWithCamera(lat, lon, mapActivity); } else { takePhotoExternal(lat, lon, mapActivity); @@ -1046,7 +1089,31 @@ public class AudioVideoNotesPlugin extends OsmandPlugin { final MapActivity mapActivity) { try { lastTakingPhoto = getBaseFileName(lat, lon, app, IMG_EXTENSION); - final SurfaceView view = recordingMenu.prepareSurfaceView(); + final Camera.Size mPreviewSize; + Parameters parameters = cam.getParameters(); + List psps = parameters.getSupportedPictureSizes(); + int camPicSizeIndex = AV_CAMERA_PICTURE_SIZE.get(); + // camera picture size + log.debug("takePhotoWithCamera() index=" + camPicSizeIndex); + if (camPicSizeIndex == AV_PHOTO_SIZE_DEFAULT) { + camPicSizeIndex = cameraPictureSizeDefault; + log.debug("takePhotoWithCamera() Default value of picture size. Set index to cameraPictureSizeDefault. Now index=" + + camPicSizeIndex); + } + final Camera.Size selectedCamPicSize = psps.get(camPicSizeIndex); + if (mSupportedPreviewSizes != null) { + int width = selectedCamPicSize.width; + int height = selectedCamPicSize.height; + mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width, height); + } else { + mPreviewSize = null; + } + final SurfaceView view; + if (mPreviewSize != null) { + view = recordingMenu.prepareSurfaceView(mPreviewSize.width, mPreviewSize.height); + } else { + view = recordingMenu.prepareSurfaceView(); + } view.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); view.getHolder().addCallback(new Callback() { @@ -1061,13 +1128,11 @@ public class AudioVideoNotesPlugin extends OsmandPlugin { if (AV_PHOTO_PLAY_SOUND.get()) { if (sp == null) sp = new SoundPool(5, AudioManager.STREAM_MUSIC, 0); - log.info("Play sound on photo"); if (shotId == 0) { try { AssetFileDescriptor assetFileDescriptor = app.getAssets().openFd("sounds/camera_click.ogg"); shotId = sp.load(assetFileDescriptor, 1); assetFileDescriptor.close(); - log.debug("loaded file sound ID: " + shotId); } catch (Exception e) { log.error("cannot get shotId for sounds/camera_click.ogg"); } @@ -1075,24 +1140,12 @@ public class AudioVideoNotesPlugin extends OsmandPlugin { } Parameters parameters = cam.getParameters(); - - // camera picture size - List psps = parameters.getSupportedPictureSizes(); - int index = AV_CAMERA_PICTURE_SIZE.get(); - log.debug("takePhotoWithCamera() index=" + index); - if (index == AV_PHOTO_SIZE_DEFAULT) { - index = cameraPictureSizeDefault; - log.debug("takePhotoWithCamera() Default value of picture size. Set index to cameraPictureSizeDefault. Now index=" - + index); - } - Camera.Size selectedCamPicSize = psps.get(index); parameters.setPictureSize(selectedCamPicSize.width, selectedCamPicSize.height); log.debug("takePhotoWithCamera() set Picture size: width=" + selectedCamPicSize.width + " height=" + selectedCamPicSize.height); // camera focus type - boolean autofocus = true; - // boolean autofocus = !Boolean.parseBoolean(parameters.get("auto-exposure-lock-supported")); + autofocus = true; parameters.setGpsLatitude(lat); parameters.setGpsLongitude(lon); switch (AV_CAMERA_FOCUS_TYPE.get()) { @@ -1134,17 +1187,14 @@ public class AudioVideoNotesPlugin extends OsmandPlugin { int cameraOrientation = getCamOrientation(mapActivity, Camera.CameraInfo.CAMERA_FACING_BACK); cam.setDisplayOrientation(cameraOrientation); parameters.set("rotation", cameraOrientation); -// if (cameraOrientation == 0 || cameraOrientation == 180) { -// parameters.setPreviewSize(recordingMenu.getViewfinderWidth(), recordingMenu.getViewfinderHeight()); -// } else { -// parameters.setPreviewSize(recordingMenu.getViewfinderHeight(), recordingMenu.getViewfinderWidth()); -// } + if (mPreviewSize != null) { + parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height); + } cam.setParameters(parameters); cam.setPreviewDisplay(holder); cam.startPreview(); - if (autofocus) { - cam.autoFocus(null); - } + internalShoot(); + } catch (Exception e) { logErr(e); closeRecordingMenu(); @@ -1154,10 +1204,6 @@ public class AudioVideoNotesPlugin extends OsmandPlugin { } } - private void printCamParams(Parameters parameters, boolean autoExposure) { - log.info("Cam params auto exposure=" + autoExposure + " focus_distances=" + parameters.get("focus-distances")); - } - @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } @@ -1171,6 +1217,64 @@ public class AudioVideoNotesPlugin extends OsmandPlugin { } } + + private void internalShoot() { + if (!autofocus) { + cam.takePicture(null, null, new AudioVideoPhotoHandler()); + } else { + cam.autoFocus(new Camera.AutoFocusCallback() { + @Override + public void onAutoFocus(boolean success, Camera camera) { + cam.cancelAutoFocus(); + try { + cam.takePicture(null, null, new AudioVideoPhotoHandler()); + } catch (Exception e) { + logErr(e); + closeRecordingMenu(); + closeCamera(); + finishRecording(); + e.printStackTrace(); + } + } + }); + } + } + + private Camera.Size getOptimalPreviewSize(List sizes, int w, int h) { + final double ASPECT_TOLERANCE = 0.1; + double targetRatio; + if (w > h) { + targetRatio = (double) w / h; + } else { + targetRatio = (double) h / w; + } + + if (sizes == null) return null; + + Camera.Size optimalSize = null; + double minDiff = Double.MAX_VALUE; + + for (Camera.Size size : sizes) { + double ratio = (double) size.width / size.height; + if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue; + if (Math.abs(size.height - h) < minDiff) { + optimalSize = size; + minDiff = Math.abs(size.height - h); + } + } + + if (optimalSize == null) { + minDiff = Double.MAX_VALUE; + for (Camera.Size size : sizes) { + if (Math.abs(size.height - h) < minDiff) { + optimalSize = size; + minDiff = Math.abs(size.height - h); + } + } + } + return optimalSize; + } + private static int getCamOrientation(MapActivity mapActivity, int cameraId) { android.hardware.Camera.CameraInfo info = new android.hardware.Camera.CameraInfo(); @@ -1208,7 +1312,7 @@ public class AudioVideoNotesPlugin extends OsmandPlugin { recordingDone = true; if (cam != null && lastTakingPhoto != null) { try { - cam.takePicture(null, null, new AudioVideoPhotoHandler(lastTakingPhoto)); + cam.takePicture(null, null, new AudioVideoPhotoHandler()); } catch (RuntimeException e) { closeRecordingMenu(); closeCamera(); @@ -1218,7 +1322,7 @@ public class AudioVideoNotesPlugin extends OsmandPlugin { } } - private void takePhotoExternal(double lat, double lon, final MapActivity mapActivity) { + public void takePhotoExternal(double lat, double lon, final MapActivity mapActivity) { Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); final File f = getBaseFileName(lat, lon, app, IMG_EXTENSION); lastTakingPhoto = f; @@ -1626,40 +1730,73 @@ public class AudioVideoNotesPlugin extends OsmandPlugin { } public class AudioVideoPhotoHandler implements PictureCallback { - private File pictureFile; - public AudioVideoPhotoHandler(File fileName) { - this.pictureFile = fileName; + public AudioVideoPhotoHandler() { } @Override - public void onPictureTaken(byte[] data, Camera camera) { - try { - FileOutputStream fos = new FileOutputStream(pictureFile); - fos.write(data); - fos.close(); - indexFile(true, pictureFile); - // play sound after photo - sound file must be loaded at this time: - if (AV_PHOTO_PLAY_SOUND.get()) { - if (sp != null && shotId != 0) { - int ret = sp.play(shotId, 0.7f, 0.7f, 0, 0, 1); - log.debug("play sound shot success!"); - log.debug("sp.play()=" + ret); - // sp.release(); - // sp=null; - // shotId=0 - } else { - log.error("can not play sound on shot - not init SoundPool or not loaded sound"); - } - } + public void onPictureTaken(final byte[] data, Camera camera) { + photoRawData = data; + if (AV_PHOTO_PLAY_SOUND.get()) { + if (sp != null && shotId != 0) { + sp.play(shotId, 0.7f, 0.7f, 0, 0, 1); + } + } + + startPhotoTimer(); + } + } + + private void startPhotoTimer() { + if (photoTimer != null) { + cancelPhotoTimer(); + } + photoTimer = new Timer(); + photoTimer.schedule(new TimerTask() { + @Override + public void run() { + finishPhotoRecording(false); + } + }, 4000); + } + + private void cancelPhotoTimer() { + if (photoTimer != null) { + photoTimer.cancel(); + photoTimer = null; + } + } + + public synchronized void shootAgain() { + cancelPhotoTimer(); + photoRawData = null; + + cam.startPreview(); + internalShoot(); + } + + public synchronized void finishPhotoRecording(boolean cancel) { + cancelPhotoTimer(); + if (photoRawData != null && photoRawData.length > 0 && lastTakingPhoto != null) { + try { + if (!cancel) { + FileOutputStream fos = new FileOutputStream(lastTakingPhoto); + fos.write(photoRawData); + fos.close(); + indexFile(true, lastTakingPhoto); + } } catch (Exception error) { logErr(error); } finally { + photoRawData = null; closeRecordingMenu(); - closeCamera(); - finishRecording(); + if (!cancel) { + finishRecording(); + } } + } else if (cancel) { + closeRecordingMenu(); } } diff --git a/OsmAnd/src/net/osmand/plus/mapcontextmenu/MapContextMenuFragment.java b/OsmAnd/src/net/osmand/plus/mapcontextmenu/MapContextMenuFragment.java index cc966249d5..3bd4e7c273 100644 --- a/OsmAnd/src/net/osmand/plus/mapcontextmenu/MapContextMenuFragment.java +++ b/OsmAnd/src/net/osmand/plus/mapcontextmenu/MapContextMenuFragment.java @@ -10,7 +10,6 @@ import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentManager; -import android.util.DisplayMetrics; import android.util.TypedValue; import android.view.GestureDetector; import android.view.GestureDetector.OnGestureListener; @@ -139,10 +138,10 @@ public class MapContextMenuFragment extends Fragment implements DownloadEvents { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - screenHeight = getScreenHeight(); + screenHeight = AndroidUtils.getScreenHeight(getActivity()); skipHalfScreenStateLimit = screenHeight * SKIP_HALF_SCREEN_STATE_KOEF; - viewHeight = screenHeight - getStatusBarHeight(); + viewHeight = screenHeight - AndroidUtils.getStatusBarHeight(getMapActivity()); fabPaddingTopPx = dpToPx(FAB_PADDING_TOP_DP); markerPaddingPx = dpToPx(MARKER_PADDING_DP); @@ -1150,21 +1149,6 @@ public class MapContextMenuFragment extends Fragment implements DownloadEvents { ); } - private int getScreenHeight() { - DisplayMetrics dm = new DisplayMetrics(); - getActivity().getWindowManager().getDefaultDisplay().getMetrics(dm); - return dm.heightPixels; - } - - public int getStatusBarHeight() { - int result = 0; - int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android"); - if (resourceId > 0) { - result = getResources().getDimensionPixelSize(resourceId); - } - return result; - } - public void updateLocation(boolean centerChanged, boolean locationChanged, boolean compassChanged) { updateDistanceDirection(); }