package com.afollestad.materialcamera.internal;
import android.Manifest;
import android.app.Activity;
import android.app.Fragment;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Color;
import android.media.CamcorderProfile;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.DrawableRes;
import android.support.annotation.IntDef;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.StringRes;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.app.AppCompatDelegate;
import android.util.Log;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import com.afollestad.materialcamera.MaterialCamera;
import com.afollestad.materialcamera.R;
import com.afollestad.materialcamera.TimeLimitReachedException;
import com.afollestad.materialcamera.util.CameraUtil;
import com.afollestad.materialdialogs.DialogAction;
import com.afollestad.materialdialogs.MaterialDialog;
import java.io.File;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.List;
/**
* @author Aidan Follestad (afollestad)
*/
public abstract class BaseCaptureActivity extends AppCompatActivity implements BaseCaptureInterface {
private int mCameraPosition = CAMERA_POSITION_UNKNOWN;
private int mFlashMode = FLASH_MODE_OFF;
private boolean mRequestingPermission;
private long mRecordingStart = -1;
private long mRecordingEnd = -1;
private long mLengthLimit = -1;
private Object mFrontCameraId;
private Object mBackCameraId;
private boolean mDidRecord = false;
private List<Integer> mFlashModes;
private boolean canShowGuide;
public boolean isCanShowGuide() {
return canShowGuide;
}
public void setCanShowGuide(boolean canShowGuide) {
this.canShowGuide = canShowGuide;
}
public static final int PERMISSION_RC = 69;
@IntDef({CAMERA_POSITION_UNKNOWN, CAMERA_POSITION_BACK, CAMERA_POSITION_FRONT})
@Retention(RetentionPolicy.SOURCE)
public @interface CameraPosition {
}
public static final int CAMERA_POSITION_UNKNOWN = 0;
public static final int CAMERA_POSITION_FRONT = 1;
public static final int CAMERA_POSITION_BACK = 2;
@IntDef({FLASH_MODE_OFF, FLASH_MODE_ALWAYS_ON, FLASH_MODE_AUTO})
@Retention(RetentionPolicy.SOURCE)
public @interface FlashMode {
}
public static final int FLASH_MODE_OFF = 0;
public static final int FLASH_MODE_ALWAYS_ON = 1;
public static final int FLASH_MODE_AUTO = 2;
public Fragment cameraFragment;
public Fragment previewFragment;
@Override
protected final void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("camera_position", mCameraPosition);
outState.putBoolean("requesting_permission", mRequestingPermission);
outState.putLong("recording_start", mRecordingStart);
outState.putLong("recording_end", mRecordingEnd);
outState.putLong(CameraIntentKey.LENGTH_LIMIT, mLengthLimit);
if (mFrontCameraId instanceof String) {
outState.putString("front_camera_id_str", (String) mFrontCameraId);
outState.putString("back_camera_id_str", (String) mBackCameraId);
} else {
if (mFrontCameraId != null)
outState.putInt("front_camera_id_int", (Integer) mFrontCameraId);
if (mBackCameraId != null)
outState.putInt("back_camera_id_int", (Integer) mBackCameraId);
}
outState.putInt("flash_mode", mFlashMode);
}
@Override
protected final void onCreate(Bundle savedInstanceState) {
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
super.onCreate(savedInstanceState);
if (!CameraUtil.hasCamera(this)) {
new MaterialDialog.Builder(this)
.title("错误")
.content("未检测到可用的相机")
.positiveText(android.R.string.ok)
.dismissListener(new DialogInterface.OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialog) {
finish();
}
}).show();
return;
}
setContentView(R.layout.mcam_activity_videocapture);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
final int primaryColor = getIntent().getIntExtra(CameraIntentKey.PRIMARY_COLOR, 0);
final boolean isPrimaryDark = CameraUtil.isColorDark(primaryColor);
final Window window = getWindow();
window.setStatusBarColor(CameraUtil.darkenColor(primaryColor));
window.setNavigationBarColor(isPrimaryDark ? primaryColor : Color.BLACK);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
final View view = window.getDecorView();
int flags = view.getSystemUiVisibility();
flags |= View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
view.setSystemUiVisibility(flags);
}
}
if (null == savedInstanceState) {
checkPermissions();
mLengthLimit = getIntent().getLongExtra(CameraIntentKey.LENGTH_LIMIT, -1);
} else {
mCameraPosition = savedInstanceState.getInt("camera_position", -1);
mRequestingPermission = savedInstanceState.getBoolean("requesting_permission", false);
mRecordingStart = savedInstanceState.getLong("recording_start", -1);
mRecordingEnd = savedInstanceState.getLong("recording_end", -1);
mLengthLimit = savedInstanceState.getLong(CameraIntentKey.LENGTH_LIMIT, -1);
if (savedInstanceState.containsKey("front_camera_id_str")) {
mFrontCameraId = savedInstanceState.getString("front_camera_id_str");
mBackCameraId = savedInstanceState.getString("back_camera_id_str");
} else {
mFrontCameraId = savedInstanceState.getInt("front_camera_id_int");
mBackCameraId = savedInstanceState.getInt("back_camera_id_int");
}
mFlashMode = savedInstanceState.getInt("flash_mode");
}
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON |
WindowManager.LayoutParams.FLAG_FULLSCREEN);
}
private void checkPermissions() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
showInitialRecorder();
return;
}
final boolean cameraGranted = ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED;
final boolean audioGranted = ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED;
final boolean audioNeeded = !useStillshot() && !audioDisabled();
String[] perms = null;
if (cameraGranted) {
if (audioNeeded && !audioGranted) {
perms = new String[]{Manifest.permission.RECORD_AUDIO};
}
} else {
if (audioNeeded && !audioGranted) {
perms = new String[]{Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO};
} else {
perms = new String[]{Manifest.permission.CAMERA};
}
}
if (perms != null) {
ActivityCompat.requestPermissions(this, perms, PERMISSION_RC);
mRequestingPermission = true;
} else {
showInitialRecorder();
}
}
@Override
protected final void onPause() {
super.onPause();
if (!isFinishing() && !isChangingConfigurations() && !mRequestingPermission)
finish();
}
@Override
public final void onBackPressed() {
final Fragment frag = getFragmentManager().findFragmentById(R.id.container);
if (frag != null) {
if (frag instanceof PreviewFragment && allowRetry()) {
new MaterialDialog.Builder(this)
.title("提示")
.content("确定要返回重新拍摄吗?")
.positiveText("确认")
.negativeText("取消")
.onPositive(new MaterialDialog.SingleButtonCallback() {
@Override
public void onClick(@NonNull MaterialDialog materialDialog, @NonNull DialogAction dialogAction) {
onRetry(((CameraUriInterface) frag).getOutputUri());
}
})
.show();
return;
} else if(frag instanceof BaseCameraFragment) {
new MaterialDialog.Builder(this)
.title("提示")
.content("退出将丢失拍摄内容,确定要放弃此次拍摄吗?")
.positiveText("确认")
.negativeText("取消")
.onPositive(new MaterialDialog.SingleButtonCallback() {
@Override
public void onClick(@NonNull MaterialDialog materialDialog, @NonNull DialogAction dialogAction) {
((BaseCameraFragment) frag).cleanup();
finish();
}
})
.show();
return;
} else if (frag instanceof BaseGalleryFragment && allowRetry()) {
onRetry(((CameraUriInterface) frag).getOutputUri());
return;
}
}
finish();
}
@NonNull
public abstract Fragment getFragment();
public final Fragment createFragment() {
Fragment frag = getFragment();
frag.setArguments(getIntent().getExtras());
return frag;
}
@Override
public void setRecordingStart(long start) {
mRecordingStart = start;
if (start > -1 && hasLengthLimit())
setRecordingEnd(mRecordingStart + getLengthLimit());
else setRecordingEnd(-1);
}
@Override
public long getRecordingStart() {
return mRecordingStart;
}
@Override
public void setRecordingEnd(long end) {
mRecordingEnd = end;
}
@Override
public long getRecordingEnd() {
return mRecordingEnd;
}
@Override
public long getLengthLimit() {
return mLengthLimit;
}
@Override
public boolean hasLengthLimit() {
return getLengthLimit() > -1;
}
@Override
public boolean countdownImmediately() {
return getIntent().getBooleanExtra(CameraIntentKey.COUNTDOWN_IMMEDIATELY, false);
}
@Override
public void setCameraPosition(int position) {
mCameraPosition = position;
}
@Override
public void toggleCameraPosition() {
if (getCurrentCameraPosition() == CAMERA_POSITION_FRONT) {
// Front, go to back if possible
if (getBackCamera() != null)
setCameraPosition(CAMERA_POSITION_BACK);
} else {
// Back, go to front if possible
if (getFrontCamera() != null)
setCameraPosition(CAMERA_POSITION_FRONT);
}
}
@Override
public int getCurrentCameraPosition() {
return mCameraPosition;
}
@Override
public Object getCurrentCameraId() {
if (getCurrentCameraPosition() == CAMERA_POSITION_FRONT)
return getFrontCamera();
else return getBackCamera();
}
@Override
public void setFrontCamera(Object id) {
mFrontCameraId = id;
}
@Override
public Object getFrontCamera() {
return mFrontCameraId;
}
@Override
public void setBackCamera(Object id) {
mBackCameraId = id;
}
@Override
public Object getBackCamera() {
return mBackCameraId;
}
private void showInitialRecorder() {
getFragmentManager().beginTransaction()
.replace(R.id.container, createFragment())
.commit();
}
@Override
public final void onRetry(@Nullable String outputUri) {
if (outputUri != null)
deleteOutputFile(outputUri);
if (!shouldAutoSubmit() || restartTimerOnRetry())
setRecordingStart(-1);
if (getIntent().getBooleanExtra(CameraIntentKey.RETRY_EXITS, false)) {
setResult(RESULT_OK, new Intent()
.putExtra(MaterialCamera.STATUS_EXTRA, MaterialCamera.STATUS_RETRY));
finish();
return;
}
getFragmentManager().beginTransaction()
.replace(R.id.container, createFragment())
.commit();
}
@Override
public final void onShowPreview(Fragment fragment, @Nullable final String outputUri, boolean countdownIsAtZero) {
if ((shouldAutoSubmit() && (countdownIsAtZero || !allowRetry() || !hasLengthLimit())) || outputUri == null) {
if (outputUri == null) {
setResult(RESULT_CANCELED, new Intent().putExtra(MaterialCamera.ERROR_EXTRA,
new TimeLimitReachedException()));
finish();
return;
}
useMedia(outputUri);
} else {
if (!hasLengthLimit() || !continueTimerInPlayback()) {
// No countdown or countdown should not continue through playback, reset timer to 0
setRecordingStart(-1);
}
// Fragment frag = PreviewFragment.newInstance(outputUri, allowRetry(),
// getIntent().getIntExtra(CameraIntentKey.PRIMARY_COLOR, 0));
// getFragmentManager().beginTransaction()
// .replace(R.id.container,frag)
// .commit();
// cameraFragment = fragment;
// previewFragment=frag;
Intent intent = new Intent();
intent.putExtra("videoUrl", outputUri);
setResult(Activity.RESULT_OK, intent);
this.finish();
}
}
@Override
public void onShowStillshot(String outputUri) {
if (shouldAutoSubmit()) {
useMedia(outputUri);
} else {
Fragment frag = PreviewFragment.newInstance(outputUri, allowRetry(),
getIntent().getIntExtra(CameraIntentKey.PRIMARY_COLOR, 0));
getFragmentManager().beginTransaction()
.replace(R.id.container, frag)
.commit();
}
}
@Override
public final boolean allowRetry() {
return getIntent().getBooleanExtra(CameraIntentKey.ALLOW_RETRY, true);
}
@Override
public final boolean shouldAutoSubmit() {
return getIntent().getBooleanExtra(CameraIntentKey.AUTO_SUBMIT, false);
}
private void deleteOutputFile(@Nullable String uri) {
if (uri != null)
new File(Uri.parse(uri).getPath()).delete();
}
@Override
protected final void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == PERMISSION_RC) showInitialRecorder();
}
@Override
public final void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
mRequestingPermission = false;
if (grantResults[0] == PackageManager.PERMISSION_DENIED) {
new MaterialDialog.Builder(this)
.title(R.string.mcam_permissions_needed)
.content(R.string.mcam_video_perm_warning)
.positiveText(android.R.string.ok)
.dismissListener(new DialogInterface.OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialog) {
finish();
}
}).show();
} else {
showInitialRecorder();
}
}
@Override
public final void useMedia(String uri) {
if (uri != null) {
setResult(Activity.RESULT_OK, getIntent()
.putExtra(MaterialCamera.STATUS_EXTRA, MaterialCamera.STATUS_RECORDED)
.setDataAndType(Uri.parse(uri), useStillshot() ? "image/jpeg" : "video/mp4"));
}
finish();
}
@Override
public void setDidRecord(boolean didRecord) {
mDidRecord = didRecord;
}
@Override
public boolean didRecord() {
return mDidRecord;
}
@Override
public int getFlashMode() {
return mFlashMode;
}
@Override
public void toggleFlashMode() {
if (mFlashModes != null) {
mFlashMode = mFlashModes.get((mFlashModes.indexOf(mFlashMode) + 1) % mFlashModes.size());
}
}
@Override
public boolean restartTimerOnRetry() {
return getIntent().getBooleanExtra(CameraIntentKey.RESTART_TIMER_ON_RETRY, false);
}
@Override
public boolean continueTimerInPlayback() {
return getIntent().getBooleanExtra(CameraIntentKey.CONTINUE_TIMER_IN_PLAYBACK, false);
}
@Override
public int videoEncodingBitRate(int defaultVal) {
return getIntent().getIntExtra(CameraIntentKey.VIDEO_BIT_RATE, defaultVal);
}
@Override
public boolean showGuide() {
return getIntent().getBooleanExtra("showGuide",false);
}
@Override
public int audioEncodingBitRate(int defaultVal) {
return getIntent().getIntExtra(CameraIntentKey.AUDIO_ENCODING_BIT_RATE, defaultVal);
}
@Override
public int videoFrameRate(int defaultVal) {
return getIntent().getIntExtra(CameraIntentKey.VIDEO_FRAME_RATE, defaultVal);
}
@Override
public float videoPreferredAspect() {
return getIntent().getFloatExtra(CameraIntentKey.VIDEO_PREFERRED_ASPECT, 4f / 3f);
}
@Override
public int videoPreferredHeight() {
return getIntent().getIntExtra(CameraIntentKey.VIDEO_PREFERRED_HEIGHT, 720);
}
@Override
public long maxAllowedFileSize() {
return getIntent().getLongExtra(CameraIntentKey.MAX_ALLOWED_FILE_SIZE, -1);
}
@Override
public int qualityProfile() {
return getIntent().getIntExtra(CameraIntentKey.QUALITY_PROFILE, CamcorderProfile.QUALITY_HIGH);
}
@DrawableRes
@Override
public int iconPause() {
return getIntent().getIntExtra(CameraIntentKey.ICON_PAUSE, R.drawable.ic_launcher);
}
@DrawableRes
@Override
public int iconPlay() {
return getIntent().getIntExtra(CameraIntentKey.ICON_PLAY, R.drawable.ic_launcher);
}
@DrawableRes
@Override
public int iconRestart() {
return getIntent().getIntExtra(CameraIntentKey.ICON_RESTART, R.drawable.ic_launcher);
}
@DrawableRes
@Override
public int iconRearCamera() {
return getIntent().getIntExtra(CameraIntentKey.ICON_REAR_CAMERA, R.drawable.ic_launcher);
}
@DrawableRes
@Override
public int iconFrontCamera() {
return getIntent().getIntExtra(CameraIntentKey.ICON_FRONT_CAMERA, R.drawable.mcam_camera_front);
}
@DrawableRes
@Override
public int iconStop() {
return getIntent().getIntExtra(CameraIntentKey.ICON_STOP, R.drawable.mcam_action_stop);
}
@DrawableRes
@Override
public int iconRecord() {
return getIntent().getIntExtra(CameraIntentKey.ICON_RECORD, R.drawable.mcam_action_capture);
}
@StringRes
@Override
public int labelRetry() {
return getIntent().getIntExtra(CameraIntentKey.LABEL_RETRY, R.string.mcam_retry);
}
@Deprecated
@StringRes
@Override
public int labelUseVideo() {
return getIntent().getIntExtra(CameraIntentKey.LABEL_CONFIRM, R.string.mcam_use_video);
}
@StringRes
@Override
public int labelConfirm() {
return getIntent().getIntExtra(CameraIntentKey.LABEL_CONFIRM, useStillshot() ? R.string.mcam_use_stillshot : R.string.mcam_use_video);
}
@DrawableRes
@Override
public int iconStillshot() {
return getIntent().getIntExtra(CameraIntentKey.ICON_STILL_SHOT, R.drawable.mcam_action_stillshot);
}
@Override
public boolean useStillshot() {
return getIntent().getBooleanExtra(CameraIntentKey.STILL_SHOT, false);
}
@DrawableRes
@Override
public int iconFlashAuto() {
return getIntent().getIntExtra(CameraIntentKey.ICON_FLASH_AUTO, R.drawable.mcam_action_flash_auto);
}
@DrawableRes
@Override
public int iconFlashOn() {
return getIntent().getIntExtra(CameraIntentKey.ICON_FLASH_ON, R.drawable.mcam_action_flash);
}
@DrawableRes
@Override
public int iconFlashOff() {
return getIntent().getIntExtra(CameraIntentKey.ICON_FLASH_OFF, R.drawable.mcam_action_flash_off);
}
@Override
public void setFlashModes(List<Integer> modes) {
mFlashModes = modes;
}
@Override
public boolean shouldHideFlash() {
return !useStillshot() || mFlashModes == null;
}
@Override
public long autoRecordDelay() {
return getIntent().getLongExtra(CameraIntentKey.AUTO_RECORD, -1);
}
@Override
public boolean audioDisabled() {
return getIntent().getBooleanExtra(CameraIntentKey.AUDIO_DISABLED, false);
}
@Override
public boolean shouldHideCameraFacing() {
return !getIntent().getBooleanExtra(CameraIntentKey.ALLOW_CHANGE_CAMERA, false);
}
}