summaryrefslogtreecommitdiff
path: root/src/com
diff options
context:
space:
mode:
Diffstat (limited to 'src/com')
-rwxr-xr-x[-rw-r--r--]src/com/android/camera/CameraActivity.java62
-rw-r--r--[-rwxr-xr-x]src/com/android/camera/CameraBackupAgent.java0
-rw-r--r--[-rwxr-xr-x]src/com/android/camera/CameraHolder.java5
-rwxr-xr-x[-rw-r--r--]src/com/android/camera/CameraModule.java2
-rwxr-xr-x[-rw-r--r--]src/com/android/camera/CameraSettings.java31
-rwxr-xr-x[-rw-r--r--]src/com/android/camera/CaptureModule.java135
-rw-r--r--[-rwxr-xr-x]src/com/android/camera/CaptureUI.java192
-rwxr-xr-x[-rw-r--r--]src/com/android/camera/ComboPreferences.java3
-rw-r--r--[-rwxr-xr-x]src/com/android/camera/ExtendedFace.java0
-rw-r--r--[-rwxr-xr-x]src/com/android/camera/ListPreference.java0
-rw-r--r--[-rwxr-xr-x]src/com/android/camera/LocationManager.java0
-rw-r--r--[-rwxr-xr-x]src/com/android/camera/MediaSaveService.java20
-rwxr-xr-x[-rw-r--r--]src/com/android/camera/PanoCaptureModule.java9
-rw-r--r--[-rwxr-xr-x]src/com/android/camera/PauseButton.java0
-rw-r--r--[-rwxr-xr-x]src/com/android/camera/PermissionsActivity.java0
-rw-r--r--[-rwxr-xr-x]src/com/android/camera/PhotoController.java0
-rw-r--r--src/com/android/camera/PhotoMenu.java2
-rwxr-xr-x[-rw-r--r--]src/com/android/camera/PhotoModule.java23
-rw-r--r--[-rwxr-xr-x]src/com/android/camera/PhotoUI.java0
-rw-r--r--[-rwxr-xr-x]src/com/android/camera/PreviewGestures.java13
-rwxr-xr-xsrc/com/android/camera/SDCard.java127
-rw-r--r--[-rwxr-xr-x]src/com/android/camera/SceneModeActivity.java0
-rw-r--r--src/com/android/camera/SetActivitiesCameraReceiver.java (renamed from src/com/android/camera/DisableCameraReceiver.java)31
-rwxr-xr-x[-rw-r--r--]src/com/android/camera/SettingsActivity.java13
-rwxr-xr-x[-rw-r--r--]src/com/android/camera/SettingsManager.java26
-rwxr-xr-x[-rw-r--r--]src/com/android/camera/Storage.java129
-rw-r--r--[-rwxr-xr-x]src/com/android/camera/Thumbnail.java0
-rw-r--r--[-rwxr-xr-x]src/com/android/camera/TsMakeupManager.java0
-rwxr-xr-x[-rw-r--r--]src/com/android/camera/VideoMenu.java2
-rwxr-xr-x[-rw-r--r--]src/com/android/camera/VideoModule.java28
-rw-r--r--[-rwxr-xr-x]src/com/android/camera/VideoUI.java0
-rwxr-xr-x[-rw-r--r--]src/com/android/camera/WideAnglePanoramaModule.java12
-rw-r--r--[-rwxr-xr-x]src/com/android/camera/WideAnglePanoramaUI.java0
-rw-r--r--src/com/android/camera/app/CameraApp.java2
-rw-r--r--src/com/android/camera/app/PlaceholderManager.java5
-rw-r--r--[-rwxr-xr-x]src/com/android/camera/data/Camera2ModeAdapter.java21
-rwxr-xr-x[-rw-r--r--]src/com/android/camera/data/CameraDataAdapter.java4
-rw-r--r--[-rwxr-xr-x]src/com/android/camera/deepportrait/CamGLRenderObserver.java0
-rw-r--r--[-rwxr-xr-x]src/com/android/camera/deepportrait/CamGLRenderer.java0
-rw-r--r--[-rwxr-xr-x]src/com/android/camera/deepportrait/CamRenderShader.java0
-rw-r--r--[-rwxr-xr-x]src/com/android/camera/deepportrait/CamRenderTexture.java0
-rw-r--r--[-rwxr-xr-x]src/com/android/camera/deepportrait/DPImage.java0
-rw-r--r--[-rwxr-xr-x]src/com/android/camera/deepportrait/GLCameraPreview.java0
-rw-r--r--[-rwxr-xr-x]src/com/android/camera/imageprocessor/FrameProcessor.java0
-rw-r--r--[-rwxr-xr-x]src/com/android/camera/imageprocessor/PostProcessor.java0
-rw-r--r--[-rwxr-xr-x]src/com/android/camera/imageprocessor/ZSLQueue.java0
-rw-r--r--[-rwxr-xr-x]src/com/android/camera/imageprocessor/filter/DeepPortraitFilter.java0
-rw-r--r--[-rwxr-xr-x]src/com/android/camera/imageprocessor/filter/DeepZoomFilter.java0
-rw-r--r--[-rwxr-xr-x]src/com/android/camera/imageprocessor/filter/UbifocusFilter.java0
-rw-r--r--[-rwxr-xr-x]src/com/android/camera/multi/MultiCamera.java92
-rw-r--r--src/com/android/camera/multi/MultiCameraModule.java1329
-rw-r--r--[-rwxr-xr-x]src/com/android/camera/multi/MultiCameraUI.java1086
-rw-r--r--[-rwxr-xr-x]src/com/android/camera/multi/MultiCaptureModule.java1646
-rw-r--r--[-rwxr-xr-x]src/com/android/camera/multi/MultiSettingsActivity.java0
-rw-r--r--src/com/android/camera/multi/MultiVideoModule.java2670
-rw-r--r--[-rwxr-xr-x]src/com/android/camera/ui/Camera2FaceView.java0
-rw-r--r--[-rwxr-xr-x]src/com/android/camera/ui/CountDownView.java0
-rw-r--r--[-rwxr-xr-x]src/com/android/camera/ui/FaceView.java0
-rw-r--r--[-rwxr-xr-x]src/com/android/camera/ui/FlashToggleButton.java50
-rw-r--r--[-rwxr-xr-x]src/com/android/camera/ui/ModuleSwitcher.java0
-rw-r--r--[-rwxr-xr-x]src/com/android/camera/ui/OneUICameraControls.java192
-rw-r--r--[-rwxr-xr-x]src/com/android/camera/ui/PieRenderer.java0
-rw-r--r--[-rwxr-xr-x]src/com/android/camera/ui/ProMode.java12
-rw-r--r--[-rwxr-xr-x]src/com/android/camera/ui/TouchTrackFocusRenderer.java0
-rw-r--r--[-rwxr-xr-x]src/com/android/camera/ui/ZoomRenderer.java0
-rw-r--r--[-rwxr-xr-x]src/com/android/camera/util/ApiHelper.java0
-rw-r--r--[-rwxr-xr-x]src/com/android/camera/util/AutoTestUtil.java0
-rw-r--r--[-rwxr-xr-x]src/com/android/camera/util/CameraUtil.java0
-rwxr-xr-x[-rw-r--r--]src/com/android/camera/util/PersistUtil.java6
-rw-r--r--[-rwxr-xr-x]src/com/android/camera/util/SettingTranslation.java0
-rw-r--r--[-rwxr-xr-x]src/com/android/camera/util/VendorTagUtil.java0
71 files changed, 4337 insertions, 3643 deletions
diff --git a/src/com/android/camera/CameraActivity.java b/src/com/android/camera/CameraActivity.java
index 6cf522dd9..6cca8da7f 100644..100755
--- a/src/com/android/camera/CameraActivity.java
+++ b/src/com/android/camera/CameraActivity.java
@@ -170,6 +170,8 @@ public class CameraActivity extends Activity
private static final int HIDE_ACTION_BAR = 1;
private static final long SHOW_ACTION_BAR_TIMEOUT_MS = 3000;
+ private static final int SWITCH_SAVE_PATH = 2;
+
/** Permission request code */
private static final int PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION = 1;
@@ -256,8 +258,6 @@ public class CameraActivity extends Activity
private Intent mStandardShareIntent;
private ShareActionProvider mPanoramaShareActionProvider;
private Intent mPanoramaShareIntent;
- private LocalMediaObserver mLocalImagesObserver;
- private LocalMediaObserver mLocalVideosObserver;
private SettingsManager mSettingsManager;
private final int DEFAULT_SYSTEM_UI_VISIBILITY = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
@@ -353,6 +353,24 @@ public class CameraActivity extends Activity
}
};
+ // update the status of storage space when SD card status changed.
+ private BroadcastReceiver mSDcardMountedReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ Log.d(TAG, "SDcard status changed, update storage space");
+ updateStorageSpaceAndHint();
+ }
+ };
+
+ private void registerSDcardMountedReceiver() {
+ // filter for SDcard status
+ IntentFilter filter = new IntentFilter(Intent.ACTION_MEDIA_MOUNTED);
+ filter.addAction(Intent.ACTION_MEDIA_SHARED);
+ filter.addAction(Intent.ACTION_MEDIA_UNMOUNTED);
+ filter.addDataScheme("file");
+ registerReceiver(mSDcardMountedReceiver, filter);
+ }
+
private class MainHandler extends Handler {
public MainHandler(Looper looper) {
super(looper);
@@ -363,6 +381,8 @@ public class CameraActivity extends Activity
if (msg.what == HIDE_ACTION_BAR) {
removeMessages(HIDE_ACTION_BAR);
CameraActivity.this.setSystemBarsVisibility(false);
+ }else if ( msg.what == SWITCH_SAVE_PATH ) {
+ mCurrentModule.onSwitchSavePath();
}
}
}
@@ -1689,16 +1709,6 @@ public class CameraActivity extends Activity
setupNfcBeamPush();
- mLocalImagesObserver = new LocalMediaObserver();
- mLocalVideosObserver = new LocalMediaObserver();
-
- getContentResolver().registerContentObserver(
- MediaStore.Images.Media.EXTERNAL_CONTENT_URI, true,
- mLocalImagesObserver);
- getContentResolver().registerContentObserver(
- MediaStore.Video.Media.EXTERNAL_CONTENT_URI, true,
- mLocalVideosObserver);
-
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
mDeveloperMenuEnabled = prefs.getBoolean(CameraSettings.KEY_DEVELOPER_MENU, false);
@@ -1713,6 +1723,7 @@ public class CameraActivity extends Activity
int offset = lower * 7 / 100;
SETTING_LIST_WIDTH_1 = lower / 2 + offset;
SETTING_LIST_WIDTH_2 = lower / 2 - offset;
+ registerSDcardMountedReceiver();
mAutoTestEnabled = PersistUtil.isAutoTestEnabled();
@@ -1775,8 +1786,6 @@ public class CameraActivity extends Activity
mCurrentModule.onPauseAfterSuper();
mPaused = true;
- mLocalImagesObserver.setActivityPaused(true);
- mLocalVideosObserver.setActivityPaused(true);
}
@Override
@@ -1914,17 +1923,12 @@ public class CameraActivity extends Activity
// than the preview.
mResetToPreviewOnResume = true;
- if (mLocalVideosObserver.isMediaDataChangedDuringPause()
- || mLocalImagesObserver.isMediaDataChangedDuringPause()) {
- if (!mSecureCamera) {
- // If it's secure camera, requestLoad() should not be called
- // as it will load all the data.
- mDataAdapter.requestLoad(getContentResolver());
- mThumbnailDrawable = null;
- }
+ if (!mSecureCamera) {
+ // If it's secure camera, requestLoad() should not be called
+ // as it will load all the data.
+ mDataAdapter.requestLoad(getContentResolver());
+ mThumbnailDrawable = null;
}
- mLocalImagesObserver.setActivityPaused(false);
- mLocalVideosObserver.setActivityPaused(false);
if (PersistUtil.isTraceEnable())
Trace.endSection();
}
@@ -1980,8 +1984,7 @@ public class CameraActivity extends Activity
Log.d(TAG, "wake lock release");
}
if (mCursor != null) {
- getContentResolver().unregisterContentObserver(mLocalImagesObserver);
- getContentResolver().unregisterContentObserver(mLocalVideosObserver);
+ unregisterReceiver(mSDcardMountedReceiver);
mCursor.close();
mCursor=null;
@@ -2047,6 +2050,10 @@ public class CameraActivity extends Activity
protected long updateStorageSpace() {
synchronized (mStorageSpaceLock) {
mStorageSpaceBytes = Storage.getAvailableSpace();
+ if (Storage.switchSavePath()) {
+ mStorageSpaceBytes = Storage.getAvailableSpace();
+ mMainHandler.sendEmptyMessage(SWITCH_SAVE_PATH);
+ }
return mStorageSpaceBytes;
}
}
@@ -2059,6 +2066,9 @@ public class CameraActivity extends Activity
public void updateStorageSpaceAndHint() {
if (mIsStartup) {
+ if (!SDCard.instance().isWriteable()) {
+ Storage.setSaveSDCard(false);
+ }
mIsStartup = false;
}
updateStorageSpace();
diff --git a/src/com/android/camera/CameraBackupAgent.java b/src/com/android/camera/CameraBackupAgent.java
index 348a08d28..348a08d28 100755..100644
--- a/src/com/android/camera/CameraBackupAgent.java
+++ b/src/com/android/camera/CameraBackupAgent.java
diff --git a/src/com/android/camera/CameraHolder.java b/src/com/android/camera/CameraHolder.java
index 4daf84320..1be5fbd6b 100755..100644
--- a/src/com/android/camera/CameraHolder.java
+++ b/src/com/android/camera/CameraHolder.java
@@ -24,6 +24,7 @@ import android.hardware.Camera.CameraInfo;
import android.hardware.Camera.Parameters;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraMetadata;
import android.os.Build;
import android.os.Handler;
import android.os.HandlerThread;
@@ -186,10 +187,10 @@ public class CameraHolder {
= manager.getCameraCharacteristics(cameraId);
Log.d(TAG,"cameraIdList size ="+cameraIdList.length);
int facing = characteristics.get(CameraCharacteristics.LENS_FACING);
- if (facing == CameraCharacteristics.LENS_FACING_FRONT) {
+ if (mFrontCameraId == -1 && facing == CameraMetadata.LENS_FACING_FRONT) {
CaptureModule.FRONT_ID = i;
mFrontCameraId = i;
- } else if (mBackCameraId != -1) {
+ } else if (mBackCameraId == -1 && facing == CameraMetadata.LENS_FACING_BACK) {
mBackCameraId = i;
}
addCameraInfo(i, characteristics);
diff --git a/src/com/android/camera/CameraModule.java b/src/com/android/camera/CameraModule.java
index aed1e57db..14fe0ea4c 100644..100755
--- a/src/com/android/camera/CameraModule.java
+++ b/src/com/android/camera/CameraModule.java
@@ -73,6 +73,8 @@ public interface CameraModule {
public void resizeForPreviewAspectRatio();
+ public void onSwitchSavePath();
+
public void waitingLocationPermissionResult(boolean waiting);
public void enableRecordingLocation(boolean enable);
diff --git a/src/com/android/camera/CameraSettings.java b/src/com/android/camera/CameraSettings.java
index c1f02ff3a..ad0c30ac6 100644..100755
--- a/src/com/android/camera/CameraSettings.java
+++ b/src/com/android/camera/CameraSettings.java
@@ -92,6 +92,7 @@ public class CameraSettings {
public static final String KEY_POWER_MODE = "pref_camera_powermode_key";
public static final String KEY_PICTURE_FORMAT = "pref_camera_pictureformat_key";
public static final String KEY_ZSL = "pref_camera_zsl_key";
+ public static final String KEY_CAMERA_SAVEPATH = "pref_camera_savepath_key";
public static final String KEY_FILTER_MODE = "pref_camera_filter_mode_key";
public static final String KEY_COLOR_EFFECT = "pref_camera_coloreffect_key";
public static final String KEY_VIDEOCAMERA_COLOR_EFFECT = "pref_camera_video_coloreffect_key";
@@ -1134,6 +1135,7 @@ public class CameraSettings {
ListPreference seeMoreMode = group.findPreference(KEY_SEE_MORE);
ListPreference videoEncoder = group.findPreference(KEY_VIDEO_ENCODER);
ListPreference noiseReductionMode = group.findPreference(KEY_NOISE_REDUCTION);
+ ListPreference savePath = group.findPreference(KEY_CAMERA_SAVEPATH);
// Since the screen could be loaded from different resources, we need
// to check if the preference is available here
@@ -1257,6 +1259,35 @@ public class CameraSettings {
removePreference(group, powerShutter.getKey());
}
+ if (PersistUtil.isSaveInSdEnabled()) {
+ final String CAMERA_SAVEPATH_SDCARD = "1";
+ final int CAMERA_SAVEPATH_SDCARD_IDX = 1;
+ final int CAMERA_SAVEPATH_PHONE_IDX = 0;
+
+ SharedPreferences pref = group.getSharedPreferences();
+ String savePathValue = null;
+ if (pref != null) {
+ savePathValue = pref.getString(KEY_CAMERA_SAVEPATH, CAMERA_SAVEPATH_SDCARD);
+ }
+ if (savePath != null && CAMERA_SAVEPATH_SDCARD.equals(savePathValue)) {
+ // If sdCard is present, set sdCard as default save path.
+ // Only for the first time when camera start.
+ if (SDCard.instance().isWriteable()) {
+ Log.d(TAG, "set Sdcard as save path.");
+ savePath.setValueIndex(CAMERA_SAVEPATH_SDCARD_IDX);
+ } else {
+ Log.d(TAG, "set Phone as save path when sdCard is unavailable.");
+ savePath.setValueIndex(CAMERA_SAVEPATH_PHONE_IDX);
+ }
+ }
+ }
+ if (savePath != null) {
+ Log.d(TAG, "check storage menu " + SDCard.instance().isWriteable());
+ if (!SDCard.instance().isWriteable()) {
+ removePreference(group, savePath.getKey());
+ }
+ }
+
qcomInitPreferences(group);
}
diff --git a/src/com/android/camera/CaptureModule.java b/src/com/android/camera/CaptureModule.java
index 7f546fdf7..b7773c873 100644..100755
--- a/src/com/android/camera/CaptureModule.java
+++ b/src/com/android/camera/CaptureModule.java
@@ -30,6 +30,7 @@ import android.content.SharedPreferences;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.Configuration;
+import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.ImageFormat;
import android.graphics.Matrix;
@@ -133,6 +134,8 @@ import com.android.camera.util.VendorTagUtil;
import org.codeaurora.snapcam.R;
import org.codeaurora.snapcam.filter.ClearSightImageProcessor;
+import org.lineageos.quickreader.ScannerActivity;
+
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
@@ -557,7 +560,7 @@ public class CaptureModule implements CameraModule, PhotoController,
private boolean[] mCameraOpened = new boolean[MAX_NUM_CAM];
private CameraDevice[] mCameraDevice = new CameraDevice[MAX_NUM_CAM];
private String[] mCameraId = new String[MAX_NUM_CAM];
- private String[] mSelectableModes = {"Video", "HFR", "Photo", "Bokeh", "SAT", "ProMode"};
+ private String[] mSelectableModes = {"Video", "HFR", "Photo", "Bokeh", "SAT", "ProMode", "QR"};
private ArrayList<SceneModule> mSceneCameraIds = new ArrayList<>();
private SceneModule mCurrentSceneMode;
private int mNextModeIndex = 1;
@@ -570,7 +573,8 @@ public class CaptureModule implements CameraModule, PhotoController,
DEFAULT,
RTB,
SAT,
- PRO_MODE
+ PRO_MODE,
+ QR,
}
public enum MFNRSupportValues {
@@ -604,6 +608,7 @@ public class CaptureModule implements CameraModule, PhotoController,
private boolean mExistAECWarmTag = true;
private boolean mExistAECFrameControlTag = true;
+ private static final long SDCARD_SIZE_LIMIT = 4000 * 1024 * 1024L;
private static final String sTempCropFilename = "crop-temp";
private static final int REQUEST_CROP = 1000;
private int mIntentMode = INTENT_MODE_NORMAL;
@@ -954,22 +959,28 @@ public class CaptureModule implements CameraModule, PhotoController,
mPreviewCaptureResult = result;
}
updateCaptureStateMachine(id, result);
- Integer ssmStatus = result.get(ssmCaptureComplete);
- if (ssmStatus != null) {
- Log.d(TAG, "ssmStatus: CaptureComplete is " + ssmStatus);
- updateProgressBar(true);
- }
- Integer procComplete = result.get(ssmProcessingComplete);
- if (procComplete != null && ++mCaptureCompleteCount == 1) {
- Log.d(TAG, "ssmStatus: ProcessingComplete is " + procComplete);
- mCaptureCompleteCount = 0;
- mSSMCaptureCompleteFlag = true;
- mActivity.runOnUiThread(new Runnable() {
- @Override
- public void run() {
- stopRecordingVideo(getMainCameraId());
+ if (isSSMEnabled()) {
+ try {
+ Integer ssmStatus = result.get(ssmCaptureComplete);
+ if (ssmStatus != null) {
+ Log.d(TAG, "ssmStatus: CaptureComplete is " + ssmStatus);
+ updateProgressBar(true);
}
- });
+ Integer procComplete = result.get(ssmProcessingComplete);
+ if (procComplete != null && ++mCaptureCompleteCount == 1) {
+ Log.d(TAG, "ssmStatus: ProcessingComplete is " + procComplete);
+ mCaptureCompleteCount = 0;
+ mSSMCaptureCompleteFlag = true;
+ mActivity.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ stopRecordingVideo(getMainCameraId());
+ }
+ });
+ }
+ } catch (IllegalArgumentException e) {
+ e.printStackTrace();
+ }
}
}
@@ -1818,6 +1829,10 @@ public class CaptureModule implements CameraModule, PhotoController,
if (!HFR_RATE.equals("")) {
mSettingsManager.setValue(SettingsManager.KEY_VIDEO_HIGH_FRAME_RATE, HFR_RATE);
}
+ if (!mSettingsManager.isHFRSupportedOnCurrentResolution()) {
+ Toast.makeText(mActivity, R.string.hfr_unsupported_current_resolution,
+ Toast.LENGTH_LONG).show();
+ }
createSessionForVideo(cameraId);
break;
default:
@@ -2334,11 +2349,20 @@ public class CaptureModule implements CameraModule, PhotoController,
mSettingsManager = SettingsManager.getInstance();
mSettingsManager.createCaptureModule(this);
mSettingsManager.registerListener(this);
- if (isBackCameraId()) {
- CURRENT_ID = BACK_MODE;
- } else {
- CURRENT_ID = FRONT_MODE;
+
+ SceneModule module;
+ for (int i = 0; i < mSelectableModes.length; i++) {
+ module = new SceneModule();
+ module.mode = CameraMode.values()[i];
+ mSceneCameraIds.add(module);
+ if (module.mode == CURRENT_MODE) {
+ mNextModeIndex = i;
+ mCurrentModeIndex = i;
+ }
}
+ mCurrentSceneMode = mSceneCameraIds.get(mCurrentModeIndex);
+ CURRENT_ID = mCurrentSceneMode.getNextCameraId(CURRENT_MODE);
+
mSettingsManager.init();
mFirstPreviewLoaded = false;
Log.d(TAG, "init");
@@ -2349,12 +2373,6 @@ public class CaptureModule implements CameraModule, PhotoController,
for (int i = 0; i < MAX_NUM_CAM; i++) {
mState[i] = STATE_PREVIEW;
}
- SceneModule module;
- for (int i = 0; i < mSelectableModes.length; i++) {
- module = new SceneModule();
- module.mode = CameraMode.values()[i];
- mSceneCameraIds.add(module);
- }
mPostProcessor = new PostProcessor(mActivity, this);
mFrameProcessor = new FrameProcessor(mActivity, this);
@@ -2430,6 +2448,7 @@ public class CaptureModule implements CameraModule, PhotoController,
removeList[CameraMode.DEFAULT.ordinal()] = false;
removeList[CameraMode.VIDEO.ordinal()] = false;
removeList[CameraMode.PRO_MODE.ordinal()] = false;
+ removeList[CameraMode.QR.ordinal()] = false;
if (facing == CameraCharacteristics.LENS_FACING_FRONT) {
CaptureModule.FRONT_ID = cameraId;
mSceneCameraIds.get(CameraMode.DEFAULT.ordinal()).frontCameraId = cameraId;
@@ -2445,6 +2464,7 @@ public class CaptureModule implements CameraModule, PhotoController,
mSceneCameraIds.get(CameraMode.DEFAULT.ordinal()).rearCameraId = cameraId;
mSceneCameraIds.get(CameraMode.VIDEO.ordinal()).rearCameraId = cameraId;
mSceneCameraIds.get(CameraMode.PRO_MODE.ordinal()).rearCameraId = cameraId;
+ mSceneCameraIds.get(CameraMode.QR.ordinal()).rearCameraId = cameraId;
if (mSettingsManager.isHFRSupported()) { // filter HFR mode
removeList[CameraMode.HFR.ordinal()] = false;
mSceneCameraIds.get(CameraMode.HFR.ordinal()).rearCameraId = cameraId;
@@ -4566,6 +4586,7 @@ public class CaptureModule implements CameraModule, PhotoController,
mSoundPlayer = SoundClips.getPlayer(mActivity);
}
+ updateSaveStorageState();
setDisplayOrientation();
if (!resumeFromRestartAll) {
startBackgroundThread();
@@ -4933,6 +4954,9 @@ public class CaptureModule implements CameraModule, PhotoController,
return;
}
Log.d(TAG, "onSingleTapUp " + x + " " + y);
+
+ mUI.closeModeSwitcher(true);
+
int currentId = mCurrentSceneMode.getCurrentId();
if(mLockAFAE) {
mLockAFAE = false;
@@ -5288,6 +5312,13 @@ public class CaptureModule implements CameraModule, PhotoController,
}
@Override
+ public void onSwitchSavePath() {
+ mSettingsManager.setValue(SettingsManager.KEY_CAMERA_SAVEPATH, "1");
+ RotateTextToast.makeText(mActivity, R.string.on_switch_save_path_to_sdcard,
+ Toast.LENGTH_SHORT).show();
+ }
+
+ @Override
public void onShutterButtonFocus(boolean pressed) {
if (!pressed && mLongshotActive) {
Log.d(TAG, "Longshot button up");
@@ -6486,7 +6517,12 @@ public class CaptureModule implements CameraModule, PhotoController,
String title = createName(dateTaken);
String filename = title + CameraUtil.convertOutputFormatToFileExt(outputFileFormat);
String mime = CameraUtil.convertOutputFormatToMimeType(outputFileFormat);
- String path = Storage.DIRECTORY + '/' + filename;
+ String path;
+ if (Storage.isSaveSDCard() && SDCard.instance().isWriteable()) {
+ path = SDCard.instance().getDirectory() + '/' + filename;
+ } else {
+ path = Storage.DIRECTORY + '/' + filename;
+ }
mCurrentVideoValues = new ContentValues(9);
mCurrentVideoValues.put(MediaStore.Video.Media.TITLE, title);
mCurrentVideoValues.put(MediaStore.Video.Media.DISPLAY_NAME, filename);
@@ -6691,6 +6727,9 @@ public class CaptureModule implements CameraModule, PhotoController,
maxFileSize = requestedSizeLimit;
}
+ if (Storage.isSaveSDCard() && maxFileSize > SDCARD_SIZE_LIMIT) {
+ maxFileSize = SDCARD_SIZE_LIMIT;
+ }
Log.i(TAG, "MediaRecorder setMaxFileSize: " + maxFileSize);
try {
mMediaRecorder.setMaxFileSize(maxFileSize);
@@ -6788,6 +6827,8 @@ public class CaptureModule implements CameraModule, PhotoController,
Log.d(TAG,"onShutterButtonClick");
+ mUI.closeModeSwitcher(true);
+
if (mCurrentSceneMode.mode == CameraMode.HFR ||
mCurrentSceneMode.mode == CameraMode.VIDEO) {
if (mSettingsManager.isLiveshotSupported(mVideoSize,mSettingsManager.getVideoFPS())){
@@ -8178,6 +8219,10 @@ public class CaptureModule implements CameraModule, PhotoController,
}
Log.d(TAG, "CaptureModule onSettingsChanged, key = " + key);
switch (key) {
+ case SettingsManager.KEY_CAMERA_SAVEPATH:
+ Storage.setSaveSDCard(value.equals("1"));
+ mActivity.updateStorageSpaceAndHint();
+ continue;
case SettingsManager.KEY_JPEG_QUALITY:
estimateJpegFileSize();
continue;
@@ -8644,7 +8689,7 @@ public class CaptureModule implements CameraModule, PhotoController,
}
mUI.showUIafterRecording();
if (what == MediaRecorder.MEDIA_RECORDER_ERROR_UNKNOWN) {
- // We may have run out of storage space.
+ // We may have run out of space on the sdcard.
mActivity.updateStorageSpaceAndHint();
} else {
warningToast("MediaRecorder error. what=" + what + ". extra=" + extra);
@@ -8675,6 +8720,11 @@ public class CaptureModule implements CameraModule, PhotoController,
return bytes;
}
+ private void updateSaveStorageState() {
+ Storage.setSaveSDCard(mSettingsManager.getValue(SettingsManager
+ .KEY_CAMERA_SAVEPATH).equals("1"));
+ }
+
public void startPlayVideoActivity() {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(mCurrentVideoUri,
@@ -8943,6 +8993,13 @@ public class CaptureModule implements CameraModule, PhotoController,
if (mCurrentSceneMode.mode == mSceneCameraIds.get(mode).mode) {
return -1;
}
+ if (mSceneCameraIds.get(mode).mode == CameraMode.QR) {
+ mUI.closeModeSwitcher(true);
+ Intent intent = new Intent(mActivity, ScannerActivity.class);
+ mActivity.startActivity(intent);
+ // Don't change the selected item in modeswitcher
+ return -1;
+ }
setCameraModeSwitcherAllowed(false);
setNextSceneMode(mode);
SceneModule nextSceneMode = mSceneCameraIds.get(mode);
@@ -8952,12 +9009,16 @@ public class CaptureModule implements CameraModule, PhotoController,
nextSceneMode.mode == CameraMode.SAT ||
nextSceneMode.mode == CameraMode.PRO_MODE)) {
mSettingsManager.setValue(SettingsManager.KEY_FRONT_REAR_SWITCHER_VALUE, "rear");
+ mUI.setFrontBackSwitcherDrawable();
} else {
restartAll();
}
updateZoomSeekBarVisible();
mUI.updateZoomSeekBar(1.0f);
updateZoom();
+ mUI.closeModeSwitcher(true);
+ mUI.setCurrentModeIcon(mode);
+ mUI.setSwitcherAnimationNeeded(true);
return 1;
}
@@ -8995,6 +9056,16 @@ public class CaptureModule implements CameraModule, PhotoController,
return mSelectableModes;
}
+ public List<Integer> getCameraModeIconList() {
+ ArrayList<Integer> cameraModeIcons = new ArrayList<>();
+ TypedArray ic = mActivity.getResources()
+ .obtainTypedArray(R.array.camera_modes_back);
+ for (SceneModule sceneModule : mSceneCameraIds) {
+ cameraModeIcons.add(ic.getResourceId(sceneModule.mode.ordinal(), 0));
+ }
+ return cameraModeIcons;
+ }
+
private class SceneModule {
CameraMode mode = CameraMode.DEFAULT;
public int rearCameraId;
@@ -9005,7 +9076,8 @@ public class CaptureModule implements CameraModule, PhotoController,
int cameraId = isBackCamera() ? rearCameraId : frontCameraId;
cameraId = isForceAUXOn(this.mode) ? auxCameraId : cameraId;
if ((this.mode == CameraMode.DEFAULT || this.mode == CameraMode.VIDEO ||
- this.mode == CameraMode.HFR || this.mode == CameraMode.PRO_MODE)
+ this.mode == CameraMode.HFR || this.mode == CameraMode.PRO_MODE ||
+ this.mode == CameraMode.QR)
&& (mSettingsManager.isDeveloperEnabled() || swithCameraId != -1)) {
String value = mSettingsManager.getValue(SettingsManager.KEY_SWITCH_CAMERA);
if (value != null && !value.equals("-1")) {
@@ -9022,7 +9094,8 @@ public class CaptureModule implements CameraModule, PhotoController,
int cameraId = isBackCamera() ? rearCameraId : frontCameraId;
cameraId = isForceAUXOn(this.mode) ? auxCameraId : cameraId;
if ((this.mode == CameraMode.DEFAULT || this.mode == CameraMode.VIDEO ||
- this.mode == CameraMode.HFR || this.mode == CameraMode.PRO_MODE)
+ this.mode == CameraMode.HFR || this.mode == CameraMode.PRO_MODE ||
+ this.mode == CameraMode.QR)
&& (mSettingsManager.isDeveloperEnabled() || swithCameraId != -1)) {
final SharedPreferences pref = mActivity.getSharedPreferences(
ComboPreferences.getLocalSharedPreferencesName(mActivity,
diff --git a/src/com/android/camera/CaptureUI.java b/src/com/android/camera/CaptureUI.java
index 7874f963f..398b0ab0b 100755..100644
--- a/src/com/android/camera/CaptureUI.java
+++ b/src/com/android/camera/CaptureUI.java
@@ -20,6 +20,8 @@
package com.android.camera;
import android.animation.Animator;
+import android.animation.Animator.AnimatorListener;
+import android.animation.AnimatorListenerAdapter;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
@@ -46,6 +48,7 @@ import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.Size;
+import android.util.TypedValue;
import android.view.Display;
import android.view.Gravity;
import android.view.LayoutInflater;
@@ -209,6 +212,7 @@ public class CaptureUI implements PreviewGestures.SingleTapListener,
private View mFilterModeSwitcher;
private View mSceneModeSwitcher;
private View mFrontBackSwitcher;
+ private View mModeSwitcher;
private ImageView mMakeupButton;
private SeekBar mMakeupSeekBar;
private SeekBar mDeepportraitSeekBar;
@@ -260,6 +264,12 @@ public class CaptureUI implements PreviewGestures.SingleTapListener,
private TextView mStatsAecSensitivityText;
private TextView mStatsAecExposureTimeText;
+ private TextView mExposureText;
+ private TextView mManualText;
+ private TextView mWhiteBalanceText;
+ private TextView mIsoText;
+ private TextView mZoomSeekbarText;
+
private LinearLayout mZoomLinearLayout;
private TextView mZoomSwitch;
@@ -270,6 +280,9 @@ public class CaptureUI implements PreviewGestures.SingleTapListener,
private boolean mIsVideoUI = false;
private boolean mIsSceneModeLabelClose = false;
+ private boolean mNeedsAnimationSetup = true;
+ private boolean mIsAnimating = false;
+
private void previewUIReady() {
if((mSurfaceHolder != null && mSurfaceHolder.getSurface().isValid())) {
mModule.onPreviewUIReady();
@@ -384,6 +397,7 @@ public class CaptureUI implements PreviewGestures.SingleTapListener,
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
+ closeModeSwitcher(true);
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
@@ -425,17 +439,25 @@ public class CaptureUI implements PreviewGestures.SingleTapListener,
initZoomSeekBar();
mFlashButton = (FlashToggleButton) mRootView.findViewById(R.id.flash_button);
+ mFlashButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ closeModeSwitcher(true);
+ mFlashButton.handleClick();
+ }
+ });
mModeSelectLayout = (RecyclerView) mRootView.findViewById(R.id.mode_select_layout);
mModeSelectLayout.setLayoutManager(new LinearLayoutManager(mActivity,
- LinearLayoutManager.HORIZONTAL, false));
- mCameraModeAdapter = new Camera2ModeAdapter(mModule.getCameraModeList());
+ LinearLayoutManager.VERTICAL, false));
+ mModeSelectLayout.setVisibility(View.INVISIBLE);
+ mCameraModeAdapter = new Camera2ModeAdapter(mModule.getCameraModeList(), mModule.getCameraModeIconList());
mCameraModeAdapter.setOnItemClickListener(mModule.getModeItemClickListener());
mModeSelectLayout.setAdapter(mCameraModeAdapter);
mSettingsIcon = (ImageView) mRootView.findViewById(R.id.settings);
- mSettingsIcon.setImageResource(R.drawable.settings);
mSettingsIcon.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
+ closeModeSwitcher(false);
openSettingsMenu();
}
});
@@ -509,6 +531,7 @@ public class CaptureUI implements PreviewGestures.SingleTapListener,
});
mCameraControls = (OneUICameraControls) mRootView.findViewById(R.id.camera_controls);
+ mCameraControls.initialize(this);
mFaceView = (Camera2FaceView) mRootView.findViewById(R.id.face_view);
mFaceView.initMode();
@@ -526,6 +549,7 @@ public class CaptureUI implements PreviewGestures.SingleTapListener,
mZoomSwitch.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
+ closeModeSwitcher(true);
String[] entries = mActivity.getResources().getStringArray(
R.array.pref_camera2_zomm_switch_entries);
String[] values = mActivity.getResources().getStringArray(
@@ -544,7 +568,6 @@ public class CaptureUI implements PreviewGestures.SingleTapListener,
mCancelButton = (ImageView) mRootView.findViewById(R.id.cancel_button);
final int intentMode = mModule.getCurrentIntentMode();
if (intentMode != CaptureModule.INTENT_MODE_NORMAL) {
- mModeSelectLayout.setVisibility(View.GONE);
mCameraControls.setIntentMode(intentMode);
mCameraControls.setVideoMode(false);
mCancelButton.setVisibility(View.VISIBLE);
@@ -603,6 +626,55 @@ public class CaptureUI implements PreviewGestures.SingleTapListener,
});
}
+ mModeSwitcher = mRootView.findViewById(R.id.mode_switcher);
+ mModeSwitcher.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ showModeSwitcher(true);
+ }
+ });
+
+ mExposureText = mRootView.findViewById(R.id.exposure_value);
+ mExposureText.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ closeModeSwitcher(true);
+ mCameraControls.onExposureTextClick();
+ }
+ });
+ mManualText = mRootView.findViewById(R.id.manual_value);
+ mManualText.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ closeModeSwitcher(true);
+ mCameraControls.onManualTextClick();
+ }
+ });
+ mWhiteBalanceText = mRootView.findViewById(R.id.white_balance_value);
+ mWhiteBalanceText.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ closeModeSwitcher(true);
+ mCameraControls.onWhiteBalanceTextClick();
+ }
+ });
+ mIsoText = mRootView.findViewById(R.id.iso_value);
+ mIsoText.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ closeModeSwitcher(true);
+ mCameraControls.onIsoTextClick();
+ }
+ });
+ mZoomSeekbarText = mRootView.findViewById(R.id.zoom_seekbar_value);
+ mZoomSeekbarText.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ closeModeSwitcher(true);
+ mCameraControls.onZoomSeekbarTextClick();
+ }
+ });
+
mActivity.getWindowManager().getDefaultDisplay().getSize(mDisplaySize);
mScreenRatio = CameraUtil.determineRatio(mDisplaySize.x, mDisplaySize.y);
if (mScreenRatio == CameraUtil.RATIO_16_9) {
@@ -674,6 +746,7 @@ public class CaptureUI implements PreviewGestures.SingleTapListener,
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
+ closeModeSwitcher(false);
}
@Override
@@ -962,6 +1035,7 @@ public class CaptureUI implements PreviewGestures.SingleTapListener,
mVideoButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
+ closeModeSwitcher(true);
cancelCountDown();
mModule.onVideoButtonClick();
}
@@ -991,6 +1065,79 @@ public class CaptureUI implements PreviewGestures.SingleTapListener,
return mFilterMenuStatus == FILTER_MENU_ON;
}
+ public void setCurrentModeIcon(int mode) {
+ ((ImageView) mModeSwitcher).setImageResource(
+ mModule.getCameraModeIconList().get(mode));
+ }
+
+ private void modeSwitcherAnimSetup() {
+ mModeSelectLayout.setAlpha(0f);
+ mModeSelectLayout.setScaleX(0.3f);
+ mModeSelectLayout.setScaleY(0.3f);
+ mModeSelectLayout.setTranslationY(mModeSwitcher.getY()
+ - mModeSelectLayout.getMeasuredHeight() / 2);
+ mNeedsAnimationSetup = false;
+ }
+
+ public void setSwitcherAnimationNeeded(boolean needed) {
+ mNeedsAnimationSetup = needed;
+ }
+
+ public void showModeSwitcher(boolean animation) {
+ if (mModeSelectLayout == null ||
+ mModeSelectLayout.getVisibility() == View.VISIBLE) {
+ return;
+ }
+
+ if (isPreviewMenuBeingShown()) {
+ removeFilterMenu(true);
+ }
+
+ if (animation) {
+ if (mNeedsAnimationSetup) {
+ modeSwitcherAnimSetup();
+ }
+
+ mModeSelectLayout.setVisibility(View.VISIBLE);
+ mModeSelectLayout.animate()
+ .alpha(1f)
+ .scaleX(1f).scaleY(1f)
+ .translationY(mModeSwitcher.getY()
+ - mModeSelectLayout.getMeasuredHeight()
+ + mModeSwitcher.getMeasuredHeight())
+ .setDuration(ANIMATION_DURATION)
+ .setListener(null);
+ } else {
+ mModeSelectLayout.setVisibility(View.VISIBLE);
+ }
+ }
+
+ public void closeModeSwitcher(boolean animation) {
+ if (mModeSelectLayout == null ||
+ mModeSelectLayout.getVisibility() != View.VISIBLE) {
+ return;
+ }
+
+ if (animation && !mIsAnimating) {
+ mIsAnimating = true;
+ mModeSelectLayout.animate()
+ .alpha(0f)
+ .scaleX(0.3f).scaleY(0.3f)
+ .translationY(mModeSwitcher.getY()
+ - mModeSelectLayout.getMeasuredHeight() / 2)
+ .setDuration(ANIMATION_DURATION)
+ .setListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mModeSelectLayout.setVisibility(View.INVISIBLE);
+ mIsAnimating = false;
+ }
+ });
+ } else {
+ mModeSelectLayout.setVisibility(View.INVISIBLE);
+ }
+ }
+
public void removeFilterMenu(boolean animate) {
if (animate) {
animateSlideOut(mFilterLayout);
@@ -1000,9 +1147,6 @@ public class CaptureUI implements PreviewGestures.SingleTapListener,
((ViewGroup) mRootView).removeView(mFilterLayout);
mFilterLayout = null;
}
- if (mModule.getCurrentIntentMode() == CaptureModule.INTENT_MODE_NORMAL) {
- mModeSelectLayout.setVisibility(View.VISIBLE);
- }
mModule.updateZoomSeekBarVisible();
}
updateMenus();
@@ -1012,6 +1156,7 @@ public class CaptureUI implements PreviewGestures.SingleTapListener,
if (mPreviewLayout != null && mPreviewLayout.getVisibility() == View.VISIBLE) {
return;
}
+ closeModeSwitcher(true);
removeFilterMenu(false);
Intent intent = new Intent(mActivity, SettingsActivity.class);
intent.putExtra(SettingsActivity.CAMERA_MODULE, mModule.getCurrenCameraMode());
@@ -1025,10 +1170,12 @@ public class CaptureUI implements PreviewGestures.SingleTapListener,
if (value == null)
return;
+ setFrontBackSwitcherDrawable();
mFrontBackSwitcher.setVisibility(View.VISIBLE);
mFrontBackSwitcher.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
+ closeModeSwitcher(false);
mModule.writeXMLForWarmAwb();
switchFrontBackCamera();
}
@@ -1055,6 +1202,16 @@ public class CaptureUI implements PreviewGestures.SingleTapListener,
switchToPhotoModeDueToError(false);
}
mSettingsManager.setValueIndex(SettingsManager.KEY_FRONT_REAR_SWITCHER_VALUE, index);
+ setFrontBackSwitcherDrawable();
+ }
+
+ public void setFrontBackSwitcherDrawable() {
+ if (mSettingsManager.getValue(SettingsManager.KEY_FRONT_REAR_SWITCHER_VALUE)
+ .equals("front")) {
+ ((ImageView) mFrontBackSwitcher).setImageResource(R.drawable.ic_switch_back);
+ } else {
+ ((ImageView) mFrontBackSwitcher).setImageResource(R.drawable.ic_switch_front);
+ }
}
private boolean isSupportFrontCamera(CaptureModule.CameraMode mode) {
@@ -1076,6 +1233,7 @@ public class CaptureUI implements PreviewGestures.SingleTapListener,
mSceneModeSwitcher.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
+ closeModeSwitcher(false);
removeFilterMenu(false);
Intent intent = new Intent(mActivity, SceneModeActivity.class);
intent.putExtra(CameraUtil.KEY_IS_SECURE_CAMERA, mActivity.isSecureCamera());
@@ -1096,10 +1254,10 @@ public class CaptureUI implements PreviewGestures.SingleTapListener,
mFilterModeSwitcher.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
+ closeModeSwitcher(false);
addFilterMode();
adjustOrientation();
updateMenus();
- mModeSelectLayout.setVisibility(View.GONE);
hideZoomSeekBar();
}
});
@@ -1131,7 +1289,7 @@ public class CaptureUI implements PreviewGestures.SingleTapListener,
} else {
mFlashButton.init(true);
}
- mVideoButton.setImageResource(R.drawable.video_stop);
+ mVideoButton.setImageResource(R.drawable.shutter_button_video_stop);
mRecordingTimeView.setText("00:00");
mRecordingTimeRect.setVisibility(View.VISIBLE);
mMuteButton.setVisibility((mModule.isHSRMode() || mModule.getCurrenCameraMode() == CaptureModule.CameraMode.VIDEO) ? View.VISIBLE : View.INVISIBLE);
@@ -1294,13 +1452,13 @@ public class CaptureUI implements PreviewGestures.SingleTapListener,
public void hideUIwhileRecording() {
mCameraControls.setVideoMode(true);
- mModeSelectLayout.setVisibility(View.INVISIBLE);
mSceneModeLabelRect.setVisibility(View.INVISIBLE);
mDeepZoomModeRect.setVisibility(View.INVISIBLE);
mFrontBackSwitcher.setVisibility(View.INVISIBLE);
mFilterModeSwitcher.setVisibility(View.INVISIBLE);
mSceneModeSwitcher.setVisibility(View.INVISIBLE);
mSettingsIcon.setVisibility(View.INVISIBLE);
+ closeModeSwitcher(true);
String value = mSettingsManager.getValue(SettingsManager.KEY_MAKEUP);
if(value != null && value.equals("0")) {
mMakeupButton.setVisibility(View.GONE);
@@ -1322,7 +1480,6 @@ public class CaptureUI implements PreviewGestures.SingleTapListener,
mPauseButton.setVisibility(View.INVISIBLE);
if (mModule.getCurrentIntentMode() == CaptureModule.INTENT_MODE_NORMAL) {
mShutterButton.setVisibility(View.INVISIBLE);
- mModeSelectLayout.setVisibility(View.VISIBLE);
}
mFilterModeSwitcher.setVisibility(View.VISIBLE);
if (mFilterMenuStatus == FILTER_MENU_ON) {
@@ -1605,6 +1762,7 @@ public class CaptureUI implements PreviewGestures.SingleTapListener,
if (mSceneModeSwitcher != null) mSceneModeSwitcher.setEnabled(status);
if (mFilterModeSwitcher != null) mFilterModeSwitcher.setEnabled(status);
if (mMakeupButton != null) mMakeupButton.setVisibility(View.GONE);
+ closeModeSwitcher(true);
}
public void initializeControlByIntent() {
@@ -1612,6 +1770,7 @@ public class CaptureUI implements PreviewGestures.SingleTapListener,
mThumbnail.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
+ closeModeSwitcher(true);
if (!CameraControls.isAnimating() && !mModule.isTakingPicture() &&
!mModule.isRecordingVideo())
mActivity.gotoGallery();
@@ -1700,6 +1859,8 @@ public class CaptureUI implements PreviewGestures.SingleTapListener,
}
mFilterModeSwitcher.setEnabled(enableFilterMenu);
mSceneModeSwitcher.setEnabled(enableSceneMenu);
+ mNeedsAnimationSetup = true;
+ mModeSelectLayout.bringToFront();
}
public void toggleProgressBar(boolean show) {
@@ -1740,6 +1901,10 @@ public class CaptureUI implements PreviewGestures.SingleTapListener,
removeFilterMenu(true);
return true;
}
+ if (mModeSelectLayout.getVisibility() == View.VISIBLE) {
+ closeModeSwitcher(true);
+ return true;
+ }
return false;
}
@@ -2008,6 +2173,7 @@ public class CaptureUI implements PreviewGestures.SingleTapListener,
@Override
public void onSingleTapUp(View view, int x, int y) {
+ closeModeSwitcher(true);
mModule.onSingleTapUp(view, x, y);
}
@@ -2062,6 +2228,7 @@ public class CaptureUI implements PreviewGestures.SingleTapListener,
}
public void pressShutterButton() {
+ closeModeSwitcher(true);
if (mShutterButton.isInTouchMode()) {
mShutterButton.requestFocusFromTouch();
} else {
@@ -2266,7 +2433,6 @@ public class CaptureUI implements PreviewGestures.SingleTapListener,
int mode = index % modeListSize;
mModule.setCameraModeSwitcherAllowed(false);
mCameraModeAdapter.setSelectedPosition(mode);
- mModeSelectLayout.smoothScrollToPosition(mode);
mModule.selectCameraMode(mode);
}
@@ -2280,12 +2446,12 @@ public class CaptureUI implements PreviewGestures.SingleTapListener,
}
}
mCameraModeAdapter.setSelectedPosition(photoModeIndex);
- mModeSelectLayout.smoothScrollToPosition(photoModeIndex);
if (switchCamera) {
mModule.selectCameraMode(photoModeIndex);
} else {
mModule.setNextSceneMode(photoModeIndex);
}
+ setFrontBackSwitcherDrawable();
}
}
diff --git a/src/com/android/camera/ComboPreferences.java b/src/com/android/camera/ComboPreferences.java
index dab69e85b..c20d40561 100644..100755
--- a/src/com/android/camera/ComboPreferences.java
+++ b/src/com/android/camera/ComboPreferences.java
@@ -107,6 +107,7 @@ public class ComboPreferences implements
movePrefFrom(prefMap, CameraSettings.KEY_CAMERA_FIRST_USE_HINT_SHOWN, src);
movePrefFrom(prefMap, CameraSettings.KEY_VIDEO_FIRST_USE_HINT_SHOWN, src);
movePrefFrom(prefMap, CameraSettings.KEY_VIDEO_EFFECT, src);
+ movePrefFrom(prefMap, CameraSettings.KEY_CAMERA_SAVEPATH, src);
}
public static String[] getSharedPreferencesNames(Context context, ArrayList<String> keys) {
@@ -156,10 +157,12 @@ public class ComboPreferences implements
|| key.equals(CameraSettings.KEY_TIMER)
|| key.equals(CameraSettings.KEY_TIMER_SOUND_EFFECTS)
|| key.equals(CameraSettings.KEY_PHOTOSPHERE_PICTURESIZE)
+ || key.equals(CameraSettings.KEY_CAMERA_SAVEPATH)
|| key.equals(SettingsManager.KEY_MONO_ONLY)
|| key.equals(SettingsManager.KEY_MONO_PREVIEW)
|| key.equals(SettingsManager.KEY_FRONT_REAR_SWITCHER_VALUE)
|| key.equals(SettingsManager.KEY_FORCE_AUX)
+ || key.equals(SettingsManager.KEY_CAMERA_SAVEPATH)
|| key.equals(SettingsManager.KEY_FACE_DETECTION)
|| key.equals(SettingsManager.KEY_RECORD_LOCATION)
|| key.equals(SettingsManager.KEY_CLEARSIGHT)
diff --git a/src/com/android/camera/ExtendedFace.java b/src/com/android/camera/ExtendedFace.java
index 7b50d4ad1..7b50d4ad1 100755..100644
--- a/src/com/android/camera/ExtendedFace.java
+++ b/src/com/android/camera/ExtendedFace.java
diff --git a/src/com/android/camera/ListPreference.java b/src/com/android/camera/ListPreference.java
index 3acf26e92..3acf26e92 100755..100644
--- a/src/com/android/camera/ListPreference.java
+++ b/src/com/android/camera/ListPreference.java
diff --git a/src/com/android/camera/LocationManager.java b/src/com/android/camera/LocationManager.java
index 2ae901aed..2ae901aed 100755..100644
--- a/src/com/android/camera/LocationManager.java
+++ b/src/com/android/camera/LocationManager.java
diff --git a/src/com/android/camera/MediaSaveService.java b/src/com/android/camera/MediaSaveService.java
index 7c1b050f2..72606766d 100755..100644
--- a/src/com/android/camera/MediaSaveService.java
+++ b/src/com/android/camera/MediaSaveService.java
@@ -291,8 +291,14 @@ public class MediaSaveService extends Service {
// combine to single mpo
String path = Storage.generateFilepath(title, pictureFormat);
- MpoInterface.writeMpo(mpo, path);
- return Storage.addImage(MediaSaveService.this, path);
+ int size = MpoInterface.writeMpo(mpo, path);
+ // Try to get the real image size after add exif.
+ File f = new File(path);
+ if (f.exists() && f.isFile()) {
+ size = (int) f.length();
+ }
+ return Storage.addImage(resolver, title, date, loc, orientation, null,
+ size, path, width, height, pictureFormat);
}
@Override
@@ -378,7 +384,9 @@ public class MediaSaveService extends Service {
@Override
protected Uri doInBackground(Void... params) {
- return Storage.addImage(MediaSaveService.this, path);
+ return Storage.addHeifImage(
+ resolver,title,date,loc,orientation,exif,path,
+ width,height,quality,pictureFormat);
}
@Override
@@ -430,7 +438,8 @@ public class MediaSaveService extends Service {
width = options.outWidth;
height = options.outHeight;
}
- return Storage.addImage(MediaSaveService.this, title, exif, data, pictureFormat);
+ return Storage.addImage(
+ resolver, title, date, loc, orientation, exif, data, width, height, pictureFormat);
}
@Override
@@ -506,7 +515,8 @@ public class MediaSaveService extends Service {
width = options.outWidth;
height = options.outHeight;
}
- return Storage.addImage(MediaSaveService.this, title, exif, data, pictureFormat);
+ return Storage.addImage(
+ resolver, title, date, loc, orientation, exif, data, width, height, pictureFormat);
}
@Override
diff --git a/src/com/android/camera/PanoCaptureModule.java b/src/com/android/camera/PanoCaptureModule.java
index b333158d9..cea752b25 100644..100755
--- a/src/com/android/camera/PanoCaptureModule.java
+++ b/src/com/android/camera/PanoCaptureModule.java
@@ -494,7 +494,9 @@ public class PanoCaptureModule implements CameraModule, PhotoController {
Log.e(TAG, "Cannot set exif for " + filepath, e);
Storage.writeFile(filepath, jpegData);
}
- return Storage.addImage(mActivity, filepath);
+ int jpegLength = (int) (new File(filepath).length());
+ return Storage.addImage(mContentResolver, filename, timeTaken, loc, orientation,
+ jpegLength, filepath, width, height, LocalData.MIME_TYPE_JPEG);
}
return null;
}
@@ -684,6 +686,11 @@ public class PanoCaptureModule implements CameraModule, PhotoController {
}
@Override
+ public void onSwitchSavePath() {
+
+ }
+
+ @Override
public void waitingLocationPermissionResult(boolean waiting) {
}
diff --git a/src/com/android/camera/PauseButton.java b/src/com/android/camera/PauseButton.java
index 6511e0e08..6511e0e08 100755..100644
--- a/src/com/android/camera/PauseButton.java
+++ b/src/com/android/camera/PauseButton.java
diff --git a/src/com/android/camera/PermissionsActivity.java b/src/com/android/camera/PermissionsActivity.java
index 19077a3c0..19077a3c0 100755..100644
--- a/src/com/android/camera/PermissionsActivity.java
+++ b/src/com/android/camera/PermissionsActivity.java
diff --git a/src/com/android/camera/PhotoController.java b/src/com/android/camera/PhotoController.java
index 18493755b..18493755b 100755..100644
--- a/src/com/android/camera/PhotoController.java
+++ b/src/com/android/camera/PhotoController.java
diff --git a/src/com/android/camera/PhotoMenu.java b/src/com/android/camera/PhotoMenu.java
index 71d827e3f..4f6c88688 100644
--- a/src/com/android/camera/PhotoMenu.java
+++ b/src/com/android/camera/PhotoMenu.java
@@ -187,6 +187,7 @@ public class PhotoMenu extends MenuController
CameraSettings.KEY_PICTURE_SIZE,
CameraSettings.KEY_JPEG_QUALITY,
CameraSettings.KEY_TIMER,
+ CameraSettings.KEY_CAMERA_SAVEPATH,
CameraSettings.KEY_LONGSHOT,
CameraSettings.KEY_FACE_DETECTION,
CameraSettings.KEY_ISO,
@@ -216,6 +217,7 @@ public class PhotoMenu extends MenuController
CameraSettings.KEY_PICTURE_SIZE,
CameraSettings.KEY_JPEG_QUALITY,
CameraSettings.KEY_TIMER,
+ CameraSettings.KEY_CAMERA_SAVEPATH,
CameraSettings.KEY_LONGSHOT,
CameraSettings.KEY_FACE_DETECTION,
CameraSettings.KEY_ISO,
diff --git a/src/com/android/camera/PhotoModule.java b/src/com/android/camera/PhotoModule.java
index 891a849a2..fb988b431 100644..100755
--- a/src/com/android/camera/PhotoModule.java
+++ b/src/com/android/camera/PhotoModule.java
@@ -616,6 +616,8 @@ public class PhotoModule
mBlurDegreeProgressBar = (SeekBar)mRootView.findViewById(R.id.blur_degree_bar);
mBlurDegreeProgressBar.setOnSeekBarChangeListener(mBlurDegreeListener);
mBlurDegreeProgressBar.setMax(100);
+ Storage.setSaveSDCard(
+ mPreferences.getString(CameraSettings.KEY_CAMERA_SAVEPATH, "0").equals("1"));
// LGE HDR mode
if (mApplicationContext != null) {
@@ -909,6 +911,19 @@ public class PhotoModule
mUI.setAspectRatio((float) size.width / size.height);
}
+ @Override
+ public void onSwitchSavePath() {
+ if (mUI.mMenuInitialized) {
+ mUI.setPreference(CameraSettings.KEY_CAMERA_SAVEPATH, "1");
+ } else {
+ mPreferences.edit()
+ .putString(CameraSettings.KEY_CAMERA_SAVEPATH, "1")
+ .apply();
+ }
+ RotateTextToast.makeText(mActivity, R.string.on_switch_save_path_to_sdcard,
+ Toast.LENGTH_SHORT).show();
+ }
+
// Snapshots can only be taken after this is called. It should be called
// once only. We could have done these things in onCreate() but we want to
// make preview screen appear as soon as possible.
@@ -1260,6 +1275,7 @@ public class PhotoModule
}
String dstPath = Storage.DIRECTORY;
+ File sdCard = android.os.Environment.getExternalStorageDirectory();
File dstFile = new File(dstPath);
if (dstFile == null) {
Log.e(TAG, "Destination file path invalid");
@@ -4963,6 +4979,13 @@ public class PhotoModule
return;
}
+ if (CameraSettings.KEY_CAMERA_SAVEPATH.equals(pref.getKey())) {
+ Storage.setSaveSDCard(
+ mPreferences.getString(CameraSettings.KEY_CAMERA_SAVEPATH, "0").equals("1"));
+ mActivity.updateStorageSpaceAndHint();
+ updateRemainingPhotos();
+ }
+
if (!CameraSettings.hasChromaFlashScene(mActivity) &&
CameraSettings.KEY_QC_CHROMA_FLASH.equals(pref.getKey())) {
mUI.setPreference(CameraSettings.KEY_ADVANCED_FEATURES, pref.getValue());
diff --git a/src/com/android/camera/PhotoUI.java b/src/com/android/camera/PhotoUI.java
index 072294da7..072294da7 100755..100644
--- a/src/com/android/camera/PhotoUI.java
+++ b/src/com/android/camera/PhotoUI.java
diff --git a/src/com/android/camera/PreviewGestures.java b/src/com/android/camera/PreviewGestures.java
index ce4587047..78591eab5 100755..100644
--- a/src/com/android/camera/PreviewGestures.java
+++ b/src/com/android/camera/PreviewGestures.java
@@ -93,17 +93,24 @@ public class PreviewGestures
return false;
}
if (mZoomOnly || mMode == MODE_ZOOM) return false;
-
int deltaX = (int) (e1.getX() - e2.getX());
int deltaY = (int) (e1.getY() - e2.getY());
if((Math.abs(deltaX) > 40 || Math.abs(deltaY) > 40) && Math.abs(e1.getY()) < 1800) {
int orientation = 0;
- if (mCaptureUI != null)
+ if (mPhotoMenu != null)
+ orientation = mPhotoMenu.getOrientation();
+ else if (mVideoMenu != null)
+ orientation = mVideoMenu.getOrientation();
+ else if (mCaptureUI != null)
orientation = mCaptureUI.getOrientation();
if (isLeftSwipe(orientation, deltaX, deltaY)) {
waitUntilNextDown = true;
- if (mCaptureUI != null)
+ if (mPhotoMenu != null && !mPhotoMenu.isMenuBeingShown())
+ mPhotoMenu.openFirstLevel();
+ else if (mVideoMenu != null && !mVideoMenu.isMenuBeingShown())
+ mVideoMenu.openFirstLevel();
+ else if (mCaptureUI != null)
mCaptureUI.swipeCameraMode(-1);
if (mMultiCameraUI != null)
mMultiCameraUI.swipeCameraMode(-1);
diff --git a/src/com/android/camera/SDCard.java b/src/com/android/camera/SDCard.java
new file mode 100755
index 000000000..836c2db8a
--- /dev/null
+++ b/src/com/android/camera/SDCard.java
@@ -0,0 +1,127 @@
+/* Copyright (c) 2014, 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 "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.android.camera;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Environment;
+import android.os.storage.StorageVolume;
+import android.os.storage.StorageManager;
+import android.util.Log;
+
+import java.util.List;
+
+public class SDCard {
+ private static final String TAG = "SDCard";
+
+ private static final int VOLUME_SDCARD_INDEX = 1;
+
+ private StorageManager mStorageManager = null;
+ private StorageVolume mVolume = null;
+ private String mPath = null;
+ private String mRawpath = null;
+ private static SDCard sSDCard;
+
+ public boolean isWriteable() {
+ if (mVolume == null) return false;
+ final String state = getSDCardStorageState();
+ if (Environment.MEDIA_MOUNTED.equals(state)) {
+ return true;
+ }
+ return false;
+ }
+
+ public String getDirectory() {
+ if (mVolume == null) {
+ return null;
+ }
+ if (mPath == null) {
+ mPath = mVolume.getDirectory().toString() + "/DCIM/Camera";
+ }
+ return mPath;
+ }
+
+ public String getRawDirectory() {
+ if (mVolume == null) {
+ return null;
+ }
+ if (mRawpath == null) {
+ mRawpath = mVolume.getDirectory().toString() + "/DCIM/Camera/raw";
+ }
+ return mRawpath;
+ }
+
+ public static void initialize(Context context) {
+ if (sSDCard == null) {
+ sSDCard = new SDCard(context);
+ }
+ }
+
+ public static synchronized SDCard instance() {
+ return sSDCard;
+ }
+
+ private String getSDCardStorageState() {
+ return mVolume.getState();
+ }
+
+ private SDCard(Context context) {
+ try {
+ mStorageManager = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);
+ initVolume();
+ registerMediaBroadcastreceiver(context);
+ } catch (Exception e) {
+ Log.e(TAG, "couldn't talk to MountService", e);
+ }
+ }
+
+ private void initVolume() {
+ final StorageVolume[] volumes = mStorageManager.getVolumeList();
+ mVolume = (volumes.length > VOLUME_SDCARD_INDEX) ?
+ volumes[VOLUME_SDCARD_INDEX] : null;
+ mPath = null;
+ mRawpath = null;
+ }
+
+ private void registerMediaBroadcastreceiver(Context context) {
+ IntentFilter filter = new IntentFilter(Intent.ACTION_MEDIA_MOUNTED);
+ filter.addAction(Intent.ACTION_MEDIA_UNMOUNTED);
+ filter.addDataScheme("file");
+ context.registerReceiver(mMediaBroadcastReceiver , filter);
+ }
+
+ private BroadcastReceiver mMediaBroadcastReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ initVolume();
+ }
+ };
+}
diff --git a/src/com/android/camera/SceneModeActivity.java b/src/com/android/camera/SceneModeActivity.java
index c6258d9d0..c6258d9d0 100755..100644
--- a/src/com/android/camera/SceneModeActivity.java
+++ b/src/com/android/camera/SceneModeActivity.java
diff --git a/src/com/android/camera/DisableCameraReceiver.java b/src/com/android/camera/SetActivitiesCameraReceiver.java
index 624874184..c2db30511 100644
--- a/src/com/android/camera/DisableCameraReceiver.java
+++ b/src/com/android/camera/SetActivitiesCameraReceiver.java
@@ -26,11 +26,10 @@ import android.util.Log;
import com.android.camera.util.CameraUtil;
import org.codeaurora.snapcam.R;
-// We want to disable camera-related activities if there is no camera. This
-// receiver runs when BOOT_COMPLETED intent is received. After running once
-// this receiver will be disabled, so it will not run again.
-public class DisableCameraReceiver extends BroadcastReceiver {
- private static final String TAG = "DisableCameraReceiver";
+// Enable or disable camera-related activities based on "camera hal" in every boot up.
+// This receiver runs when BOOT_COMPLETED intent is received.
+public class SetActivitiesCameraReceiver extends BroadcastReceiver {
+ private static final String TAG = "SetActivitiesCameraReceiver";
private static final boolean CHECK_BACK_CAMERA_ONLY = false;
private static final String ACTIVITIES[] = {
"com.android.camera.CameraLauncher",
@@ -51,19 +50,17 @@ public class DisableCameraReceiver extends BroadcastReceiver {
CameraHolder.setCamera2Mode(context, mCamera2enabled);
// Disable camera-related activities if there is no camera.
- boolean needCameraActivity = CHECK_BACK_CAMERA_ONLY
+ int component_state = (CHECK_BACK_CAMERA_ONLY
? hasBackCamera()
- : hasCamera();
+ : hasCamera())
+ ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
+ : PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
- if (!needCameraActivity) {
- Log.i(TAG, "disable all camera activities");
- for (int i = 0; i < ACTIVITIES.length; i++) {
- disableComponent(context, ACTIVITIES[i]);
- }
+ Log.i(TAG, "component state is " + component_state);
+ for (int i = 0; i < ACTIVITIES.length; i++) {
+ setComponent(context, ACTIVITIES[i],
+ component_state);
}
-
- // Disable this receiver so it won't run again.
- disableComponent(context, "com.android.camera.DisableCameraReceiver");
}
private boolean hasCamera() {
@@ -78,14 +75,14 @@ public class DisableCameraReceiver extends BroadcastReceiver {
return backCameraId != -1;
}
- private void disableComponent(Context context, String klass) {
+ private void setComponent(Context context, String klass, final int enabledState) {
ComponentName name = new ComponentName(context, klass);
PackageManager pm = context.getPackageManager();
// We need the DONT_KILL_APP flag, otherwise we will be killed
// immediately because we are in the same app.
pm.setComponentEnabledSetting(name,
- PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
+ enabledState,
PackageManager.DONT_KILL_APP);
}
}
diff --git a/src/com/android/camera/SettingsActivity.java b/src/com/android/camera/SettingsActivity.java
index 1a6702d8e..460385f38 100644..100755
--- a/src/com/android/camera/SettingsActivity.java
+++ b/src/com/android/camera/SettingsActivity.java
@@ -1175,6 +1175,7 @@ public class SettingsActivity extends PreferenceActivity {
updateZslPreference();
updateFormatPreference();
updateEISPreference();
+ updateStoragePreference();
updateMfnrPreference();
Map<String, SettingsManager.Values> map = mSettingsManager.getValuesMap();
@@ -1232,6 +1233,18 @@ public class SettingsActivity extends PreferenceActivity {
}
}
+ private void updateStoragePreference() {
+ boolean isWrite = SDCard.instance().isWriteable();
+ ListPreference pref = (ListPreference)findPreference(SettingsManager.KEY_CAMERA_SAVEPATH);
+ if (pref == null) {
+ return;
+ }
+ pref.setEnabled(isWrite);
+ if (!isWrite) {
+ updatePreference(SettingsManager.KEY_CAMERA_SAVEPATH);
+ }
+ }
+
private void updateMfnrPreference(){
CaptureModule.CameraMode mode =
(CaptureModule.CameraMode) getIntent().getSerializableExtra(CAMERA_MODULE);
diff --git a/src/com/android/camera/SettingsManager.java b/src/com/android/camera/SettingsManager.java
index 208d5a5c5..cfe42dfcd 100644..100755
--- a/src/com/android/camera/SettingsManager.java
+++ b/src/com/android/camera/SettingsManager.java
@@ -130,6 +130,7 @@ public class SettingsManager implements ListMenu.SettingsListener {
public static final String SCENE_MODE_DUAL_STRING = "100";
public static final String SCENE_MODE_SUNSET_STRING = "10";
public static final String SCENE_MODE_LANDSCAPE_STRING = "4";
+ public static final String KEY_CAMERA_SAVEPATH = "pref_camera2_savepath_key";
public static final String KEY_RECORD_LOCATION = "pref_camera2_recordlocation_key";
public static final String KEY_JPEG_QUALITY = "pref_camera2_jpegquality_key";
public static final String KEY_FOCUS_MODE = "pref_camera2_focusmode_key";
@@ -250,6 +251,7 @@ public class SettingsManager implements ListMenu.SettingsListener {
private boolean mIsFrontCameraPresent = false;
private boolean mHasMultiCamera = false;
private boolean mIsHFRSupported = false;
+ private boolean mIsHFRSupportedOnCurrentResolution = false;
private JSONObject mDependency;
private int mCameraId;
private Set<String> mFilteredKeys;
@@ -1076,6 +1078,7 @@ public class SettingsManager implements ListMenu.SettingsListener {
}
}
// filter unsupported preferences
+ ListPreference savePath = mPreferenceGroup.findPreference(KEY_CAMERA_SAVEPATH);
ListPreference forceAUX = mPreferenceGroup.findPreference(KEY_FORCE_AUX);
ListPreference whiteBalance = mPreferenceGroup.findPreference(KEY_WHITE_BALANCE);
ListPreference flashMode = mPreferenceGroup.findPreference(KEY_FLASH_MODE);
@@ -1116,6 +1119,13 @@ public class SettingsManager implements ListMenu.SettingsListener {
}
buildCameraId();
+ if (savePath != null) {
+ if (filterUnsupportedOptions(savePath, getSupportedSavePaths(cameraId))) {
+ mFilteredKeys.add(savePath.getKey());
+ }
+ }
+
+
if (whiteBalance != null) {
if (filterUnsupportedOptions(whiteBalance, getSupportedWhiteBalanceModes(cameraId))) {
mFilteredKeys.add(whiteBalance.getKey());
@@ -1526,6 +1536,10 @@ public class SettingsManager implements ListMenu.SettingsListener {
return mIsHFRSupported;
}
+ public boolean isHFRSupportedOnCurrentResolution() {
+ return mIsHFRSupportedOnCurrentResolution;
+ }
+
private void filterVideoEncoderProfileOptions() {
ListPreference videoEncoderProfilePref =
mPreferenceGroup.findPreference(KEY_VIDEO_ENCODER_PROFILE);
@@ -1696,12 +1710,14 @@ public class SettingsManager implements ListMenu.SettingsListener {
rate = String.valueOf(r.getUpper());
supported.add("hfr" + rate);
supported.add("hsr" + rate);
+ mIsHFRSupportedOnCurrentResolution = true;
}
}
}
}
} catch (IllegalArgumentException ex) {
Log.w(TAG, "HFR is not supported for this resolution " + ex);
+ mIsHFRSupportedOnCurrentResolution = false;
}
if (mExtendedHFRSize != null && mExtendedHFRSize.length >= 3) {
for (int i = 0; i < mExtendedHFRSize.length; i += 3) {
@@ -2117,6 +2133,16 @@ public class SettingsManager implements ListMenu.SettingsListener {
.get(CameraCharacteristics.LENS_INFO_MINIMUM_FOCUS_DISTANCE);
}
+ private List<String> getSupportedSavePaths(int cameraId) {
+ boolean writeable = SDCard.instance().isWriteable();
+ List<String> savePaths = new ArrayList<>();
+ savePaths.add("" + 0);
+ if (writeable) {
+ savePaths.add("" + 1);
+ }
+ return savePaths;
+ }
+
private List<String> getSupportedWhiteBalanceModes(int cameraId) {
try {
List<String> modes = new ArrayList<>();
diff --git a/src/com/android/camera/Storage.java b/src/com/android/camera/Storage.java
index db37b10a0..9c8f92af4 100644..100755
--- a/src/com/android/camera/Storage.java
+++ b/src/com/android/camera/Storage.java
@@ -23,11 +23,9 @@ import java.io.IOException;
import android.annotation.TargetApi;
import android.content.ContentResolver;
import android.content.ContentValues;
-import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.location.Location;
-import android.media.MediaScannerConnection;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
@@ -64,6 +62,16 @@ public class Storage {
public static final long UNKNOWN_SIZE = -3L;
public static final long LOW_STORAGE_THRESHOLD_BYTES = 60 * 1024 * 1024L;
+ private static boolean sSaveSDCard = false;
+
+ public static boolean isSaveSDCard() {
+ return sSaveSDCard;
+ }
+
+ public static void setSaveSDCard(boolean saveSDCard) {
+ sSaveSDCard = saveSDCard;
+ }
+
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
private static void setImageSize(ContentValues values, int width, int height) {
// The two fields are available since ICS but got published in JB
@@ -110,12 +118,19 @@ public class Storage {
}
// Save the image with a given mimeType and add it the MediaStore.
- public static Uri addImage(Context context, String title,
- ExifInterface exif, byte[] jpeg, String mimeType) {
+ public static Uri addImage(ContentResolver resolver, String title, long date,
+ Location location, int orientation, ExifInterface exif, byte[] jpeg, int width,
+ int height, String mimeType) {
String path = generateFilepath(title, mimeType);
- writeFile(path, jpeg, exif, mimeType);
- return addImage(context, path);
+ int size = writeFile(path, jpeg, exif, mimeType);
+ // Try to get the real image size after add exif.
+ File f = new File(path);
+ if (f.exists() && f.isFile()) {
+ size = (int) f.length();
+ }
+ return addImage(resolver, title, date, location, orientation, exif,
+ size, path, width, height, mimeType);
}
// Get a ContentValues object for the given photo data
@@ -168,15 +183,26 @@ public class Storage {
}
// Add the image to media store.
- public static Uri addImage(Context context, String path) {
- // Scan file
- MediaScannerConnection.scanFile(
- context,
- new String[] { path },
- null /* no mimetype, let scanner guess */,
- null /* no callback */);
-
- return Uri.fromFile(new File(path));
+ public static Uri addImage(ContentResolver resolver, String title,
+ long date, Location location, int orientation, ExifInterface exif,int jpegLength,
+ String path, int width, int height, String mimeType) {
+ // Insert into MediaStore.
+ ContentValues values =
+ getContentValuesForData(title, date, location, orientation, exif, jpegLength, path,
+ width, height, mimeType);
+
+ return insertImage(resolver, values);
+ }
+
+ public static Uri addImage(ContentResolver resolver, String title,
+ long date, Location location, int orientation,int jpegLength,
+ String path, int width, int height, String mimeType) {
+ // Insert into MediaStore.
+ ContentValues values =
+ getContentValuesForData(title, date, location, orientation, null, jpegLength,
+ path, width, height, mimeType);
+
+ return insertImage(resolver, values);
}
public static long addRawImage(String title, byte[] data,
@@ -191,20 +217,32 @@ public class Storage {
return size;
}
+ public static Uri addHeifImage(ContentResolver resolver, String title, long date,
+ Location location, int orientation, ExifInterface exif, String path, int width,
+ int height, int quality, String mimeType) {
+ File f = new File(path);
+ int size = 0;
+ if (f.exists() && f.isFile()) {
+ size = (int) f.length();
+ }
+ return addImage(resolver, title, date, location, orientation,
+ size, path, width, height, mimeType);
+ }
+
// Overwrites the file and updates the MediaStore, or inserts the image if
// one does not already exist.
- public static void updateImage(Uri imageUri, Context context, String title, long date,
+ public static void updateImage(Uri imageUri, ContentResolver resolver, String title, long date,
Location location, int orientation, ExifInterface exif, byte[] jpeg, int width,
int height, String mimeType) {
String path = generateFilepath(title, mimeType);
writeFile(path, jpeg, exif, mimeType);
- updateImage(imageUri, context, title, date, location, orientation, jpeg.length, path,
+ updateImage(imageUri, resolver, title, date, location, orientation, jpeg.length, path,
width, height, mimeType);
}
// Updates the image values in MediaStore, or inserts the image if one does
// not already exist.
- public static void updateImage(Uri imageUri, Context context, String title,
+ public static void updateImage(Uri imageUri, ContentResolver resolver, String title,
long date, Location location, int orientation, int jpegLength,
String path, int width, int height, String mimeType) {
@@ -213,7 +251,6 @@ public class Storage {
width, height, mimeType);
// Update the MediaStore
- ContentResolver resolver = context.getContentResolver();
int rowsModified = resolver.update(imageUri, values, null, null);
if (rowsModified == 0) {
@@ -225,13 +262,6 @@ public class Storage {
throw new IllegalStateException("Bad number of rows (" + rowsModified
+ ") updated for uri: " + imageUri);
}
-
- // Scan file
- MediaScannerConnection.scanFile(
- context,
- new String[] { path },
- null /* no mimetype, let scanner guess */,
- null /* no callback */);
}
public static void deleteImage(ContentResolver resolver, Uri uri) {
@@ -252,10 +282,18 @@ public class Storage {
}else if(pictureFormat.equalsIgnoreCase("heics")) {
suffix = ".heics";
}
- return DIRECTORY + '/' + title + suffix;
+ if (isSaveSDCard() && SDCard.instance().isWriteable()) {
+ return SDCard.instance().getDirectory() + '/' + title + suffix;
+ } else {
+ return DIRECTORY + '/' + title + suffix;
+ }
} else if (pictureFormat.equalsIgnoreCase("yuv")){
String suffix = ".yuv";
- return DIRECTORY + '/' + title + suffix;
+ if (isSaveSDCard() && SDCard.instance().isWriteable()) {
+ return SDCard.instance().getDirectory() + '/' + title + suffix;
+ } else {
+ return DIRECTORY + '/' + title + suffix;
+ }
} else {
File dir = new File(RAW_DIRECTORY);
dir.mkdirs();
@@ -263,7 +301,22 @@ public class Storage {
}
}
- public static long getAvailableSpace() {
+ private static long getSDCardAvailableSpace() {
+ if (SDCard.instance().isWriteable()) {
+ File dir = new File(SDCard.instance().getDirectory());
+ dir.mkdirs();
+ try {
+ StatFs stat = new StatFs(SDCard.instance().getDirectory());
+ long ret = stat.getAvailableBlocks() * (long) stat.getBlockSize();
+ return ret;
+ } catch (Exception e) {
+ }
+ return UNKNOWN_SIZE;
+ }
+ return UNKNOWN_SIZE;
+ }
+
+ private static long getInternalStorageAvailableSpace() {
String state = Environment.getExternalStorageState();
Log.d(TAG, "External storage state=" + state);
if (Environment.MEDIA_CHECKING.equals(state)) {
@@ -288,6 +341,14 @@ public class Storage {
return UNKNOWN_SIZE;
}
+ public static long getAvailableSpace() {
+ if (isSaveSDCard()) {
+ return getSDCardAvailableSpace();
+ } else {
+ return getInternalStorageAvailableSpace();
+ }
+ }
+
public static long getTotalSpace(){
String state = Environment.getExternalStorageState();
Log.d(TAG, "External storage state=" + state);
@@ -313,6 +374,16 @@ public class Storage {
return UNKNOWN_SIZE;
}
+ public static boolean switchSavePath() {
+ if (!isSaveSDCard()
+ && getInternalStorageAvailableSpace() <= LOW_STORAGE_THRESHOLD_BYTES
+ && getSDCardAvailableSpace() > LOW_STORAGE_THRESHOLD_BYTES) {
+ setSaveSDCard(true);
+ return true;
+ }
+ return false;
+ }
+
/**
* OSX requires plugged-in USB storage to have path /DCIM/NNNAAAAA to be
* imported. This is a temporary fix for bug#1655552.
diff --git a/src/com/android/camera/Thumbnail.java b/src/com/android/camera/Thumbnail.java
index 5f8483d6c..5f8483d6c 100755..100644
--- a/src/com/android/camera/Thumbnail.java
+++ b/src/com/android/camera/Thumbnail.java
diff --git a/src/com/android/camera/TsMakeupManager.java b/src/com/android/camera/TsMakeupManager.java
index b58c0c1c0..b58c0c1c0 100755..100644
--- a/src/com/android/camera/TsMakeupManager.java
+++ b/src/com/android/camera/TsMakeupManager.java
diff --git a/src/com/android/camera/VideoMenu.java b/src/com/android/camera/VideoMenu.java
index 6c2918e77..1bde44a8c 100644..100755
--- a/src/com/android/camera/VideoMenu.java
+++ b/src/com/android/camera/VideoMenu.java
@@ -115,6 +115,7 @@ public class VideoMenu extends MenuController
CameraSettings.KEY_VIDEOCAMERA_FLASH_MODE,
CameraSettings.KEY_RECORD_LOCATION,
CameraSettings.KEY_VIDEO_QUALITY,
+ CameraSettings.KEY_CAMERA_SAVEPATH,
CameraSettings.KEY_EXPOSURE,
CameraSettings.KEY_WHITE_BALANCE,
CameraSettings.KEY_VIDEOCAMERA_FOCUS_MODE,
@@ -129,6 +130,7 @@ public class VideoMenu extends MenuController
CameraSettings.KEY_RECORD_LOCATION,
CameraSettings.KEY_VIDEO_QUALITY,
CameraSettings.KEY_VIDEO_SNAPSHOT_SIZE,
+ CameraSettings.KEY_CAMERA_SAVEPATH,
CameraSettings.KEY_FACE_DETECTION,
CameraSettings.KEY_EXPOSURE,
CameraSettings.KEY_WHITE_BALANCE,
diff --git a/src/com/android/camera/VideoModule.java b/src/com/android/camera/VideoModule.java
index d59184592..b74458897 100644..100755
--- a/src/com/android/camera/VideoModule.java
+++ b/src/com/android/camera/VideoModule.java
@@ -108,6 +108,8 @@ public class VideoModule implements CameraModule,
private static final int SCREEN_DELAY = 2 * 60 * 1000;
+ private static final int SDCARD_SIZE_LIMIT = 4000 * 1024 * 1024;
+
private static final long SHUTTER_BUTTON_TIMEOUT = 0L; // 0ms
/**
@@ -135,6 +137,7 @@ public class VideoModule implements CameraModule,
private ComboPreferences mPreferences;
private PreferenceGroup mPreferenceGroup;
+ private boolean mSaveToSDCard = false;
// Preference must be read before starting preview. We check this before starting
// preview.
@@ -539,6 +542,9 @@ public class VideoModule implements CameraModule,
mContentResolver = mActivity.getContentResolver();
+ Storage.setSaveSDCard(
+ mPreferences.getString(CameraSettings.KEY_CAMERA_SAVEPATH, "0").equals("1"));
+ mSaveToSDCard = Storage.isSaveSDCard();
// Surface texture is from camera screen nail and startPreview needs it.
// This must be done before startPreview.
mIsVideoCaptureIntent = isVideoCaptureIntent();
@@ -1198,6 +1204,13 @@ public class VideoModule implements CameraModule,
}
@Override
+ public void onSwitchSavePath() {
+ mUI.setPreference(CameraSettings.KEY_CAMERA_SAVEPATH, "1");
+ RotateTextToast.makeText(mActivity, R.string.on_switch_save_path_to_sdcard,
+ Toast.LENGTH_SHORT).show();
+ }
+
+ @Override
public void installIntentFilter() {
if(mReceiver != null)
return;
@@ -1782,6 +1795,10 @@ public class VideoModule implements CameraModule,
maxFileSize = requestedSizeLimit;
}
+ if (Storage.isSaveSDCard() && maxFileSize > SDCARD_SIZE_LIMIT) {
+ maxFileSize = SDCARD_SIZE_LIMIT;
+ }
+
try {
mMediaRecorder.setMaxFileSize(maxFileSize);
} catch (RuntimeException exception) {
@@ -1849,7 +1866,12 @@ public class VideoModule implements CameraModule,
// Used when emailing.
String filename = title + convertOutputFormatToFileExt(outputFileFormat);
String mime = convertOutputFormatToMimeType(outputFileFormat);
- String path = Storage.DIRECTORY + '/' + filename;
+ String path = null;
+ if (Storage.isSaveSDCard() && SDCard.instance().isWriteable()) {
+ path = SDCard.instance().getDirectory() + '/' + filename;
+ } else {
+ path = Storage.DIRECTORY + '/' + filename;
+ }
mCurrentVideoValues = new ContentValues(9);
mCurrentVideoValues.put(Video.Media.TITLE, title);
mCurrentVideoValues.put(Video.Media.DISPLAY_NAME, filename);
@@ -1927,7 +1949,7 @@ public class VideoModule implements CameraModule,
stopVideoRecording();
mUI.showUIafterRecording();
if (what == MediaRecorder.MEDIA_RECORDER_ERROR_UNKNOWN) {
- // We may have run out of storage space.
+ // We may have run out of space on the sdcard.
mActivity.updateStorageSpaceAndHint();
}
}
@@ -3046,6 +3068,8 @@ public class VideoModule implements CameraModule,
setCameraParameters(false);
}
mRestartPreview = false;
+ Storage.setSaveSDCard(
+ mPreferences.getString(CameraSettings.KEY_CAMERA_SAVEPATH, "0").equals("1"));
mActivity.updateStorageSpaceAndHint();
mActivity.initPowerShutter(mPreferences);
mActivity.initMaxBrightness(mPreferences);
diff --git a/src/com/android/camera/VideoUI.java b/src/com/android/camera/VideoUI.java
index 712cfeeaf..712cfeeaf 100755..100644
--- a/src/com/android/camera/VideoUI.java
+++ b/src/com/android/camera/VideoUI.java
diff --git a/src/com/android/camera/WideAnglePanoramaModule.java b/src/com/android/camera/WideAnglePanoramaModule.java
index d66acd186..e1edcad6b 100644..100755
--- a/src/com/android/camera/WideAnglePanoramaModule.java
+++ b/src/com/android/camera/WideAnglePanoramaModule.java
@@ -49,6 +49,7 @@ import com.android.camera.CameraManager.CameraProxy;
import com.android.camera.app.OrientationManager;
import com.android.camera.data.LocalData;
import com.android.camera.exif.ExifInterface;
+import com.android.camera.ui.RotateTextToast;
import com.android.camera.util.CameraUtil;
import com.android.camera.util.UsageStatistics;
import org.codeaurora.snapcam.R;
@@ -886,7 +887,9 @@ public class WideAnglePanoramaModule
Log.e(TAG, "Cannot set exif for " + filepath, e);
Storage.writeFile(filepath, jpegData);
}
- return Storage.addImage(mActivity, filepath);
+ int jpegLength = (int) (new File(filepath).length());
+ return Storage.addImage(mContentResolver, filename, mTimeTaken, loc, orientation,
+ jpegLength, filepath, width, height, LocalData.MIME_TYPE_JPEG);
}
return null;
}
@@ -1013,6 +1016,13 @@ public class WideAnglePanoramaModule
}
@Override
+ public void onSwitchSavePath() {
+ mPreferences.getGlobal().edit().putString(CameraSettings.KEY_CAMERA_SAVEPATH, "1").apply();
+ RotateTextToast.makeText(mActivity, R.string.on_switch_save_path_to_sdcard,
+ Toast.LENGTH_SHORT).show();
+ }
+
+ @Override
public void onResumeBeforeSuper() {
mPaused = false;
mPreferences = ComboPreferences.get(mActivity);
diff --git a/src/com/android/camera/WideAnglePanoramaUI.java b/src/com/android/camera/WideAnglePanoramaUI.java
index 9a55972c3..9a55972c3 100755..100644
--- a/src/com/android/camera/WideAnglePanoramaUI.java
+++ b/src/com/android/camera/WideAnglePanoramaUI.java
diff --git a/src/com/android/camera/app/CameraApp.java b/src/com/android/camera/app/CameraApp.java
index ef36f2656..dc5825cb1 100644
--- a/src/com/android/camera/app/CameraApp.java
+++ b/src/com/android/camera/app/CameraApp.java
@@ -20,6 +20,7 @@ import android.app.ActivityManager;
import android.app.Application;
import android.content.Context;
+import com.android.camera.SDCard;
import com.android.camera.util.CameraUtil;
import com.android.camera.util.UsageStatistics;
import com.android.camera.SettingsManager;
@@ -44,6 +45,7 @@ public class CameraApp extends Application {
SettingsManager.createInstance(this);
UsageStatistics.initialize(this);
CameraUtil.initialize(this);
+ SDCard.initialize(this);
}
public static Context getContext() {
diff --git a/src/com/android/camera/app/PlaceholderManager.java b/src/com/android/camera/app/PlaceholderManager.java
index e9a99a6b1..326f0be80 100644
--- a/src/com/android/camera/app/PlaceholderManager.java
+++ b/src/com/android/camera/app/PlaceholderManager.java
@@ -147,7 +147,8 @@ public class PlaceholderManager implements ImageTaskManager {
}
Uri uri =
- Storage.addImage(mContext, null, null, null, PLACEHOLDER_MIME_TYPE);
+ Storage.addImage(mContext.getContentResolver(), title, timestamp, null, 0, null,
+ placeholder, width, height, PLACEHOLDER_MIME_TYPE);
if (uri == null) {
return null;
@@ -166,7 +167,7 @@ public class PlaceholderManager implements ImageTaskManager {
public void replacePlaceholder(Session session, Location location, int orientation,
ExifInterface exif, byte[] jpeg, int width, int height, String mimeType) {
- Storage.updateImage(session.outputUri, mContext, session.outputTitle,
+ Storage.updateImage(session.outputUri, mContext.getContentResolver(), session.outputTitle,
session.time, location, orientation, exif, jpeg, width, height, mimeType);
synchronized (mListenerRefs) {
diff --git a/src/com/android/camera/data/Camera2ModeAdapter.java b/src/com/android/camera/data/Camera2ModeAdapter.java
index 039180b91..086e9f779 100755..100644
--- a/src/com/android/camera/data/Camera2ModeAdapter.java
+++ b/src/com/android/camera/data/Camera2ModeAdapter.java
@@ -34,18 +34,22 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
-import android.widget.TextView;
+
+import com.android.camera.ui.RotateImageView;
+
import org.codeaurora.snapcam.R;
import java.util.List;
public class Camera2ModeAdapter extends RecyclerView.Adapter<Camera2ModeAdapter.ViewHolder> {
private List<String> mModeList;
+ private List<Integer> mIcons;
private int mSelectedPos = 2;
private OnItemClickListener mOnItemClickListener;
- public Camera2ModeAdapter(List<String> list) {
+ public Camera2ModeAdapter(List<String> list, List<Integer> icons) {
this.mModeList = list;
+ this.mIcons = icons;
}
public void setOnItemClickListener(OnItemClickListener listener) {
@@ -62,9 +66,9 @@ public class Camera2ModeAdapter extends RecyclerView.Adapter<Camera2ModeAdapter.
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
- holder.mCameraModeText.setText(mModeList.get(position));
- holder.mCameraModeText.setSelected(mSelectedPos == position);
- holder.mCameraModeText.setOnClickListener(new View.OnClickListener() {
+ holder.mCameraModeIcon.setSelected(mSelectedPos == position);
+ holder.mCameraModeIcon.setImageResource(mIcons.get(position));
+ holder.mCameraModeIcon.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mOnItemClickListener.onItemClick(position) >= 0) {
@@ -90,12 +94,11 @@ public class Camera2ModeAdapter extends RecyclerView.Adapter<Camera2ModeAdapter.
}
class ViewHolder extends RecyclerView.ViewHolder{
-
- protected TextView mCameraModeText;
+ protected RotateImageView mCameraModeIcon;
public ViewHolder(View itemView) {
super(itemView);
- mCameraModeText = (TextView) itemView.findViewById(R.id.mode_text);
+ mCameraModeIcon = itemView.findViewById(R.id.mode_icon);
}
}
-} \ No newline at end of file
+}
diff --git a/src/com/android/camera/data/CameraDataAdapter.java b/src/com/android/camera/data/CameraDataAdapter.java
index 8b6b03e54..95c1ea723 100644..100755
--- a/src/com/android/camera/data/CameraDataAdapter.java
+++ b/src/com/android/camera/data/CameraDataAdapter.java
@@ -27,6 +27,7 @@ import android.provider.MediaStore;
import android.util.Log;
import android.view.View;
+import com.android.camera.SDCard;
import com.android.camera.Storage;
import com.android.camera.app.PlaceholderManager;
import com.android.camera.ui.FilmStripView.ImageData;
@@ -279,7 +280,8 @@ public class CameraDataAdapter implements LocalDataAdapter {
}
private static String[] getCameraPath() {
- String[] cameraPath = { Storage.DIRECTORY + "/%" };
+ String[] cameraPath =
+ {Storage.DIRECTORY + "/%", SDCard.instance().getDirectory() + "/%"};
return cameraPath;
}
diff --git a/src/com/android/camera/deepportrait/CamGLRenderObserver.java b/src/com/android/camera/deepportrait/CamGLRenderObserver.java
index 53faa4543..53faa4543 100755..100644
--- a/src/com/android/camera/deepportrait/CamGLRenderObserver.java
+++ b/src/com/android/camera/deepportrait/CamGLRenderObserver.java
diff --git a/src/com/android/camera/deepportrait/CamGLRenderer.java b/src/com/android/camera/deepportrait/CamGLRenderer.java
index ef8e3b1f4..ef8e3b1f4 100755..100644
--- a/src/com/android/camera/deepportrait/CamGLRenderer.java
+++ b/src/com/android/camera/deepportrait/CamGLRenderer.java
diff --git a/src/com/android/camera/deepportrait/CamRenderShader.java b/src/com/android/camera/deepportrait/CamRenderShader.java
index 5b80ed919..5b80ed919 100755..100644
--- a/src/com/android/camera/deepportrait/CamRenderShader.java
+++ b/src/com/android/camera/deepportrait/CamRenderShader.java
diff --git a/src/com/android/camera/deepportrait/CamRenderTexture.java b/src/com/android/camera/deepportrait/CamRenderTexture.java
index c0b4108b3..c0b4108b3 100755..100644
--- a/src/com/android/camera/deepportrait/CamRenderTexture.java
+++ b/src/com/android/camera/deepportrait/CamRenderTexture.java
diff --git a/src/com/android/camera/deepportrait/DPImage.java b/src/com/android/camera/deepportrait/DPImage.java
index 381270682..381270682 100755..100644
--- a/src/com/android/camera/deepportrait/DPImage.java
+++ b/src/com/android/camera/deepportrait/DPImage.java
diff --git a/src/com/android/camera/deepportrait/GLCameraPreview.java b/src/com/android/camera/deepportrait/GLCameraPreview.java
index 7d62faebf..7d62faebf 100755..100644
--- a/src/com/android/camera/deepportrait/GLCameraPreview.java
+++ b/src/com/android/camera/deepportrait/GLCameraPreview.java
diff --git a/src/com/android/camera/imageprocessor/FrameProcessor.java b/src/com/android/camera/imageprocessor/FrameProcessor.java
index cd1a5f8a2..cd1a5f8a2 100755..100644
--- a/src/com/android/camera/imageprocessor/FrameProcessor.java
+++ b/src/com/android/camera/imageprocessor/FrameProcessor.java
diff --git a/src/com/android/camera/imageprocessor/PostProcessor.java b/src/com/android/camera/imageprocessor/PostProcessor.java
index d12955ada..d12955ada 100755..100644
--- a/src/com/android/camera/imageprocessor/PostProcessor.java
+++ b/src/com/android/camera/imageprocessor/PostProcessor.java
diff --git a/src/com/android/camera/imageprocessor/ZSLQueue.java b/src/com/android/camera/imageprocessor/ZSLQueue.java
index 8bcba71db..8bcba71db 100755..100644
--- a/src/com/android/camera/imageprocessor/ZSLQueue.java
+++ b/src/com/android/camera/imageprocessor/ZSLQueue.java
diff --git a/src/com/android/camera/imageprocessor/filter/DeepPortraitFilter.java b/src/com/android/camera/imageprocessor/filter/DeepPortraitFilter.java
index 6e98824d3..6e98824d3 100755..100644
--- a/src/com/android/camera/imageprocessor/filter/DeepPortraitFilter.java
+++ b/src/com/android/camera/imageprocessor/filter/DeepPortraitFilter.java
diff --git a/src/com/android/camera/imageprocessor/filter/DeepZoomFilter.java b/src/com/android/camera/imageprocessor/filter/DeepZoomFilter.java
index 9e271ae17..9e271ae17 100755..100644
--- a/src/com/android/camera/imageprocessor/filter/DeepZoomFilter.java
+++ b/src/com/android/camera/imageprocessor/filter/DeepZoomFilter.java
diff --git a/src/com/android/camera/imageprocessor/filter/UbifocusFilter.java b/src/com/android/camera/imageprocessor/filter/UbifocusFilter.java
index 0c588b976..0c588b976 100755..100644
--- a/src/com/android/camera/imageprocessor/filter/UbifocusFilter.java
+++ b/src/com/android/camera/imageprocessor/filter/UbifocusFilter.java
diff --git a/src/com/android/camera/multi/MultiCamera.java b/src/com/android/camera/multi/MultiCamera.java
index b63b4ab32..a934ec712 100755..100644
--- a/src/com/android/camera/multi/MultiCamera.java
+++ b/src/com/android/camera/multi/MultiCamera.java
@@ -1,47 +1,47 @@
-/*
-Copyright (c) 2020, The Linux Foundation. All rights reserved.
-
-Not a Contribution.
-
-Copyright (C) 2013 The Android Open Source Project
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-package com.android.camera.multi;
-
-public interface MultiCamera {
-
- boolean openCamera(String[] id);
-
- void startPreview();
-
- void closeSession();
-
- void closeCamera();
-
- void onShutterButtonClick(String[] ids);
-
- void onVideoButtonClick(String[] ids);
-
- void onPause();
-
- void onResume(String[] ids);
-
- void onButtonPause(String[] ids);
-
- void onButtonContinue(String[] ids);
-
- void onOrientationChanged(int orientation);
-
- boolean isRecordingVideo();
+/*
+Copyright (c) 2020, The Linux Foundation. All rights reserved.
+
+Not a Contribution.
+
+Copyright (C) 2013 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+package com.android.camera.multi;
+
+public interface MultiCamera {
+
+ boolean openCamera(String[] id);
+
+ void startPreview();
+
+ void closeSession();
+
+ void closeCamera();
+
+ void onShutterButtonClick(String[] ids);
+
+ void onVideoButtonClick(String[] ids);
+
+ void onPause();
+
+ void onResume(String[] ids);
+
+ void onButtonPause(String[] ids);
+
+ void onButtonContinue(String[] ids);
+
+ void onOrientationChanged(int orientation);
+
+ boolean isRecordingVideo();
} \ No newline at end of file
diff --git a/src/com/android/camera/multi/MultiCameraModule.java b/src/com/android/camera/multi/MultiCameraModule.java
index 9f5745225..10ed17f93 100644
--- a/src/com/android/camera/multi/MultiCameraModule.java
+++ b/src/com/android/camera/multi/MultiCameraModule.java
@@ -1,655 +1,674 @@
-/*
- * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved.
- * Not a Contribution.
- *
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.camera.multi;
-
-import android.content.Context;
-import android.content.Intent;
-import android.content.res.Configuration;
-import android.graphics.Rect;
-import android.hardware.camera2.CameraManager;
-import android.hardware.camera2.CameraAccessException;
-import android.hardware.camera2.CameraCharacteristics;
-import android.media.AudioManager;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.Looper;
-import android.os.Message;
-import android.view.WindowManager;
-import android.view.View;
-import android.view.KeyEvent;
-import android.view.OrientationEventListener;
-import android.util.Log;
-
-import java.util.List;
-import java.util.ArrayList;
-import java.util.Set;
-
-import com.android.camera.CameraModule;
-import com.android.camera.CameraActivity;
-import com.android.camera.MediaSaveService;
-import com.android.camera.PhotoController;
-import com.android.camera.util.CameraUtil;
-import com.android.camera.data.Camera2ModeAdapter.OnItemClickListener;
-
-public class MultiCameraModule implements CameraModule, PhotoController {
-
- private static final String TAG = "SnapCam_MultiCameraModule";
- private static final int MAX_NUM_CAM = 16;
-
- private static final int OPEN_CAMERA = 0;
-
- public static final int CLEAR_SCREEN_DELAY = 101;
-
- private View mRootView;
- private MultiCameraUI mUI;
- private CameraActivity mActivity;
- private MultiCamera mMultiCamera;
-
- /**
- * An additional thread for running tasks that shouldn't block the UI.
- */
- private HandlerThread mCameraThread;
- private HandlerThread mCaptureCallbackThread;
-
- private Handler mCameraHandler;
- private Handler mCaptureCallbackHandler;
-
- private final Handler mHandler = new MainHandler();
-
- private int mDisplayRotation;
- private int mDisplayOrientation;
-
- private boolean mCameraModeSwitcherAllowed = true;
- private int mNextModeIndex = 1;
- private int mCurrentModeIndex = 1;
-
- // The degrees of the device rotated clockwise from its natural orientation.
- private int mOrientation = OrientationEventListener.ORIENTATION_UNKNOWN;
-
- private boolean mIsMute = false;
-
- private boolean[] mTakingPicture = new boolean[MAX_NUM_CAM];
-
- private ArrayList<SceneModule> mSceneCameraIds = new ArrayList<>();
- private String[] mSelectableModes = {"Video", "Photo"};
- private SceneModule mCurrentSceneMode;
- private String[] mCameraIds = new String[2];
-
- public static int CURRENT_ID = 0;
- public static CameraMode CURRENT_MODE = CameraMode.DEFAULT;
-
- public enum CameraMode {
- VIDEO,
- DEFAULT
- }
-
- public Handler getMainHandler() {
- return mHandler;
- }
-
- public Handler getMyCameraHandler() {
- return mCameraHandler;
- }
-
- public void reinit() {
- }
-
- public List<String> getCameraModeList() {
- ArrayList<String> cameraModes = new ArrayList<>();
- for (SceneModule sceneModule : mSceneCameraIds) {
- cameraModes.add(mSelectableModes[sceneModule.mode.ordinal()]);
- }
- return cameraModes;
- }
-
- public OnItemClickListener getModeItemClickListener() {
- return new OnItemClickListener() {
- @Override
- public int onItemClick(int mode) {
- Log.v(TAG, " onItemClick mode :" + mode);
- if (!getCameraModeSwitcherAllowed()) {
- return -1;
- }
- return selectCameraMode(mode);
- }
- };
- }
-
- public int selectCameraMode(int mode) {
- if (mCurrentSceneMode.mode == mSceneCameraIds.get(mode).mode) {
- return -1;
- }
- setCameraModeSwitcherAllowed(true);
- setNextSceneMode(mode);
- mCurrentSceneMode = mSceneCameraIds.get(mode);
- SceneModule nextSceneMode = mSceneCameraIds.get(mode);
- restartAll();
- return 1;
- }
-
- public void setNextSceneMode(int index) {
- mNextModeIndex = index;
- }
-
- public void setCameraModeSwitcherAllowed(boolean allow) {
- mCameraModeSwitcherAllowed = allow;
- }
-
- public int getCurrentModeIndex() {
- return mCurrentModeIndex;
- }
-
- public void setCurrentSceneModeOnly(int mode) {
- mCurrentSceneMode = mSceneCameraIds.get(mode);
- mCurrentModeIndex = mode;
- CURRENT_ID = mCurrentSceneMode.getCurrentId();
- CURRENT_MODE = mCurrentSceneMode.mode;
- }
-
- public void restartAll() {
- Log.d(TAG, "restart all");
- onPauseBeforeSuper();
- onPauseAfterSuper();
- setCurrentSceneModeOnly(mNextModeIndex);
- updateMultiCamera();
- onResumeBeforeSuper();
- onResumeAfterSuper();
- }
-
- private void updateMultiCamera() {
- mMultiCamera = null;
- if (mCurrentSceneMode.mode == CameraMode.VIDEO) {
- mMultiCamera = new MultiVideoModule(mActivity, mUI, this);
- } else if (mCurrentSceneMode.mode == CameraMode.DEFAULT) {
- mMultiCamera = new MultiCaptureModule(mActivity, mUI, this);
- }
- }
-
- public boolean getCameraModeSwitcherAllowed() {
- return mCameraModeSwitcherAllowed;
- }
-
- public void onVideoButtonClick() {
- Log.d(TAG, "onVideoButtonClick");
- mMultiCamera.onVideoButtonClick(mCameraIds);
- }
-
- public boolean isTakingPicture() {
- for (int i = 0; i < mTakingPicture.length; i++) {
- if (mTakingPicture[i]) return true;
- }
- return false;
- }
-
- public boolean isRecordingVideo() {
- return mMultiCamera.isRecordingVideo();
- }
-
- public void updateTakingPicture() {
- for (int i = 0; i < mTakingPicture.length; i++) {
- mTakingPicture[i] = false;
- }
- }
-
- public void setMute(boolean enable, boolean isValue) {
- AudioManager am = (AudioManager) mActivity.getSystemService(Context.AUDIO_SERVICE);
- am.setMicrophoneMute(enable);
- if (isValue) {
- mIsMute = enable;
- }
- }
-
- public boolean isAudioMute() {
- return mIsMute;
- }
-
- public void onButtonPause() {
- Log.v(TAG, "onButtonPause");
- mMultiCamera.onButtonPause(mCameraIds);
- }
-
- public void onButtonContinue() {
- Log.v(TAG, "onButtonContinue");
- mMultiCamera.onButtonContinue(mCameraIds);
- }
-
- public int[] getOpenCameraIdList() {
- int[] result = new int[2];
- result[0] = 0;
- result[1] = 2;
- return result;
- }
-
- public CameraMode getCurrenCameraMode() {
- if (mCurrentSceneMode == null) {
- Log.w(TAG, "getCurrenCameraMode mCurrentSceneMode is NULL retrun CameraMode.DEFAULT");
- return CameraMode.DEFAULT;
- } else {
- return mCurrentSceneMode.mode;
- }
- }
-
- @Override
- public void init(CameraActivity activity, View parent) {
- SceneModule module;
- Log.v(TAG, " init ");
- for (int i = 0; i < mSelectableModes.length; i++) {
- module = new SceneModule();
- module.mode = CameraMode.values()[i];
- mSceneCameraIds.add(module);
- }
-
- for (int i = 0; i < MAX_NUM_CAM; i++) {
- mTakingPicture[i] = false;
- }
-
- mCurrentSceneMode = mSceneCameraIds.get(1);
-
- mActivity = activity;
- mRootView = parent;
- if (mUI == null) {
- mUI = new MultiCameraUI(activity, this, parent);
- }
- mMultiCamera = new MultiCaptureModule(mActivity, mUI, this);
- startBackgroundThread();
- initCameraIds();
- }
-
- @Override
- public void onPreviewFocusChanged(boolean previewFocused) {
-
- }
-
- @Override
- public void onResumeBeforeSuper() {
- for (int i = 0; i < MAX_NUM_CAM; i++) {
- mTakingPicture[i] = false;
- }
- startBackgroundThread();
- }
-
- @Override
- public void onResumeAfterSuper() {
- Log.d(TAG, " onResumeAfterSuper ");
- mCameraIds[0] = "0";
- mCameraIds[1] = "2";
- mMultiCamera.onResume(mCameraIds);
- Message msg = Message.obtain();
- msg.what = OPEN_CAMERA;
- if (mCameraHandler != null) {
- mCameraHandler.sendMessage(msg);
- }
- mUI.showRelatedIcons(mCurrentSceneMode.mode);
- }
-
- @Override
- public void onPauseBeforeSuper() {
- Log.d(TAG, " onPauseBeforeSuper ");
- mMultiCamera.onPause();
- }
-
- @Override
- public void onPauseAfterSuper() {
- stopBackgroundThread();
- }
-
- @Override
- public void onConfigurationChanged(Configuration config) {
-
- }
-
- @Override
- public void onStop() {
-
- }
-
- @Override
- public void onDestroy() {
-
- }
-
- @Override
- public void installIntentFilter() {
-
- }
-
- @Override
- public void onActivityResult(int requestCode, int resultCode, Intent data) {
-
- }
-
- @Override
- public boolean onBackPressed() {
- return false;
- }
-
- @Override
- public boolean onKeyDown(int keyCode, KeyEvent event) {
- return false;
- }
-
- @Override
- public boolean onKeyUp(int keyCode, KeyEvent event) {
- return false;
- }
-
- @Override
- public void onSingleTapUp(View view, int x, int y) {
-
- }
-
- @Override
- public void onLongPress(View view, int x, int y) {
- }
-
- @Override
- public void onPreviewTextureCopied() {
-
- }
-
- @Override
- public void onCaptureTextureCopied() {
-
- }
-
- @Override
- public void onUserInteraction() {
-
- }
-
- @Override
- public boolean updateStorageHintOnResume() {
- return false;
- }
-
- @Override
- public void onOrientationChanged(int orientation) {
- // We keep the last known orientation. So if the user first orient
- // the camera then point the camera to floor or sky, we still have
- // the correct orientation.
- if (orientation == OrientationEventListener.ORIENTATION_UNKNOWN) return;
- int oldOrientation = mOrientation;
- mOrientation = CameraUtil.roundOrientation(orientation, mOrientation);
- if (oldOrientation != mOrientation) {
- mUI.setOrientation(mOrientation, true);
- mMultiCamera.onOrientationChanged(mOrientation);
- }
-
- }
-
- @Override
- public void onShowSwitcherPopup() {
-
- }
-
- @Override
- public void onMediaSaveServiceConnected(MediaSaveService s) {
-
- }
-
- @Override
- public boolean arePreviewControlsVisible() {
- return false;
- }
-
- @Override
- public void resizeForPreviewAspectRatio() {
-
- }
-
- @Override
- public void waitingLocationPermissionResult(boolean waiting) {
-
- }
-
- @Override
- public void enableRecordingLocation(boolean enable) {
-
- }
-
- @Override
- public void setPreferenceForTest(String key, String value) {
-
- }
-
- @Override
- public int onZoomChanged(int requestedZoom) {
- return 0;
- }
-
- @Override
- public void onZoomChanged(float requestedZoom) {
- }
-
- @Override
- public boolean isImageCaptureIntent() {
- return false;
- }
-
- @Override
- public boolean isCameraIdle() {
- return true;
- }
-
- @Override
- public void onCaptureDone() {
-
- }
-
- @Override
- public void onCaptureCancelled() {
-
- }
-
- @Override
- public void onCaptureRetake() {
-
- }
-
- @Override
- public void cancelAutoFocus() {
-
- }
-
- @Override
- public void stopPreview() {
-
- }
-
- @Override
- public int getCameraState() {
- return 0;
- }
-
- @Override
- public void onCountDownFinished() {
- }
-
- @Override
- public void onScreenSizeChanged(int width, int height) {
-
- }
-
- @Override
- public void onPreviewRectChanged(Rect previewRect) {
-
- }
-
- @Override
- public void updateCameraOrientation() {
- if (mDisplayRotation != CameraUtil.getDisplayRotation(mActivity)) {
- setDisplayOrientation();
- }
- }
-
- @Override
- public void onPreviewUIReady() {
- }
-
- @Override
- public void onPreviewUIDestroyed() {
- }
-
- @Override
- public void onShutterButtonClick() {
- Log.d(TAG, "onShutterButtonClick");
- mMultiCamera.onShutterButtonClick(mCameraIds);
- for (String CameraId : mCameraIds) {
- int id = Integer.parseInt(CameraId);
- mTakingPicture[id] = true;
- }
- }
-
- @Override
- public void onShutterButtonLongClick() {
-
- }
-
- @Override
- public void onShutterButtonFocus(boolean pressed) {
-
- }
-
- private class SceneModule {
- CameraMode mode = CameraMode.DEFAULT;
- public int rearCameraId;
- public int frontCameraId;
- public int auxCameraId = 0;
- int getCurrentId() {
- return rearCameraId;
- }
- }
-
- /**
- * This Handler is used to post message back onto the main thread of the
- * application
- */
- private class MainHandler extends Handler {
- public MainHandler() {
- super(Looper.getMainLooper());
- }
-
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case CLEAR_SCREEN_DELAY: {
- mActivity.getWindow().clearFlags(
- WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
- break;
- }
- }
- }
- }
-
- private void initCameraIds() {
- CameraManager manager = (CameraManager) mActivity.getSystemService(Context.CAMERA_SERVICE);
- boolean isFirstDefault = true;
- String[] cameraIdList = null;
- try {
- cameraIdList = manager.getCameraIdList();
- } catch (CameraAccessException e) {
- e.printStackTrace();
- }
- if (cameraIdList == null || cameraIdList.length == 0) {
- return;
- }
- for (int i = 0; i < cameraIdList.length; i++) {
- String cameraId = cameraIdList[i];
- CameraCharacteristics characteristics;
- try {
- characteristics = manager.getCameraCharacteristics(cameraId);
- } catch (CameraAccessException e) {
- e.printStackTrace();
- continue;
- }
- Set<String> physicalCameraIds = characteristics.getPhysicalCameraIds();
- for (String camId : physicalCameraIds) {
- Log.v(TAG, "initCameraIds physicalCameraIds :" + physicalCameraIds);
- Log.v(TAG, "initCameraIds >>>> camId :" + camId + " cameraId :" + cameraId + ", i :" + i);
- }
- }
- }
-
- /**
- * Starts a background thread and its {@link Handler}.
- */
- private void startBackgroundThread() {
- if (mCameraThread == null) {
- mCameraThread = new HandlerThread("CameraBackground");
- mCameraThread.start();
- }
- if (mCaptureCallbackThread == null) {
- mCaptureCallbackThread = new HandlerThread("CameraCaptureCallback");
- mCaptureCallbackThread.start();
- }
-
- if (mCameraHandler == null) {
- mCameraHandler = new MyCameraHandler(mCameraThread.getLooper());
- }
- if (mCaptureCallbackHandler == null) {
- mCaptureCallbackHandler = new Handler(mCaptureCallbackThread.getLooper());
- }
- }
-
- private void stopBackgroundThread() {
- mCameraThread.quitSafely();
- try {
- mCameraThread.join();
- mCameraThread = null;
- mCameraHandler = null;
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
-
- mCaptureCallbackThread.quitSafely();
- try {
- mCaptureCallbackThread.join();
- mCaptureCallbackThread = null;
- mCaptureCallbackHandler = null;
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
-
- private class MyCameraHandler extends Handler {
-
- public MyCameraHandler(Looper looper) {
- super(looper);
- }
-
- @Override
- public void handleMessage(Message msg) {
- int id = msg.arg1;
- switch (msg.what) {
- case OPEN_CAMERA:
- if (mMultiCamera != null) {
- mMultiCamera.openCamera(mCameraIds);
- }
- break;
- }
- }
- }
-
- private void setDisplayOrientation() {
- mDisplayRotation = CameraUtil.getDisplayRotation(mActivity);
- mDisplayOrientation = CameraUtil.getDisplayOrientationForCamera2(
- mDisplayRotation, 0);
- }
-
-}
+/*
+ * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.camera.multi;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Configuration;
+import android.content.res.TypedArray;
+import android.graphics.Rect;
+import android.hardware.camera2.CameraManager;
+import android.hardware.camera2.CameraAccessException;
+import android.hardware.camera2.CameraCharacteristics;
+import android.media.AudioManager;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.Message;
+import android.view.WindowManager;
+import android.view.View;
+import android.view.KeyEvent;
+import android.view.OrientationEventListener;
+import android.util.Log;
+
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Set;
+
+import com.android.camera.CameraModule;
+import com.android.camera.CameraActivity;
+import com.android.camera.MediaSaveService;
+import com.android.camera.PhotoController;
+import com.android.camera.util.CameraUtil;
+import com.android.camera.data.Camera2ModeAdapter.OnItemClickListener;
+
+import org.codeaurora.snapcam.R;
+
+public class MultiCameraModule implements CameraModule, PhotoController {
+
+ private static final String TAG = "SnapCam_MultiCameraModule";
+ private static final int MAX_NUM_CAM = 16;
+
+ private static final int OPEN_CAMERA = 0;
+
+ public static final int CLEAR_SCREEN_DELAY = 101;
+
+ private View mRootView;
+ private MultiCameraUI mUI;
+ private CameraActivity mActivity;
+ private MultiCamera mMultiCamera;
+
+ /**
+ * An additional thread for running tasks that shouldn't block the UI.
+ */
+ private HandlerThread mCameraThread;
+ private HandlerThread mCaptureCallbackThread;
+
+ private Handler mCameraHandler;
+ private Handler mCaptureCallbackHandler;
+
+ private final Handler mHandler = new MainHandler();
+
+ private int mDisplayRotation;
+ private int mDisplayOrientation;
+
+ private boolean mCameraModeSwitcherAllowed = true;
+ private int mNextModeIndex = 1;
+ private int mCurrentModeIndex = 1;
+
+ // The degrees of the device rotated clockwise from its natural orientation.
+ private int mOrientation = OrientationEventListener.ORIENTATION_UNKNOWN;
+
+ private boolean mIsMute = false;
+
+ private boolean[] mTakingPicture = new boolean[MAX_NUM_CAM];
+
+ private ArrayList<SceneModule> mSceneCameraIds = new ArrayList<>();
+ private String[] mSelectableModes = {"Video", "Photo"};
+ private SceneModule mCurrentSceneMode;
+ private String[] mCameraIds = new String[2];
+
+ public static int CURRENT_ID = 0;
+ public static CameraMode CURRENT_MODE = CameraMode.DEFAULT;
+
+ public enum CameraMode {
+ VIDEO,
+ DEFAULT
+ }
+
+ public Handler getMainHandler() {
+ return mHandler;
+ }
+
+ public Handler getMyCameraHandler() {
+ return mCameraHandler;
+ }
+
+ public void reinit() {
+ }
+
+ public List<String> getCameraModeList() {
+ ArrayList<String> cameraModes = new ArrayList<>();
+ for (SceneModule sceneModule : mSceneCameraIds) {
+ cameraModes.add(mSelectableModes[sceneModule.mode.ordinal()]);
+ }
+ return cameraModes;
+ }
+
+ public OnItemClickListener getModeItemClickListener() {
+ return new OnItemClickListener() {
+ @Override
+ public int onItemClick(int mode) {
+ Log.v(TAG, " onItemClick mode :" + mode);
+ if (!getCameraModeSwitcherAllowed()) {
+ return -1;
+ }
+ return selectCameraMode(mode);
+ }
+ };
+ }
+
+ public int selectCameraMode(int mode) {
+ if (mCurrentSceneMode.mode == mSceneCameraIds.get(mode).mode) {
+ return -1;
+ }
+ setCameraModeSwitcherAllowed(true);
+ setNextSceneMode(mode);
+ mCurrentSceneMode = mSceneCameraIds.get(mode);
+ SceneModule nextSceneMode = mSceneCameraIds.get(mode);
+ restartAll();
+ return 1;
+ }
+
+ public void setNextSceneMode(int index) {
+ mNextModeIndex = index;
+ }
+
+ public void setCameraModeSwitcherAllowed(boolean allow) {
+ mCameraModeSwitcherAllowed = allow;
+ }
+
+ public int getCurrentModeIndex() {
+ return mCurrentModeIndex;
+ }
+
+ public List<Integer> getCameraModeIconList() {
+ ArrayList<Integer> cameraModeIcons = new ArrayList<>();
+ TypedArray ic = mActivity.getResources()
+ .obtainTypedArray(R.array.camera_modes_front);
+ for (SceneModule sceneModule : mSceneCameraIds) {
+ cameraModeIcons.add(ic.getResourceId(sceneModule.mode.ordinal(), 0));
+ }
+ return cameraModeIcons;
+ }
+
+ public void setCurrentSceneModeOnly(int mode) {
+ mCurrentSceneMode = mSceneCameraIds.get(mode);
+ mCurrentModeIndex = mode;
+ CURRENT_ID = mCurrentSceneMode.getCurrentId();
+ CURRENT_MODE = mCurrentSceneMode.mode;
+ }
+
+ public void restartAll() {
+ Log.d(TAG, "restart all");
+ onPauseBeforeSuper();
+ onPauseAfterSuper();
+ setCurrentSceneModeOnly(mNextModeIndex);
+ updateMultiCamera();
+ onResumeBeforeSuper();
+ onResumeAfterSuper();
+ }
+
+ private void updateMultiCamera() {
+ mMultiCamera = null;
+ if (mCurrentSceneMode.mode == CameraMode.VIDEO) {
+ mMultiCamera = new MultiVideoModule(mActivity, mUI, this);
+ } else if (mCurrentSceneMode.mode == CameraMode.DEFAULT) {
+ mMultiCamera = new MultiCaptureModule(mActivity, mUI, this);
+ }
+ }
+
+ public boolean getCameraModeSwitcherAllowed() {
+ return mCameraModeSwitcherAllowed;
+ }
+
+ public void onVideoButtonClick() {
+ Log.d(TAG, "onVideoButtonClick");
+ mMultiCamera.onVideoButtonClick(mCameraIds);
+ }
+
+ public boolean isTakingPicture() {
+ for (int i = 0; i < mTakingPicture.length; i++) {
+ if (mTakingPicture[i]) return true;
+ }
+ return false;
+ }
+
+ public boolean isRecordingVideo() {
+ return mMultiCamera.isRecordingVideo();
+ }
+
+ public void updateTakingPicture() {
+ for (int i = 0; i < mTakingPicture.length; i++) {
+ mTakingPicture[i] = false;
+ }
+ }
+
+ public void setMute(boolean enable, boolean isValue) {
+ AudioManager am = (AudioManager) mActivity.getSystemService(Context.AUDIO_SERVICE);
+ am.setMicrophoneMute(enable);
+ if (isValue) {
+ mIsMute = enable;
+ }
+ }
+
+ public boolean isAudioMute() {
+ return mIsMute;
+ }
+
+ public void onButtonPause() {
+ Log.v(TAG, "onButtonPause");
+ mMultiCamera.onButtonPause(mCameraIds);
+ }
+
+ public void onButtonContinue() {
+ Log.v(TAG, "onButtonContinue");
+ mMultiCamera.onButtonContinue(mCameraIds);
+ }
+
+ public int[] getOpenCameraIdList() {
+ int[] result = new int[2];
+ result[0] = 0;
+ result[1] = 2;
+ return result;
+ }
+
+ public CameraMode getCurrenCameraMode() {
+ if (mCurrentSceneMode == null) {
+ Log.w(TAG, "getCurrenCameraMode mCurrentSceneMode is NULL retrun CameraMode.DEFAULT");
+ return CameraMode.DEFAULT;
+ } else {
+ return mCurrentSceneMode.mode;
+ }
+ }
+
+ @Override
+ public void init(CameraActivity activity, View parent) {
+ SceneModule module;
+ Log.v(TAG, " init ");
+ for (int i = 0; i < mSelectableModes.length; i++) {
+ module = new SceneModule();
+ module.mode = CameraMode.values()[i];
+ mSceneCameraIds.add(module);
+ }
+
+ for (int i = 0; i < MAX_NUM_CAM; i++) {
+ mTakingPicture[i] = false;
+ }
+
+ mCurrentSceneMode = mSceneCameraIds.get(1);
+
+ mActivity = activity;
+ mRootView = parent;
+ if (mUI == null) {
+ mUI = new MultiCameraUI(activity, this, parent);
+ }
+ mMultiCamera = new MultiCaptureModule(mActivity, mUI, this);
+ startBackgroundThread();
+ initCameraIds();
+ }
+
+ @Override
+ public void onPreviewFocusChanged(boolean previewFocused) {
+
+ }
+
+ @Override
+ public void onResumeBeforeSuper() {
+ for (int i = 0; i < MAX_NUM_CAM; i++) {
+ mTakingPicture[i] = false;
+ }
+ startBackgroundThread();
+ }
+
+ @Override
+ public void onResumeAfterSuper() {
+ Log.d(TAG, " onResumeAfterSuper ");
+ mCameraIds[0] = "0";
+ mCameraIds[1] = "2";
+ mMultiCamera.onResume(mCameraIds);
+ Message msg = Message.obtain();
+ msg.what = OPEN_CAMERA;
+ if (mCameraHandler != null) {
+ mCameraHandler.sendMessage(msg);
+ }
+ mUI.showRelatedIcons(mCurrentSceneMode.mode);
+ }
+
+ @Override
+ public void onPauseBeforeSuper() {
+ Log.d(TAG, " onPauseBeforeSuper ");
+ mMultiCamera.onPause();
+ }
+
+ @Override
+ public void onPauseAfterSuper() {
+ stopBackgroundThread();
+ }
+
+ @Override
+ public void onConfigurationChanged(Configuration config) {
+
+ }
+
+ @Override
+ public void onStop() {
+
+ }
+
+ @Override
+ public void onDestroy() {
+
+ }
+
+ @Override
+ public void installIntentFilter() {
+
+ }
+
+ @Override
+ public void onActivityResult(int requestCode, int resultCode, Intent data) {
+
+ }
+
+ @Override
+ public boolean onBackPressed() {
+ return false;
+ }
+
+ @Override
+ public boolean onKeyDown(int keyCode, KeyEvent event) {
+ return false;
+ }
+
+ @Override
+ public boolean onKeyUp(int keyCode, KeyEvent event) {
+ return false;
+ }
+
+ @Override
+ public void onSingleTapUp(View view, int x, int y) {
+
+ }
+
+ @Override
+ public void onLongPress(View view, int x, int y) {
+ }
+
+ @Override
+ public void onPreviewTextureCopied() {
+
+ }
+
+ @Override
+ public void onCaptureTextureCopied() {
+
+ }
+
+ @Override
+ public void onUserInteraction() {
+
+ }
+
+ @Override
+ public boolean updateStorageHintOnResume() {
+ return false;
+ }
+
+ @Override
+ public void onOrientationChanged(int orientation) {
+ // We keep the last known orientation. So if the user first orient
+ // the camera then point the camera to floor or sky, we still have
+ // the correct orientation.
+ if (orientation == OrientationEventListener.ORIENTATION_UNKNOWN) return;
+ int oldOrientation = mOrientation;
+ mOrientation = CameraUtil.roundOrientation(orientation, mOrientation);
+ if (oldOrientation != mOrientation) {
+ mUI.setOrientation(mOrientation, true);
+ mMultiCamera.onOrientationChanged(mOrientation);
+ }
+
+ }
+
+ @Override
+ public void onShowSwitcherPopup() {
+
+ }
+
+ @Override
+ public void onMediaSaveServiceConnected(MediaSaveService s) {
+
+ }
+
+ @Override
+ public boolean arePreviewControlsVisible() {
+ return false;
+ }
+
+ @Override
+ public void resizeForPreviewAspectRatio() {
+
+ }
+
+ @Override
+ public void onSwitchSavePath() {
+
+ }
+
+ @Override
+ public void waitingLocationPermissionResult(boolean waiting) {
+
+ }
+
+ @Override
+ public void enableRecordingLocation(boolean enable) {
+
+ }
+
+ @Override
+ public void setPreferenceForTest(String key, String value) {
+
+ }
+
+ @Override
+ public int onZoomChanged(int requestedZoom) {
+ return 0;
+ }
+
+ @Override
+ public void onZoomChanged(float requestedZoom) {
+ }
+
+ @Override
+ public boolean isImageCaptureIntent() {
+ return false;
+ }
+
+ @Override
+ public boolean isCameraIdle() {
+ return true;
+ }
+
+ @Override
+ public void onCaptureDone() {
+
+ }
+
+ @Override
+ public void onCaptureCancelled() {
+
+ }
+
+ @Override
+ public void onCaptureRetake() {
+
+ }
+
+ @Override
+ public void cancelAutoFocus() {
+
+ }
+
+ @Override
+ public void stopPreview() {
+
+ }
+
+ @Override
+ public int getCameraState() {
+ return 0;
+ }
+
+ @Override
+ public void onCountDownFinished() {
+ }
+
+ @Override
+ public void onScreenSizeChanged(int width, int height) {
+
+ }
+
+ @Override
+ public void onPreviewRectChanged(Rect previewRect) {
+
+ }
+
+ @Override
+ public void updateCameraOrientation() {
+ if (mDisplayRotation != CameraUtil.getDisplayRotation(mActivity)) {
+ setDisplayOrientation();
+ }
+ }
+
+ @Override
+ public void onPreviewUIReady() {
+ }
+
+ @Override
+ public void onPreviewUIDestroyed() {
+ }
+
+ @Override
+ public void onShutterButtonClick() {
+ Log.d(TAG, "onShutterButtonClick");
+ mMultiCamera.onShutterButtonClick(mCameraIds);
+ for (String CameraId : mCameraIds) {
+ int id = Integer.parseInt(CameraId);
+ mTakingPicture[id] = true;
+ }
+ }
+
+ @Override
+ public void onShutterButtonLongClick() {
+
+ }
+
+ @Override
+ public void onShutterButtonFocus(boolean pressed) {
+
+ }
+
+ private class SceneModule {
+ CameraMode mode = CameraMode.DEFAULT;
+ public int rearCameraId;
+ public int frontCameraId;
+ public int auxCameraId = 0;
+ int getCurrentId() {
+ return rearCameraId;
+ }
+ }
+
+ /**
+ * This Handler is used to post message back onto the main thread of the
+ * application
+ */
+ private class MainHandler extends Handler {
+ public MainHandler() {
+ super(Looper.getMainLooper());
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case CLEAR_SCREEN_DELAY: {
+ mActivity.getWindow().clearFlags(
+ WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+ break;
+ }
+ }
+ }
+ }
+
+ private void initCameraIds() {
+ CameraManager manager = (CameraManager) mActivity.getSystemService(Context.CAMERA_SERVICE);
+ boolean isFirstDefault = true;
+ String[] cameraIdList = null;
+ try {
+ cameraIdList = manager.getCameraIdList();
+ } catch (CameraAccessException e) {
+ e.printStackTrace();
+ }
+ if (cameraIdList == null || cameraIdList.length == 0) {
+ return;
+ }
+ for (int i = 0; i < cameraIdList.length; i++) {
+ String cameraId = cameraIdList[i];
+ CameraCharacteristics characteristics;
+ try {
+ characteristics = manager.getCameraCharacteristics(cameraId);
+ } catch (CameraAccessException e) {
+ e.printStackTrace();
+ continue;
+ }
+ Set<String> physicalCameraIds = characteristics.getPhysicalCameraIds();
+ for (String camId : physicalCameraIds) {
+ Log.v(TAG, "initCameraIds physicalCameraIds :" + physicalCameraIds);
+ Log.v(TAG, "initCameraIds >>>> camId :" + camId + " cameraId :" + cameraId + ", i :" + i);
+ }
+ }
+ }
+
+ /**
+ * Starts a background thread and its {@link Handler}.
+ */
+ private void startBackgroundThread() {
+ if (mCameraThread == null) {
+ mCameraThread = new HandlerThread("CameraBackground");
+ mCameraThread.start();
+ }
+ if (mCaptureCallbackThread == null) {
+ mCaptureCallbackThread = new HandlerThread("CameraCaptureCallback");
+ mCaptureCallbackThread.start();
+ }
+
+ if (mCameraHandler == null) {
+ mCameraHandler = new MyCameraHandler(mCameraThread.getLooper());
+ }
+ if (mCaptureCallbackHandler == null) {
+ mCaptureCallbackHandler = new Handler(mCaptureCallbackThread.getLooper());
+ }
+ }
+
+ private void stopBackgroundThread() {
+ mCameraThread.quitSafely();
+ try {
+ mCameraThread.join();
+ mCameraThread = null;
+ mCameraHandler = null;
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+
+ mCaptureCallbackThread.quitSafely();
+ try {
+ mCaptureCallbackThread.join();
+ mCaptureCallbackThread = null;
+ mCaptureCallbackHandler = null;
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private class MyCameraHandler extends Handler {
+
+ public MyCameraHandler(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ int id = msg.arg1;
+ switch (msg.what) {
+ case OPEN_CAMERA:
+ if (mMultiCamera != null) {
+ mMultiCamera.openCamera(mCameraIds);
+ }
+ break;
+ }
+ }
+ }
+
+ private void setDisplayOrientation() {
+ mDisplayRotation = CameraUtil.getDisplayRotation(mActivity);
+ mDisplayOrientation = CameraUtil.getDisplayOrientationForCamera2(
+ mDisplayRotation, 0);
+ }
+
+}
diff --git a/src/com/android/camera/multi/MultiCameraUI.java b/src/com/android/camera/multi/MultiCameraUI.java
index df4c54341..8391f8bae 100755..100644
--- a/src/com/android/camera/multi/MultiCameraUI.java
+++ b/src/com/android/camera/multi/MultiCameraUI.java
@@ -1,539 +1,549 @@
-/*
- * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved.
- * Not a Contribution.
- *
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.camera.multi;
-
-import android.content.Intent;
-import android.graphics.Bitmap;
-import android.graphics.drawable.AnimationDrawable;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ImageView;
-import android.widget.TextView;
-import android.view.SurfaceHolder;
-import android.util.Log;
-
-import android.support.v7.widget.LinearLayoutManager;
-import android.support.v7.widget.RecyclerView;
-
-import com.android.camera.CameraActivity;
-import com.android.camera.PauseButton;
-import com.android.camera.PreviewGestures;
-import com.android.camera.data.Camera2ModeAdapter;
-import com.android.camera.ShutterButton;
-import com.android.camera.ui.AutoFitSurfaceView;
-import com.android.camera.ui.CameraControls;
-import com.android.camera.ui.Camera2FaceView;
-import com.android.camera.ui.CountDownView;
-import com.android.camera.ui.FlashToggleButton;
-import com.android.camera.ui.OneUICameraControls;
-import com.android.camera.ui.RenderOverlay;
-import com.android.camera.ui.RotateImageView;
-import com.android.camera.ui.RotateLayout;
-
-import org.codeaurora.snapcam.R;
-
-import java.util.ArrayList;
-
-public class MultiCameraUI implements PreviewGestures.SingleTapListener,
- PauseButton.OnPauseButtonListener {
-
- private static final String TAG = "SnapCam_MultiCameraUI";
-
- private static final int MAX_NUM_CAM = 16;
-
- private static final int PREVIEW_WIDTH = 1024;
- private static final int PREVIEW_HIEGHT = 768;
-
- private CameraActivity mActivity;
- private View mRootView;
- private MultiCameraModule mModule;
- private PreviewGestures mGestures;
-
- /**
- * An {@link AutoFitTextureView} for camera preview.
- */
- private AutoFitSurfaceView mMainPreviewSurface;
- private AutoFitSurfaceView mFirstPreviewSurface;
- private AutoFitSurfaceView mSecondPreviewSurface;
- private AutoFitSurfaceView mPreviewSurface;
- private ArrayList<AutoFitSurfaceView> mSurfaceViewList = new ArrayList();
-
- private SurfaceHolder mMainSurfaceHolder;
- private SurfaceHolder mFirstSurfaceHolder;
- private SurfaceHolder mSecondSurfaceHolder;
-
- private RenderOverlay mRenderOverlay;
- private ShutterButton mShutterButton;
- private PauseButton mPauseButton;
- private RotateImageView mMuteButton;
- private ImageView mVideoButton;
- private ImageView mThumbnail;
- private ImageView mSettingsIcon;
-
- private CountDownView mCountDownView;
- private OneUICameraControls mCameraControls;
- private Camera2FaceView mFaceView;
-
- private TextView mRecordingTimeView;
- private View mTimeLapseLabel;
- private RotateLayout mRecordingTimeRect;
-
- private FlashToggleButton mFlashButton;
- private View mFilterModeSwitcher;
- private View mSceneModeSwitcher;
-
- private int mOrientation;
-
- private RecyclerView mModeSelectLayout;
- private Camera2ModeAdapter mCameraModeAdapter;
-
- private int mPreviewWidths[] = new int[MAX_NUM_CAM];
- private int mPreviewHeights[] = new int[MAX_NUM_CAM];
-
- public MultiCameraUI(CameraActivity activity, final MultiCameraModule module, View parent) {
- mActivity = activity;
- mModule = module;
- mRootView = parent;
- mActivity.getLayoutInflater().inflate(R.layout.multi_camera_module,
- (ViewGroup) mRootView, true);
-
- initPreviewSurface();
- initCameraControls();
- initShutterButton();
- initVideoButton();
- initVideoMuteButton();
- initializeThumbnail();
- hideMenuButton();
- initPauseButton();
- initSettingsMenu();
- initModeSelectLayout();
- }
-
- @Override
- public void onButtonPause() {
- mRecordingTimeView.setCompoundDrawablesWithIntrinsicBounds(
- R.drawable.ic_pausing_indicator, 0, 0, 0);
- mModule.onButtonPause();
- }
-
- @Override
- public void onButtonContinue() {
- mRecordingTimeView.setCompoundDrawablesWithIntrinsicBounds(
- R.drawable.ic_recording_indicator, 0, 0, 0);
- mModule.onButtonContinue();
- }
-
- public void showSurfaceView(int index) {
- Log.d(TAG, "showSurfaceView" + mPreviewWidths[index] + " " + mPreviewHeights[index]);
- mSurfaceViewList.get(index).getHolder().setFixedSize(mPreviewWidths[index], mPreviewHeights[index]);
- mSurfaceViewList.get(index).setAspectRatio(mPreviewHeights[index], mPreviewWidths[index]);
- mSurfaceViewList.get(index).setVisibility(View.VISIBLE);
- }
-
- public boolean setPreviewSize(int index, int width, int height) {
- Log.d(TAG, "setPreviewSize " + width + " " + height);
- boolean changed = (width != mPreviewWidths[index]) || (height != mPreviewHeights[index]);
- mPreviewWidths[index] = width;
- mPreviewHeights[index] = height;
- if (changed) {
- showSurfaceView(index);
- }
- return changed;
- }
-
- private void initPreviewSurface() {
- // Multi camera preview
- mMainPreviewSurface = (AutoFitSurfaceView) mRootView.findViewById(R.id.main_preview_content);
- mFirstPreviewSurface = (AutoFitSurfaceView) mRootView.findViewById(R.id.first_preview_content);
- mSecondPreviewSurface = (AutoFitSurfaceView) mRootView.findViewById(R.id.second_preview_content);
-
- mSurfaceViewList.add(mMainPreviewSurface);
- mSurfaceViewList.add(mFirstPreviewSurface);
- mSurfaceViewList.add(mSecondPreviewSurface);
-
- mMainSurfaceHolder = mMainPreviewSurface.getHolder();
- mMainSurfaceHolder.addCallback(mMainSurfaceHolderCallback);
- mFirstSurfaceHolder = mFirstPreviewSurface.getHolder();
- mFirstSurfaceHolder.addCallback(mFirstHolderCallback);
- mSecondSurfaceHolder = mSecondPreviewSurface.getHolder();
- mSecondSurfaceHolder.addCallback(mSecondHolderCallback);
-
- mMainPreviewSurface.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
- @Override
- public void onLayoutChange(View v, int left, int top, int right,
- int bottom, int oldLeft, int oldTop, int oldRight,
- int oldBottom) {
- int width = right - left;
- int height = bottom - top;
- }
- });
- }
-
- private void initShutterButton() {
- mShutterButton = (ShutterButton) mRootView.findViewById(R.id.shutter_button);
- mShutterButton.setOnShutterButtonListener(mModule);
- mShutterButton.setImageResource(R.drawable.btn_new_shutter);
- }
-
- private void initializeThumbnail() {
- if (mThumbnail == null) {
- mThumbnail = (ImageView) mRootView.findViewById(R.id.preview_thumb);
- }
- mActivity.updateThumbnail(mThumbnail);
- mThumbnail.setVisibility(View.INVISIBLE);
- mThumbnail.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- if (!CameraControls.isAnimating() && !mModule.isTakingPicture() &&
- !mModule.isRecordingVideo()) {
- mActivity.gotoGallery();
- }
- }
- });
- }
-
- private void initModeSelectLayout() {
- mRenderOverlay = (RenderOverlay) mRootView.findViewById(R.id.render_overlay);
- mModeSelectLayout = (RecyclerView) mRootView.findViewById(R.id.mode_select_layout);
- mModeSelectLayout.setLayoutManager(new LinearLayoutManager(mActivity,
- LinearLayoutManager.HORIZONTAL, false));
- mCameraModeAdapter = new Camera2ModeAdapter(mModule.getCameraModeList());
- mCameraModeAdapter.setSelectedPosition(1);
- mCameraModeAdapter.setOnItemClickListener(mModule.getModeItemClickListener());
- mModeSelectLayout.setAdapter(mCameraModeAdapter);
- mModeSelectLayout.setVisibility(View.VISIBLE);
-
- if (mGestures == null) {
- // this will handle gesture disambiguation and dispatching
- mGestures = new PreviewGestures(mActivity, this, null, null, null);
- mRenderOverlay.setGestures(mGestures);
- }
-
- mGestures.setRenderOverlay(mRenderOverlay);
- mRenderOverlay.requestLayout();
- mActivity.setPreviewGestures(mGestures);
- }
-
- private void initCameraControls() {
- mCameraControls = (OneUICameraControls) mRootView.findViewById(R.id.camera_controls);
- mFaceView = (Camera2FaceView) mRootView.findViewById(R.id.face_view);
- mFaceView.initMode();
- }
-
- private void initSettingsMenu() {
- mSettingsIcon = (ImageView) mRootView.findViewById(R.id.settings);
- mSettingsIcon.setImageResource(R.drawable.settings);
- mSettingsIcon.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- openSettingsMenu();
- }
- });
- }
-
- private void initPauseButton() {
- mRecordingTimeView = (TextView) mRootView.findViewById(R.id.recording_time);
- mRecordingTimeRect = (RotateLayout) mRootView.findViewById(R.id.multi_recording_time_rect);
- mTimeLapseLabel = mRootView.findViewById(R.id.time_lapse_label);
-
- mPauseButton = (PauseButton) mRootView.findViewById(R.id.video_pause);
- mPauseButton.setOnPauseButtonListener(this);
- }
-
- private void hideMenuButton() {
- if (mFlashButton == null) {
- mFlashButton = (FlashToggleButton) mRootView.findViewById(R.id.flash_button);
- }
- if (mFilterModeSwitcher == null) {
- mFilterModeSwitcher = mRootView.findViewById(R.id.filter_mode_switcher);
- }
- if (mSceneModeSwitcher == null) {
- mSceneModeSwitcher = mRootView.findViewById(R.id.scene_mode_switcher);
- }
- mFlashButton.setVisibility(View.INVISIBLE);
- mFilterModeSwitcher.setVisibility(View.INVISIBLE);
- mSceneModeSwitcher.setVisibility(View.INVISIBLE);
- }
-
- private void initVideoButton() {
- mVideoButton = (ImageView) mRootView.findViewById(R.id.video_button);
- mVideoButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- cancelCountDown();
- mModule.onVideoButtonClick();
- }
- });
- }
-
- private void initVideoMuteButton() {
- mMuteButton = (RotateImageView)mRootView.findViewById(R.id.mute_button);
- mMuteButton.setVisibility(View.VISIBLE);
- setMuteButtonResource(!mModule.isAudioMute());
- mMuteButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- boolean isEnabled = !mModule.isAudioMute();
- mModule.setMute(isEnabled, true);
- setMuteButtonResource(!isEnabled);
- }
- });
- }
-
- private void initializeCountDown() {
- mActivity.getLayoutInflater().inflate(R.layout.count_down_to_capture,
- (ViewGroup) mRootView, true);
- mCountDownView = (CountDownView) (mRootView.findViewById(R.id.count_down_to_capture));
- mCountDownView.setCountDownFinishedListener((CountDownView.OnCountDownFinishedListener) mModule);
- mCountDownView.bringToFront();
- mCountDownView.setOrientation(mOrientation);
- }
-
- private void setMuteButtonResource(boolean isUnMute) {
- if(isUnMute) {
- mMuteButton.setImageResource(R.drawable.ic_unmuted_button);
- } else {
- mMuteButton.setImageResource(R.drawable.ic_muted_button);
- }
- }
-
- public void setRecordingTime(String text) {
- mRecordingTimeView.setText(text);
- }
-
- public void setRecordingTimeTextColor(int color) {
- mRecordingTimeView.setTextColor(color);
- }
-
- public void resetPauseButton() {
- mRecordingTimeView.setCompoundDrawablesWithIntrinsicBounds(
- R.drawable.ic_recording_indicator, 0, 0, 0);
- mPauseButton.setPaused(false);
- }
-
- public void showRecordingUI(boolean recording) {
- if (recording) {
- mCameraControls.setVideoMode(true);
- mVideoButton.setImageResource(R.drawable.video_stop);
- mPauseButton.setVisibility(View.VISIBLE);
- mRecordingTimeView.setText("00:00");
- mRecordingTimeRect.setVisibility(View.VISIBLE);
- mMuteButton.setVisibility(View.INVISIBLE);
- setMuteButtonResource(!mModule.isAudioMute());
- showTimeLapseUI(false);
- mShutterButton.setVisibility(View.VISIBLE);
- mSettingsIcon.setVisibility(View.INVISIBLE);
- } else {
- //mFlashButton.setVisibility(View.VISIBLE);
- //mFlashButton.init(true);
- mCameraControls.setVideoMode(false);
- mPauseButton.setVisibility(View.INVISIBLE);
- mVideoButton.setImageResource(R.drawable.btn_new_shutter_video);
- mRecordingTimeRect.setVisibility(View.GONE);
- mMuteButton.setVisibility(View.INVISIBLE);
- mShutterButton.setVisibility(View.INVISIBLE);
- mSettingsIcon.setVisibility(View.VISIBLE);
- }
- }
-
- public void showTimeLapseUI(boolean enable) {
- if (mTimeLapseLabel != null) {
- mTimeLapseLabel.setVisibility(enable ? View.VISIBLE : View.GONE);
- }
- }
-
- /**
- * Enables or disables the shutter button.
- */
- public void enableShutter(boolean enabled) {
- if (mShutterButton != null) {
- mShutterButton.setEnabled(enabled);
- }
- }
-
- public void showRelatedIcons(MultiCameraModule.CameraMode mode) {
- //common settings
- mShutterButton.setVisibility(View.VISIBLE);
- //settings for each mode
- switch (mode) {
- case DEFAULT:
- mCameraControls.setVideoMode(false);
- mVideoButton.setVisibility(View.INVISIBLE);
- mMuteButton.setVisibility(View.INVISIBLE);
- mPauseButton.setVisibility(View.INVISIBLE);
- break;
- case VIDEO:
- mVideoButton.setVisibility(View.VISIBLE);
- mShutterButton.setVisibility(View.INVISIBLE);
- break;
- default:
- break;
- }
- }
-
- public void setOrientation(int orientation, boolean animation) {
- mOrientation = orientation;
- mCameraControls.setOrientation(orientation, animation);
- if (mRecordingTimeRect != null) {
- mRecordingTimeView.setRotation(-orientation);
- }
- if (mCountDownView != null)
- mCountDownView.setOrientation(orientation);
-
- }
-
- public int getOrientation() {
- return mOrientation;
- }
-
- public void cancelCountDown() {
- if (mCountDownView == null) return;
- mCountDownView.cancelCountDown();
- }
-
- public void initCountDownView() {
- if (mCountDownView == null) {
- initializeCountDown();
- } else {
- mCountDownView.initSoundPool();
- }
- }
-
- public void onCameraOpened(int cameraId) {
- mGestures.setMultiCameraUI(this);
- }
-
- public void swipeCameraMode(int move) {
- if (!mModule.getCameraModeSwitcherAllowed()) {
- return;
- }
- int index = mModule.getCurrentModeIndex() + move;
- int modeListSize = mModule.getCameraModeList().size();
- if (index >= modeListSize || index == -1) {
- return;
- }
- int mode = index % modeListSize;
- mModule.setCameraModeSwitcherAllowed(false);
- mCameraModeAdapter.setSelectedPosition(mode);
- mModeSelectLayout.smoothScrollToPosition(mode);
- mModule.selectCameraMode(mode);
- }
-
- public boolean isShutterEnabled() {
- return mShutterButton.isEnabled();
- }
-
- public ArrayList<AutoFitSurfaceView> getSurfaceViewList () {
- return mSurfaceViewList;
- }
-
-
- private void openSettingsMenu() {
- Intent intent = new Intent(mActivity, MultiSettingsActivity.class);
- intent.putExtra(MultiSettingsActivity.CAMERA_MODULE, mModule.getCurrenCameraMode());
- intent.putExtra(MultiSettingsActivity.CAMERA_ID_LISTS, mModule.getOpenCameraIdList());
- mActivity.startActivity(intent);
- }
-
- private void previewUIReady() {
- if((mMainSurfaceHolder != null && mMainSurfaceHolder.getSurface().isValid())) {
- mModule.onPreviewUIReady();
- if (mModule.isRecordingVideo() && mThumbnail != null){
- mThumbnail.setVisibility(View.INVISIBLE);
- mThumbnail = null;
- mActivity.updateThumbnail(mThumbnail);
- } else if (!mModule.isRecordingVideo()){
- if (mThumbnail == null)
- mThumbnail = (ImageView) mRootView.findViewById(R.id.preview_thumb);
- mActivity.updateThumbnail(mThumbnail);
- }
- }
- }
-
- private SurfaceHolder.Callback mMainSurfaceHolderCallback = new SurfaceHolder.Callback() {
-
- @Override
- public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
- Log.v(TAG, "surfaceChanged: width =" + width + ", height = " + height);
- }
-
- @Override
- public void surfaceCreated(SurfaceHolder holder) {
- Log.v(TAG, "mMainSurfaceHolderCallback surfaceCreated");
- mMainSurfaceHolder = holder;
- previewUIReady();
- }
-
- @Override
- public void surfaceDestroyed(SurfaceHolder holder) {
- Log.v(TAG, "mMainSurfaceHolderCallback surfaceDestroyed");
- mMainSurfaceHolder = null;
- }
- };
-
- private SurfaceHolder.Callback mFirstHolderCallback = new SurfaceHolder.Callback() {
-
- @Override
- public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
- Log.v(TAG, "mFirstHolderCallback surfaceChanged: w : h =" + width + "x" + height);
- }
-
- @Override
- public void surfaceCreated(SurfaceHolder holder) {
- Log.v(TAG, "mFirstHolderCallback surfaceCreated");
- mFirstSurfaceHolder = holder;
- }
-
- @Override
- public void surfaceDestroyed(SurfaceHolder holder) {
- Log.v(TAG, "mFirstHolderCallback surfaceDestroyed");
- mFirstSurfaceHolder = null;
- }
- };
-
- private SurfaceHolder.Callback mSecondHolderCallback = new SurfaceHolder.Callback() {
-
- @Override
- public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
- Log.v(TAG, "mSecondHolderCallback surfaceChanged: w : h =" + width + "x" + height);
- }
-
- @Override
- public void surfaceCreated(SurfaceHolder holder) {
- Log.v(TAG, "mSecondHolderCallback surfaceCreated");
- mSecondSurfaceHolder = holder;
- }
-
- @Override
- public void surfaceDestroyed(SurfaceHolder holder) {
- Log.v(TAG, "mSecondHolderCallback surfaceDestroyed");
- mSecondSurfaceHolder = null;
- }
- };
-
- @Override
- public void onSingleTapUp(View view, int x, int y) {
- mModule.onSingleTapUp(view, x, y);
- }
-
- @Override
- public void onLongPress(View view, int x, int y) {
- mModule.onLongPress(view, x, y);
- }
+/*
+ * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.camera.multi;
+
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.graphics.drawable.AnimationDrawable;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+import android.view.SurfaceHolder;
+import android.util.Log;
+
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView;
+
+import com.android.camera.CameraActivity;
+import com.android.camera.PauseButton;
+import com.android.camera.PreviewGestures;
+import com.android.camera.data.Camera2ModeAdapter;
+import com.android.camera.ShutterButton;
+import com.android.camera.ui.AutoFitSurfaceView;
+import com.android.camera.ui.CameraControls;
+import com.android.camera.ui.Camera2FaceView;
+import com.android.camera.ui.CountDownView;
+import com.android.camera.ui.FlashToggleButton;
+import com.android.camera.ui.OneUICameraControls;
+import com.android.camera.ui.RenderOverlay;
+import com.android.camera.ui.RotateImageView;
+import com.android.camera.ui.RotateLayout;
+
+import org.codeaurora.snapcam.R;
+
+import java.util.ArrayList;
+
+public class MultiCameraUI implements PreviewGestures.SingleTapListener,
+ PauseButton.OnPauseButtonListener {
+
+ private static final String TAG = "SnapCam_MultiCameraUI";
+
+ private static final int MAX_NUM_CAM = 16;
+
+ private static final int PREVIEW_WIDTH = 1024;
+ private static final int PREVIEW_HIEGHT = 768;
+
+ private CameraActivity mActivity;
+ private View mRootView;
+ private MultiCameraModule mModule;
+ private PreviewGestures mGestures;
+
+ /**
+ * An {@link AutoFitTextureView} for camera preview.
+ */
+ private AutoFitSurfaceView mMainPreviewSurface;
+ private AutoFitSurfaceView mFirstPreviewSurface;
+ private AutoFitSurfaceView mSecondPreviewSurface;
+ private AutoFitSurfaceView mPreviewSurface;
+ private ArrayList<AutoFitSurfaceView> mSurfaceViewList = new ArrayList();
+
+ private SurfaceHolder mMainSurfaceHolder;
+ private SurfaceHolder mFirstSurfaceHolder;
+ private SurfaceHolder mSecondSurfaceHolder;
+
+ private RenderOverlay mRenderOverlay;
+ private ShutterButton mShutterButton;
+ private PauseButton mPauseButton;
+ private RotateImageView mMuteButton;
+ private ImageView mVideoButton;
+ private ImageView mThumbnail;
+ private ImageView mSettingsIcon;
+
+ private CountDownView mCountDownView;
+ private OneUICameraControls mCameraControls;
+ private Camera2FaceView mFaceView;
+
+ private TextView mRecordingTimeView;
+ private View mTimeLapseLabel;
+ private RotateLayout mRecordingTimeRect;
+
+ private FlashToggleButton mFlashButton;
+ private View mFilterModeSwitcher;
+ private View mSceneModeSwitcher;
+
+ private int mOrientation;
+
+ private RecyclerView mModeSelectLayout;
+ private Camera2ModeAdapter mCameraModeAdapter;
+
+ private int mPreviewWidths[] = new int[MAX_NUM_CAM];
+ private int mPreviewHeights[] = new int[MAX_NUM_CAM];
+
+ public MultiCameraUI(CameraActivity activity, final MultiCameraModule module, View parent) {
+ mActivity = activity;
+ mModule = module;
+ mRootView = parent;
+ mActivity.getLayoutInflater().inflate(R.layout.multi_camera_module,
+ (ViewGroup) mRootView, true);
+
+ initPreviewSurface();
+ initCameraControls();
+ initShutterButton();
+ initVideoButton();
+ initVideoMuteButton();
+ initFlashButton();
+ initializeThumbnail();
+ hideMenuButton();
+ initPauseButton();
+ initSettingsMenu();
+ initModeSelectLayout();
+ }
+
+ @Override
+ public void onButtonPause() {
+ mRecordingTimeView.setCompoundDrawablesWithIntrinsicBounds(
+ R.drawable.ic_pausing_indicator, 0, 0, 0);
+ mModule.onButtonPause();
+ }
+
+ @Override
+ public void onButtonContinue() {
+ mRecordingTimeView.setCompoundDrawablesWithIntrinsicBounds(
+ R.drawable.ic_recording_indicator, 0, 0, 0);
+ mModule.onButtonContinue();
+ }
+
+ public void showSurfaceView(int index) {
+ Log.d(TAG, "showSurfaceView" + mPreviewWidths[index] + " " + mPreviewHeights[index]);
+ mSurfaceViewList.get(index).getHolder().setFixedSize(mPreviewWidths[index], mPreviewHeights[index]);
+ mSurfaceViewList.get(index).setAspectRatio(mPreviewHeights[index], mPreviewWidths[index]);
+ mSurfaceViewList.get(index).setVisibility(View.VISIBLE);
+ }
+
+ public boolean setPreviewSize(int index, int width, int height) {
+ Log.d(TAG, "setPreviewSize " + width + " " + height);
+ boolean changed = (width != mPreviewWidths[index]) || (height != mPreviewHeights[index]);
+ mPreviewWidths[index] = width;
+ mPreviewHeights[index] = height;
+ if (changed) {
+ showSurfaceView(index);
+ }
+ return changed;
+ }
+
+ private void initPreviewSurface() {
+ // Multi camera preview
+ mMainPreviewSurface = (AutoFitSurfaceView) mRootView.findViewById(R.id.main_preview_content);
+ mFirstPreviewSurface = (AutoFitSurfaceView) mRootView.findViewById(R.id.first_preview_content);
+ mSecondPreviewSurface = (AutoFitSurfaceView) mRootView.findViewById(R.id.second_preview_content);
+
+ mSurfaceViewList.add(mMainPreviewSurface);
+ mSurfaceViewList.add(mFirstPreviewSurface);
+ mSurfaceViewList.add(mSecondPreviewSurface);
+
+ mMainSurfaceHolder = mMainPreviewSurface.getHolder();
+ mMainSurfaceHolder.addCallback(mMainSurfaceHolderCallback);
+ mFirstSurfaceHolder = mFirstPreviewSurface.getHolder();
+ mFirstSurfaceHolder.addCallback(mFirstHolderCallback);
+ mSecondSurfaceHolder = mSecondPreviewSurface.getHolder();
+ mSecondSurfaceHolder.addCallback(mSecondHolderCallback);
+
+ mMainPreviewSurface.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
+ @Override
+ public void onLayoutChange(View v, int left, int top, int right,
+ int bottom, int oldLeft, int oldTop, int oldRight,
+ int oldBottom) {
+ int width = right - left;
+ int height = bottom - top;
+ }
+ });
+ }
+
+ private void initShutterButton() {
+ mShutterButton = (ShutterButton) mRootView.findViewById(R.id.shutter_button);
+ mShutterButton.setOnShutterButtonListener(mModule);
+ mShutterButton.setImageResource(R.drawable.btn_new_shutter);
+ }
+
+ private void initializeThumbnail() {
+ if (mThumbnail == null) {
+ mThumbnail = (ImageView) mRootView.findViewById(R.id.preview_thumb);
+ }
+ mActivity.updateThumbnail(mThumbnail);
+ mThumbnail.setVisibility(View.INVISIBLE);
+ mThumbnail.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (!CameraControls.isAnimating() && !mModule.isTakingPicture() &&
+ !mModule.isRecordingVideo()) {
+ mActivity.gotoGallery();
+ }
+ }
+ });
+ }
+
+ private void initModeSelectLayout() {
+ mRenderOverlay = (RenderOverlay) mRootView.findViewById(R.id.render_overlay);
+ mModeSelectLayout = (RecyclerView) mRootView.findViewById(R.id.mode_select_layout);
+ mModeSelectLayout.setLayoutManager(new LinearLayoutManager(mActivity,
+ LinearLayoutManager.HORIZONTAL, false));
+ mCameraModeAdapter = new Camera2ModeAdapter(mModule.getCameraModeList(),
+ mModule.getCameraModeIconList());
+ mCameraModeAdapter.setSelectedPosition(1);
+ mCameraModeAdapter.setOnItemClickListener(mModule.getModeItemClickListener());
+ mModeSelectLayout.setAdapter(mCameraModeAdapter);
+ mModeSelectLayout.setVisibility(View.INVISIBLE);
+
+ if (mGestures == null) {
+ // this will handle gesture disambiguation and dispatching
+ mGestures = new PreviewGestures(mActivity, this, null, null, null);
+ mRenderOverlay.setGestures(mGestures);
+ }
+
+ mGestures.setRenderOverlay(mRenderOverlay);
+ mRenderOverlay.requestLayout();
+ mActivity.setPreviewGestures(mGestures);
+ }
+
+ private void initCameraControls() {
+ mCameraControls = (OneUICameraControls) mRootView.findViewById(R.id.camera_controls);
+ mFaceView = (Camera2FaceView) mRootView.findViewById(R.id.face_view);
+ mFaceView.initMode();
+ }
+
+ private void initSettingsMenu() {
+ mSettingsIcon = (ImageView) mRootView.findViewById(R.id.settings);
+ mSettingsIcon.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ openSettingsMenu();
+ }
+ });
+ }
+
+ private void initPauseButton() {
+ mRecordingTimeView = (TextView) mRootView.findViewById(R.id.recording_time);
+ mRecordingTimeRect = (RotateLayout) mRootView.findViewById(R.id.multi_recording_time_rect);
+ mTimeLapseLabel = mRootView.findViewById(R.id.time_lapse_label);
+
+ mPauseButton = (PauseButton) mRootView.findViewById(R.id.video_pause);
+ mPauseButton.setOnPauseButtonListener(this);
+ }
+
+ private void initFlashButton() {
+ if (mFlashButton == null) {
+ mFlashButton = (FlashToggleButton) mRootView.findViewById(R.id.flash_button);
+ }
+ mFlashButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ mFlashButton.handleClick();
+ }
+ });
+ }
+
+ private void hideMenuButton() {
+ if (mFilterModeSwitcher == null) {
+ mFilterModeSwitcher = mRootView.findViewById(R.id.filter_mode_switcher);
+ }
+ if (mSceneModeSwitcher == null) {
+ mSceneModeSwitcher = mRootView.findViewById(R.id.scene_mode_switcher);
+ }
+ mFlashButton.setVisibility(View.INVISIBLE);
+ mFilterModeSwitcher.setVisibility(View.INVISIBLE);
+ mSceneModeSwitcher.setVisibility(View.INVISIBLE);
+ }
+
+ private void initVideoButton() {
+ mVideoButton = (ImageView) mRootView.findViewById(R.id.video_button);
+ mVideoButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ cancelCountDown();
+ mModule.onVideoButtonClick();
+ }
+ });
+ }
+
+ private void initVideoMuteButton() {
+ mMuteButton = (RotateImageView)mRootView.findViewById(R.id.mute_button);
+ mMuteButton.setVisibility(View.VISIBLE);
+ setMuteButtonResource(!mModule.isAudioMute());
+ mMuteButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ boolean isEnabled = !mModule.isAudioMute();
+ mModule.setMute(isEnabled, true);
+ setMuteButtonResource(!isEnabled);
+ }
+ });
+ }
+
+ private void initializeCountDown() {
+ mActivity.getLayoutInflater().inflate(R.layout.count_down_to_capture,
+ (ViewGroup) mRootView, true);
+ mCountDownView = (CountDownView) (mRootView.findViewById(R.id.count_down_to_capture));
+ mCountDownView.setCountDownFinishedListener((CountDownView.OnCountDownFinishedListener) mModule);
+ mCountDownView.bringToFront();
+ mCountDownView.setOrientation(mOrientation);
+ }
+
+ private void setMuteButtonResource(boolean isUnMute) {
+ if(isUnMute) {
+ mMuteButton.setImageResource(R.drawable.ic_unmuted_button);
+ } else {
+ mMuteButton.setImageResource(R.drawable.ic_muted_button);
+ }
+ }
+
+ public void setRecordingTime(String text) {
+ mRecordingTimeView.setText(text);
+ }
+
+ public void setRecordingTimeTextColor(int color) {
+ mRecordingTimeView.setTextColor(color);
+ }
+
+ public void resetPauseButton() {
+ mRecordingTimeView.setCompoundDrawablesWithIntrinsicBounds(
+ R.drawable.ic_recording_indicator, 0, 0, 0);
+ mPauseButton.setPaused(false);
+ }
+
+ public void showRecordingUI(boolean recording) {
+ if (recording) {
+ mCameraControls.setVideoMode(true);
+ mVideoButton.setImageResource(R.drawable.shutter_button_video_stop);
+ mPauseButton.setVisibility(View.VISIBLE);
+ mRecordingTimeView.setText("00:00");
+ mRecordingTimeRect.setVisibility(View.VISIBLE);
+ mMuteButton.setVisibility(View.INVISIBLE);
+ setMuteButtonResource(!mModule.isAudioMute());
+ showTimeLapseUI(false);
+ mShutterButton.setVisibility(View.VISIBLE);
+ mSettingsIcon.setVisibility(View.INVISIBLE);
+ } else {
+ //mFlashButton.setVisibility(View.VISIBLE);
+ //mFlashButton.init(true);
+ mCameraControls.setVideoMode(false);
+ mPauseButton.setVisibility(View.INVISIBLE);
+ mVideoButton.setImageResource(R.drawable.btn_new_shutter_video);
+ mRecordingTimeRect.setVisibility(View.GONE);
+ mMuteButton.setVisibility(View.INVISIBLE);
+ mShutterButton.setVisibility(View.INVISIBLE);
+ mSettingsIcon.setVisibility(View.VISIBLE);
+ }
+ }
+
+ public void showTimeLapseUI(boolean enable) {
+ if (mTimeLapseLabel != null) {
+ mTimeLapseLabel.setVisibility(enable ? View.VISIBLE : View.GONE);
+ }
+ }
+
+ /**
+ * Enables or disables the shutter button.
+ */
+ public void enableShutter(boolean enabled) {
+ if (mShutterButton != null) {
+ mShutterButton.setEnabled(enabled);
+ }
+ }
+
+ public void showRelatedIcons(MultiCameraModule.CameraMode mode) {
+ //common settings
+ mShutterButton.setVisibility(View.VISIBLE);
+ //settings for each mode
+ switch (mode) {
+ case DEFAULT:
+ mCameraControls.setVideoMode(false);
+ mVideoButton.setVisibility(View.INVISIBLE);
+ mMuteButton.setVisibility(View.INVISIBLE);
+ mPauseButton.setVisibility(View.INVISIBLE);
+ break;
+ case VIDEO:
+ mVideoButton.setVisibility(View.VISIBLE);
+ mShutterButton.setVisibility(View.INVISIBLE);
+ break;
+ default:
+ break;
+ }
+ }
+
+ public void setOrientation(int orientation, boolean animation) {
+ mOrientation = orientation;
+ mCameraControls.setOrientation(orientation, animation);
+ if (mRecordingTimeRect != null) {
+ mRecordingTimeView.setRotation(-orientation);
+ }
+ if (mCountDownView != null)
+ mCountDownView.setOrientation(orientation);
+
+ }
+
+ public int getOrientation() {
+ return mOrientation;
+ }
+
+ public void cancelCountDown() {
+ if (mCountDownView == null) return;
+ mCountDownView.cancelCountDown();
+ }
+
+ public void initCountDownView() {
+ if (mCountDownView == null) {
+ initializeCountDown();
+ } else {
+ mCountDownView.initSoundPool();
+ }
+ }
+
+ public void onCameraOpened(int cameraId) {
+ mGestures.setMultiCameraUI(this);
+ }
+
+ public void swipeCameraMode(int move) {
+ if (!mModule.getCameraModeSwitcherAllowed()) {
+ return;
+ }
+ int index = mModule.getCurrentModeIndex() + move;
+ int modeListSize = mModule.getCameraModeList().size();
+ if (index >= modeListSize || index == -1) {
+ return;
+ }
+ int mode = index % modeListSize;
+ mModule.setCameraModeSwitcherAllowed(false);
+ mCameraModeAdapter.setSelectedPosition(mode);
+ mModeSelectLayout.smoothScrollToPosition(mode);
+ mModule.selectCameraMode(mode);
+ }
+
+ public boolean isShutterEnabled() {
+ return mShutterButton.isEnabled();
+ }
+
+ public ArrayList<AutoFitSurfaceView> getSurfaceViewList () {
+ return mSurfaceViewList;
+ }
+
+
+ private void openSettingsMenu() {
+ Intent intent = new Intent(mActivity, MultiSettingsActivity.class);
+ intent.putExtra(MultiSettingsActivity.CAMERA_MODULE, mModule.getCurrenCameraMode());
+ intent.putExtra(MultiSettingsActivity.CAMERA_ID_LISTS, mModule.getOpenCameraIdList());
+ mActivity.startActivity(intent);
+ }
+
+ private void previewUIReady() {
+ if((mMainSurfaceHolder != null && mMainSurfaceHolder.getSurface().isValid())) {
+ mModule.onPreviewUIReady();
+ if (mModule.isRecordingVideo() && mThumbnail != null){
+ mThumbnail.setVisibility(View.INVISIBLE);
+ mThumbnail = null;
+ mActivity.updateThumbnail(mThumbnail);
+ } else if (!mModule.isRecordingVideo()){
+ if (mThumbnail == null)
+ mThumbnail = (ImageView) mRootView.findViewById(R.id.preview_thumb);
+ mActivity.updateThumbnail(mThumbnail);
+ }
+ }
+ }
+
+ private SurfaceHolder.Callback mMainSurfaceHolderCallback = new SurfaceHolder.Callback() {
+
+ @Override
+ public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
+ Log.v(TAG, "surfaceChanged: width =" + width + ", height = " + height);
+ }
+
+ @Override
+ public void surfaceCreated(SurfaceHolder holder) {
+ Log.v(TAG, "mMainSurfaceHolderCallback surfaceCreated");
+ mMainSurfaceHolder = holder;
+ previewUIReady();
+ }
+
+ @Override
+ public void surfaceDestroyed(SurfaceHolder holder) {
+ Log.v(TAG, "mMainSurfaceHolderCallback surfaceDestroyed");
+ mMainSurfaceHolder = null;
+ }
+ };
+
+ private SurfaceHolder.Callback mFirstHolderCallback = new SurfaceHolder.Callback() {
+
+ @Override
+ public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
+ Log.v(TAG, "mFirstHolderCallback surfaceChanged: w : h =" + width + "x" + height);
+ }
+
+ @Override
+ public void surfaceCreated(SurfaceHolder holder) {
+ Log.v(TAG, "mFirstHolderCallback surfaceCreated");
+ mFirstSurfaceHolder = holder;
+ }
+
+ @Override
+ public void surfaceDestroyed(SurfaceHolder holder) {
+ Log.v(TAG, "mFirstHolderCallback surfaceDestroyed");
+ mFirstSurfaceHolder = null;
+ }
+ };
+
+ private SurfaceHolder.Callback mSecondHolderCallback = new SurfaceHolder.Callback() {
+
+ @Override
+ public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
+ Log.v(TAG, "mSecondHolderCallback surfaceChanged: w : h =" + width + "x" + height);
+ }
+
+ @Override
+ public void surfaceCreated(SurfaceHolder holder) {
+ Log.v(TAG, "mSecondHolderCallback surfaceCreated");
+ mSecondSurfaceHolder = holder;
+ }
+
+ @Override
+ public void surfaceDestroyed(SurfaceHolder holder) {
+ Log.v(TAG, "mSecondHolderCallback surfaceDestroyed");
+ mSecondSurfaceHolder = null;
+ }
+ };
+
+ @Override
+ public void onSingleTapUp(View view, int x, int y) {
+ mModule.onSingleTapUp(view, x, y);
+ }
+
+ @Override
+ public void onLongPress(View view, int x, int y) {
+ mModule.onLongPress(view, x, y);
+ }
}
diff --git a/src/com/android/camera/multi/MultiCaptureModule.java b/src/com/android/camera/multi/MultiCaptureModule.java
index cf629daa1..34065150f 100755..100644
--- a/src/com/android/camera/multi/MultiCaptureModule.java
+++ b/src/com/android/camera/multi/MultiCaptureModule.java
@@ -1,824 +1,824 @@
-/*
- * Copyright (c) 2019 The Linux Foundation. All rights reserved.
- * Not a Contribution.
- *
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.camera.multi;
-
-import android.content.Context;
-import android.content.ContentResolver;
-import android.content.SharedPreferences;
-import android.graphics.ImageFormat;
-import android.graphics.Point;
-import android.hardware.camera2.CameraDevice;
-import android.hardware.camera2.CameraManager;
-import android.hardware.camera2.CameraAccessException;
-import android.hardware.camera2.CameraCaptureSession;
-import android.hardware.camera2.CameraCharacteristics;
-import android.hardware.camera2.CaptureFailure;
-import android.hardware.camera2.CaptureRequest;
-import android.hardware.camera2.CaptureResult;
-import android.hardware.camera2.TotalCaptureResult;
-import android.hardware.camera2.params.OutputConfiguration;
-import android.hardware.camera2.params.SessionConfiguration;
-import android.hardware.camera2.params.StreamConfigurationMap;
-import android.media.CameraProfile;
-import android.media.Image;
-import android.media.ImageReader;
-import android.net.Uri;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.Looper;
-import android.os.Message;
-import android.util.Log;
-import android.util.Size;
-import android.view.Surface;
-import android.view.SurfaceHolder;
-import android.widget.Toast;
-
-import java.nio.ByteBuffer;
-import java.util.concurrent.Executor;
-import java.util.concurrent.Semaphore;
-import java.util.concurrent.TimeUnit;
-import java.util.Arrays;
-import java.util.ArrayList;
-import java.util.List;
-
-import com.android.camera.CameraActivity;
-import com.android.camera.CaptureModule;
-import com.android.camera.ComboPreferences;
-import com.android.camera.MediaSaveService;
-import com.android.camera.Exif;
-import com.android.camera.SoundClips;
-import com.android.camera.exif.ExifInterface;
-import com.android.camera.PhotoModule.NamedImages;
-import com.android.camera.PhotoModule.NamedImages.NamedEntity;
-import com.android.camera.util.CameraUtil;
-import com.android.camera.util.PersistUtil;
-import org.codeaurora.snapcam.R;
-
-public class MultiCaptureModule implements MultiCamera {
-
- private static final String TAG = "SnapCam_MultiCaptureModule";
-
- private static final boolean DEBUG =
- (PersistUtil.getCamera2Debug() == PersistUtil.CAMERA2_DEBUG_DUMP_LOG) ||
- (PersistUtil.getCamera2Debug() == PersistUtil.CAMERA2_DEBUG_DUMP_ALL);
-
- private static final int WAIT_SURFACE = 0;
- private static final int OPEN_CAMERA = 1;
-
- private int mCameraListIndex = 0;
-
- private static final int MAX_NUM_CAM = 16;
-
- private CameraActivity mActivity;
- private MultiCameraUI mMultiCameraUI;
- private MultiCameraModule mMultiCameraModule;
- private CameraDevice[] mCameraDevices = new CameraDevice[MAX_NUM_CAM];
- private SharedPreferences mLocalSharedPref;
- private ArrayList<CameraCharacteristics> mCharacteristics;
-
- private ArrayList<String> mCameraIDList = new ArrayList<>();
- private CameraCaptureSession[] mCameraCaptureSessions = new CameraCaptureSession[MAX_NUM_CAM];
- private ImageReader[] mImageReaders = new ImageReader[MAX_NUM_CAM];
-
- private Size mPreviewSizes[] = new Size[MAX_NUM_CAM];
- private Size mPictureSizes[] = new Size[MAX_NUM_CAM];
- private int[][] mMaxPreviewSize = new int[MAX_NUM_CAM][];
-
- private Handler mCameraHandler;
- private HandlerThread mCameraThread;
-
- private static final CaptureRequest.Key<Byte> override_resource_cost_validation =
- new CaptureRequest.Key<>(
- "org.codeaurora.qcamera3.sessionParameters.overrideResourceCostValidation",
- byte.class);
-
- /**
- * {@link CaptureRequest.Builder} for the camera preview
- */
- private CaptureRequest.Builder[] mPreviewRequestBuilders = new CaptureRequest.Builder[MAX_NUM_CAM];
- /**
- * {@link CaptureRequest} generated by {@link #mPreviewRequestBuilder}
- */
- private CaptureRequest mPreviewRequest;
- /**
- * A {@link Semaphore} make sure the camera open callback happens first before closing the
- * camera.
- */
- private Semaphore mCameraOpenCloseLock = new Semaphore(3);
-
- /**
- * Orientation of the camera sensor
- */
- private int mSensorOrientation;
-
- private long mCaptureStartTime;
- private NamedImages mNamedImages;
- private ContentResolver mContentResolver;
- private SoundClips.Player mSoundPlayer;
-
- public MultiCaptureModule(CameraActivity activity, MultiCameraUI ui, MultiCameraModule module) {
- mActivity = activity;
- mMultiCameraUI = ui;
- mMultiCameraModule = module;
- mContentResolver = mActivity.getContentResolver();
- mNamedImages = new NamedImages();
- mLocalSharedPref = mActivity.getSharedPreferences(
- ComboPreferences.getLocalSharedPreferencesName(mActivity,
- "multi" + mMultiCameraModule.getCurrenCameraMode()), Context.MODE_PRIVATE);
- initCameraCharacteristics();
- startBackgroundThread();
- }
-
- @Override
- public void onResume(String[] ids) {
- for (String id : ids) {
- mCameraIDList.add(id);
- }
- // Set up sound playback for shutter button, video record and video stop
- if (mSoundPlayer == null) {
- mSoundPlayer = SoundClips.getPlayer(mActivity);
- }
- startBackgroundThread();
- initCameraCharacteristics();
- for (String id : ids) {
- int cameraId = Integer.parseInt(id);
- updatePictureSize(cameraId);
- int index = mCameraIDList.indexOf(id);
- mMultiCameraUI.setPreviewSize(index, mPreviewSizes[cameraId].getWidth(),
- mPreviewSizes[cameraId].getHeight());
- }
- }
-
- @Override
- public void onPause() {
- if (mSoundPlayer != null) {
- mSoundPlayer.release();
- mSoundPlayer = null;
- }
- closeCamera();
- if (mCameraIDList != null) {
- mCameraIDList.clear();
- }
- mCameraListIndex = 0;
- stopBackgroundThread();
- }
-
- @Override
- public boolean openCamera(String[] ids) {
- Message msg = Message.obtain();
- msg.what = OPEN_CAMERA;
- if (mCameraHandler != null) {
- mCameraHandler.sendMessage(msg);
- }
- return true;
- }
-
- @Override
- public void startPreview() {
-
- }
-
- @Override
- public void closeSession() {
-
- }
-
- @Override
- public void closeCamera() {
- Log.d(TAG, "closeCamera");
- /* no need to set this in the callback and handle asynchronously. This is the same
- reason as why we release the semaphore here, not in camera close callback function
- as we don't have to protect the case where camera open() gets called during camera
- close(). The low level framework/HAL handles the synchronization for open()
- happens after close() */
- try {
- // Close camera starting with AUX first
- for (int i = MAX_NUM_CAM - 1; i >= 0; i--) {
- if (null != mCameraDevices[i]) {
- if (!mCameraOpenCloseLock.tryAcquire(2000, TimeUnit.MILLISECONDS)) {
- Log.d(TAG, "Time out waiting to lock camera closing.");
- throw new RuntimeException("Time out waiting to lock camera closing");
- }
- Log.d(TAG, "Closing camera: " + mCameraDevices[i].getId());
- mCameraDevices[i].close();
- mCameraDevices[i] = null;
- mCameraCaptureSessions[i] = null;
- }
- if (null != mImageReaders[i]) {
- mImageReaders[i].close();
- mImageReaders[i] = null;
- }
- }
- } catch (InterruptedException e) {
- mCameraOpenCloseLock.release();
- throw new RuntimeException("Interrupted while trying to lock camera closing.", e);
- } catch (IllegalStateException e) {
- e.printStackTrace();
- } finally {
- mCameraOpenCloseLock.release();
- }
- }
-
- private void openCameraInSequence(String id) {
- CameraManager manager = (CameraManager) mActivity.getSystemService(Context.CAMERA_SERVICE);
- CameraCharacteristics characteristics = null;
- try {
- characteristics = manager.getCameraCharacteristics(id);
- } catch (CameraAccessException e) {
- e.printStackTrace();
- }
- mSensorOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
- Log.d(TAG, "openCameraInSequence " + id + ", mSensorOrientation :" + mSensorOrientation);
- try {
- if (!mCameraOpenCloseLock.tryAcquire(5000, TimeUnit.MILLISECONDS)) {
- Log.d(TAG, "Time out waiting to lock camera opening.");
- throw new RuntimeException("Time out waiting to lock camera opening");
- }
- manager.openCamera(id, mStateCallback, mMultiCameraModule.getMyCameraHandler());
- } catch (CameraAccessException e) {
- e.printStackTrace();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- manager = null;
- characteristics = null;
- }
-
- private void startBackgroundThread() {
- if (mCameraThread == null) {
- mCameraThread = new HandlerThread("CameraBackground");
- mCameraThread.start();
- }
- if (mCameraHandler == null) {
- mCameraHandler = new MyCameraHandler(mCameraThread.getLooper());
- }
- }
-
- private void stopBackgroundThread() {
- mCameraThread.quitSafely();
- try {
- mCameraThread.join();
- mCameraThread = null;
- mCameraHandler = null;
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
-
- private Size[] getSupportedOutputSize(int cameraId, Class cl) {
- StreamConfigurationMap map = mCharacteristics.get(cameraId).get(
- CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
- Size[] normal = map.getOutputSizes(cl);
- Size[] high = map.getHighResolutionOutputSizes(ImageFormat.PRIVATE);
- Size[] ret = new Size[normal.length + high.length];
- System.arraycopy(normal, 0, ret, 0, normal.length);
- System.arraycopy(high, 0, ret, normal.length, high.length);
- return ret;
- }
-
- private Size getOptimalPreviewSize(int id, Size pictureSize, Size[] prevSizes) {
- Point[] points = new Point[prevSizes.length];
-
- double targetRatio = (double) pictureSize.getWidth() / pictureSize.getHeight();
- int index = 0;
- int point_max[] = mMaxPreviewSize[id];
- int max_size = -1;
- if (point_max != null){
- max_size = point_max[0] * point_max[1];
- }
- for (Size s : prevSizes) {
- if (max_size != -1){
- int size = s.getWidth() * s.getHeight();
- if (s.getWidth() == s.getHeight()){
- if (s.getWidth() > Math.max(point_max[0],point_max[1]))
- continue;
- } else if (size > max_size || size == 0) {
- continue;
- }
- }
- points[index++] = new Point(s.getWidth(), s.getHeight());
- }
-
- int optimalPickIndex = CameraUtil.getOptimalPreviewSize(mActivity, points, targetRatio);
- return (optimalPickIndex == -1) ? null :
- new Size(points[optimalPickIndex].x,points[optimalPickIndex].y);
- }
-
- private class MyCameraHandler extends Handler {
-
- public MyCameraHandler(Looper looper) {
- super(looper);
- }
-
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case WAIT_SURFACE:
- int id = msg.arg1;
- int index = mCameraIDList.indexOf(String.valueOf(id));
- Log.v(TAG, "WAIT_SURFACE id :" + id + ", index :" + index);
- if (index == -1) {
- break;
- }
- Surface surface = mMultiCameraUI.getSurfaceViewList().get(index)
- .getHolder().getSurface();
- if (surface.isValid()) {
- createCaptureSessions(id, surface);
- } else {
- mCameraHandler.sendMessageDelayed(msg, 200);
- Log.v(TAG, "Surface is invalid, wait more 200ms surfaceCreated");
- }
- break;
- case OPEN_CAMERA:
- if (mCameraListIndex == mCameraIDList.size()) {
- mCameraListIndex = 0;
- } else {
- String cameraId = mCameraIDList.get(mCameraListIndex);
- openCameraInSequence(cameraId);
- mCameraListIndex ++;
- Log.v(TAG, " OPEN_CAMERA cameraId :" + cameraId + ", mCameraListIndex :"
- + mCameraListIndex);
- }
- break;
- }
- }
- }
-
- private final CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {
-
- @Override
- public void onOpened(CameraDevice cameraDevice) {
- final int id = Integer.parseInt(cameraDevice.getId());
- mCameraDevices[id] = cameraDevice;
- Log.d(TAG, "onOpened " + id);
- mCameraOpenCloseLock.release();
- //updatePictureSize(id);
- createCameraPreviewSession(id);
- mActivity.runOnUiThread(new Runnable() {
- @Override
- public void run() {
- mMultiCameraUI.onCameraOpened(id);
- }
- });
- }
-
- @Override
- public void onDisconnected(CameraDevice cameraDevice) {
- int id = Integer.parseInt(cameraDevice.getId());
- Log.d(TAG, "onDisconnected " + id);
- mCameraOpenCloseLock.release();
- mCameraDevices[id] = null;
- }
-
- @Override
- public void onError(CameraDevice cameraDevice, int error) {
- int id = Integer.parseInt(cameraDevice.getId());
- Log.e(TAG, "onError " + id + " " + error);
- mCameraOpenCloseLock.release();
-
- if (null != mActivity) {
- Toast.makeText(mActivity,"open camera error id =" + id,
- Toast.LENGTH_LONG).show();
- mActivity.finish();
- }
- }
-
- @Override
- public void onClosed(CameraDevice cameraDevice) {
- int id = Integer.parseInt(cameraDevice.getId());
- Log.d(TAG, "onClosed " + id);
- mCameraOpenCloseLock.release();
- mCameraDevices[id] = null;
- }
- };
-
- /**
- * Creates a new {@link CameraCaptureSession} for camera preview.
- */
- private void createCameraPreviewSession(int id) {
- // This is the output Surface we need to start preview.
- int index = mCameraIDList.indexOf(String.valueOf(id));
- Log.v(TAG, "createCameraPreviewSession id :" + id + ", index :" + index);
- Surface surface = mMultiCameraUI.getSurfaceViewList().get(index).getHolder().getSurface();
- if (surface.isValid()) {
- createCaptureSessions(id, surface);
- } else {
- Message msg = Message.obtain();
- msg.what = WAIT_SURFACE;
- msg.arg1 = id;
- mCameraHandler.sendMessageDelayed(msg, 200);
- Log.v(TAG, "Surface is invalid, wait 200ms surfaceCreated");
- }
- }
-
- private void createCaptureSessions(final int id, Surface surface) {
- try {
- // We set up a CaptureRequest.Builder with the output Surface.
- mPreviewRequestBuilders[id]
- = mCameraDevices[id].createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
- mPreviewRequestBuilders[id].addTarget(surface);
- mPreviewRequestBuilders[id].setTag(id);
- CameraCaptureSession.StateCallback stateCallback =
- new CameraCaptureSession.StateCallback() {
- @Override
- public void onConfigured(CameraCaptureSession cameraCaptureSession) {
- // The camera is already closed
- if (null == mCameraDevices[id]) {
- return;
- }
- Log.v(TAG, " CameraCaptureSession onConfigured id :" + id);
- // When the session is ready, we start displaying the preview.
- mCameraCaptureSessions[id] = cameraCaptureSession;
- try {
- // Auto focus should be continuous for camera preview.
- mPreviewRequestBuilders[id].set(CaptureRequest.CONTROL_AF_MODE,
- CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
- // Finally, we start displaying the camera preview.
- mCameraCaptureSessions[id].setRepeatingRequest(
- mPreviewRequestBuilders[id].build(),
- mCaptureCallback, mMultiCameraModule.getMyCameraHandler());
- } catch (CameraAccessException e) {
- e.printStackTrace();
- }
-
- Message msg = Message.obtain();
- msg.what = OPEN_CAMERA;
- if (mCameraHandler != null) {
- mCameraHandler.sendMessage(msg);
- }
- }
-
- @Override
- public void onConfigureFailed(CameraCaptureSession cameraCaptureSession) {
- showToast("onConfigureFailed");
- }
- };
-
- try {
- final byte enable = 1;
- mPreviewRequestBuilders[id].set(override_resource_cost_validation, enable);
- Log.v(TAG, " set" + override_resource_cost_validation + " is 1");
- } catch (IllegalArgumentException e) {
- e.printStackTrace();
- }
-
- List<OutputConfiguration> outConfigurations = new ArrayList<>(2);
- outConfigurations.add(new OutputConfiguration(surface));
- outConfigurations.add(new OutputConfiguration(mImageReaders[id].getSurface()));
-
- SessionConfiguration sessionConfiguration = new SessionConfiguration(
- SessionConfiguration.SESSION_REGULAR, outConfigurations,
- new HandlerExecutor(mCameraHandler), stateCallback);
- sessionConfiguration.setSessionParameters(mPreviewRequestBuilders[id].build());
- mCameraDevices[id].createCaptureSession(sessionConfiguration);
- try {
- CaptureRequest captureRequest = sessionConfiguration.getSessionParameters();
- Log.v(TAG, " override_resource_cost_validation result: " +
- captureRequest.get(override_resource_cost_validation));
- } catch (IllegalArgumentException e) {
- e.printStackTrace();
- }
- } catch (CameraAccessException e) {
- e.printStackTrace();
- }
- }
-
- private class HandlerExecutor implements Executor {
- private final Handler ihandler;
-
- public HandlerExecutor(Handler handler) {
- ihandler = handler;
- }
-
- @Override
- public void execute(Runnable runCmd) {
- ihandler.post(runCmd);
- }
- }
-
- /**
- * A {@link CameraCaptureSession.CaptureCallback} that handles events related to JPEG capture.
- */
- private CameraCaptureSession.CaptureCallback mCaptureCallback
- = new CameraCaptureSession.CaptureCallback() {
-
- private void process(CaptureResult result) {
- Integer afState = result.get(CaptureResult.CONTROL_AF_STATE);
- Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);
- if (DEBUG) {
- Log.v(TAG, "process afState :" + afState + ", aeState :" + aeState);
- }
- }
-
- @Override
- public void onCaptureProgressed(CameraCaptureSession session, CaptureRequest request,
- CaptureResult partialResult) {
- process(partialResult);
- }
-
- @Override
- public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request,
- TotalCaptureResult result) {
- process(result);
- }
-
- };
-
- private void updatePictureSize(int id) {
- String defaultSize = mActivity.getString(R.string.pref_multi_camera_picturesize_default);
- int index = mCameraIDList.indexOf(String.valueOf(id));
- String pictureSize = mLocalSharedPref.getString(
- MultiSettingsActivity.KEY_PICTURE_SIZES.get(index), defaultSize);
- mPictureSizes[id] = parsePictureSize(pictureSize);
- Log.v(TAG, " updatePictureSize size :" + mPictureSizes[id].getWidth() + "x"
- + mPictureSizes[id].getHeight());
- mImageReaders[id] = ImageReader.newInstance(mPictureSizes[id].getWidth(),
- mPictureSizes[id].getHeight(), ImageFormat.JPEG, /*maxImages*/2);
- mImageReaders[id].setOnImageAvailableListener(
- mOnImageAvailableListener, mMultiCameraModule.getMyCameraHandler());
-
- Size[] prevSizes = getSupportedOutputSize(id, SurfaceHolder.class);
- mPreviewSizes[id] = getOptimalPreviewSize(id, mPictureSizes[id], prevSizes);
- }
-
- private final ImageReader.OnImageAvailableListener mOnImageAvailableListener
- = new ImageReader.OnImageAvailableListener() {
-
- @Override
- public void onImageAvailable(ImageReader reader) {
- Log.v(TAG, "onImageAvailable ...");
- Image image = reader.acquireNextImage();
- mCaptureStartTime = System.currentTimeMillis();
- mNamedImages.nameNewImage(mCaptureStartTime);
- NamedEntity name = mNamedImages.getNextNameEntity();
- String title = (name == null) ? null : name.title;
- long date = (name == null) ? -1 : name.date;
-
- byte[] bytes = getJpegData(image);
- Log.i(TAG, "image format:" + image.getFormat());
- if (image.getFormat() == ImageFormat.RAW10) {
- mActivity.getMediaSaveService().addRawImage(bytes, title,
- "raw");
- image.close();
- } else if (image.getFormat() == ImageFormat.YUV_420_888) {
- Log.d(TAG, "YUV buffer received" );
- image.close();
- } else {
- int orientation = 0;
- ExifInterface exif = null;
- if (image.getFormat() != ImageFormat.HEIC) {
- exif = Exif.getExif(bytes);
- orientation = Exif.getOrientation(exif);
- }
-
- String pictureFormat = "jpeg";
- if (image.getFormat() == ImageFormat.HEIC) {
- pictureFormat = "heic";
- }
- mActivity.getMediaSaveService().addImage(bytes, title, date,
- null, image.getWidth(), image.getHeight(), orientation, exif,
- mOnMediaSavedListener, mContentResolver, pictureFormat);
-
- if (image.getFormat() != ImageFormat.HEIC) {
- mActivity.updateThumbnail(bytes);
- }
- image.close();
- mMultiCameraModule.updateTakingPicture();
- }
- }
-
- };
-
- /**
- * Shows a {@link Toast} on the UI thread.
- * @param text The message to show
- */
- private void showToast(final String text) {
- if (mActivity != null) {
- mActivity.runOnUiThread(new Runnable() {
- @Override
- public void run() {
- Toast.makeText(mActivity, text, Toast.LENGTH_SHORT).show();
- }
- });
- }
- }
-
- private byte[] getJpegData(Image image) {
- ByteBuffer buffer = image.getPlanes()[0].getBuffer();
- byte[] bytes = new byte[buffer.remaining()];
- buffer.get(bytes);
- return bytes;
- }
-
- @Override
- public void onShutterButtonClick(String[] ids) {
- checkAndPlayShutterSound();
- mMultiCameraUI.enableShutter(false);
- boolean halZSLCheck = mLocalSharedPref.getBoolean(MultiSettingsActivity.KEY_HAL_ZAL, false);
- for (String id : ids) {
- try {
- int cameraId = Integer.parseInt(id);
- final CaptureRequest.Builder captureBuilder =
- mCameraDevices[cameraId].createCaptureRequest(
- CameraDevice.TEMPLATE_STILL_CAPTURE);
- captureBuilder.addTarget(mImageReaders[cameraId].getSurface());
- int index = mCameraIDList.indexOf(String.valueOf(cameraId));
- captureBuilder.addTarget(mMultiCameraUI.getSurfaceViewList().get(
- index).getHolder().getSurface());
- applySettingsForCapture(captureBuilder, cameraId);
- // Use the same AE and AF modes as the preview.
- captureBuilder.set(CaptureRequest.CONTROL_AF_MODE,
- CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
- if (halZSLCheck) {
- captureBuilder.set(CaptureRequest.CONTROL_ENABLE_ZSL, true);
- } else {
- captureBuilder.set(CaptureRequest.CONTROL_ENABLE_ZSL, false);
- }
- setAutoFlash(captureBuilder);
- // Orientation
- int rotation = mActivity.getWindowManager().getDefaultDisplay().getRotation();
- captureBuilder.set(CaptureRequest.JPEG_ORIENTATION,
- CameraUtil.getJpegRotation(cameraId, rotation));
- mCameraCaptureSessions[cameraId].capture(captureBuilder.build(),
- mCaptureStillCallback, mMultiCameraModule.getMyCameraHandler());
- Log.d(TAG, " cameraCaptureSession" + id + " captured ");
- } catch (CameraAccessException e) {
- e.printStackTrace();
- }
- }
- }
-
- @Override
- public void onVideoButtonClick(String[] ids) {
-
- }
-
- @Override
- public void onButtonPause(String[] ids) {
-
- }
-
- @Override
- public void onButtonContinue(String[] ids) {
-
- }
-
- @Override
- public void onOrientationChanged(int orientation) {
-
- }
-
- @Override
- public boolean isRecordingVideo() {
- return false;
- }
-
- private void checkAndPlayShutterSound() {
- boolean isPlay = mLocalSharedPref.getBoolean(MultiSettingsActivity.KEY_SHUTTER_SOUND, true);
- if (mSoundPlayer != null && isPlay) {
- mSoundPlayer.play(SoundClips.SHUTTER_CLICK);
- }
- }
-
- private MediaSaveService.OnMediaSavedListener mOnMediaSavedListener =
- new MediaSaveService.OnMediaSavedListener() {
- @Override
- public void onMediaSaved(Uri uri) {
- if (uri != null) {
- mActivity.notifyNewMedia(uri);
- }
- }
- };
-
- private CameraCaptureSession.CaptureCallback mCaptureStillCallback
- = new CameraCaptureSession.CaptureCallback() {
-
- @Override
- public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request,
- TotalCaptureResult result) {
- Log.d(TAG, " mCaptureCallback onCaptureCompleted ");
- mMultiCameraModule.getMainHandler().post(new Runnable() {
- @Override
- public void run() {
- Log.d(TAG, " enable Shutter " );
- mMultiCameraUI.enableShutter(true);
- }
- });
- }
-
- @Override
- public void onCaptureFailed(CameraCaptureSession session,
- CaptureRequest request,
- CaptureFailure result) {
- Log.d(TAG, " mCaptureCallback onCaptureFailed " );
- }
-
-
- @Override
- public void onCaptureSequenceCompleted(CameraCaptureSession session, int
- sequenceId, long frameNumber) {
- Log.d(TAG, " mCaptureCallback onCaptureSequenceCompleted ");
- }
- };
-
- private void applySettingsForCapture(CaptureRequest.Builder builder, int id) {
- builder.set(CaptureRequest.CONTROL_AF_TRIGGER, CaptureRequest.CONTROL_AF_TRIGGER_IDLE);
- applyJpegQuality(builder);
- }
-
- private void applyJpegQuality(CaptureRequest.Builder request) {
- String defaultValue = mActivity.getString(R.string.pref_camera_jpegquality_default);
- String value = mLocalSharedPref.getString(MultiSettingsActivity.KEY_PICTURE_QUALITY,
- defaultValue);
- int jpegQuality = getQualityNumber(value);
- request.set(CaptureRequest.JPEG_QUALITY, (byte) jpegQuality);
- }
-
- private int getQualityNumber(String jpegQuality) {
- if (jpegQuality == null) {
- return 85;
- }
- try {
- int qualityPercentile = Integer.parseInt(jpegQuality);
- if (qualityPercentile >= 0 && qualityPercentile <= 100)
- return qualityPercentile;
- else
- return 85;
- } catch (NumberFormatException nfe) {
- //chosen quality is not a number, continue
- }
- int value = 0;
- switch (jpegQuality) {
- case "superfine":
- value = CameraProfile.QUALITY_HIGH;
- break;
- case "fine":
- value = CameraProfile.QUALITY_MEDIUM;
- break;
- case "normal":
- value = CameraProfile.QUALITY_LOW;
- break;
- default:
- return 85;
- }
- return CameraProfile.getJpegEncodingQualityParameter(value);
- }
-
- private Size parsePictureSize(String value) {
- int indexX = value.indexOf('x');
- int width = Integer.parseInt(value.substring(0, indexX));
- int height = Integer.parseInt(value.substring(indexX + 1));
- return new Size(width, height);
- }
-
- private void initCameraCharacteristics() {
- mCharacteristics = new ArrayList<>();
- CameraManager manager = (CameraManager) mActivity.getSystemService(Context.CAMERA_SERVICE);
- try {
- String[] cameraIdList = manager.getCameraIdList();
- Log.d(TAG, "cameraIdList size =" + cameraIdList.length);
- for (int i = 0; i < cameraIdList.length; i++) {
- String cameraId = cameraIdList[i];
- CameraCharacteristics characteristics
- = manager.getCameraCharacteristics(cameraId);
- mCharacteristics.add(i, characteristics);
- try {
- mMaxPreviewSize[i] = characteristics.get(CaptureModule.max_preview_size);
- } catch (IllegalArgumentException e) {
- Log.e(TAG, "getMaxPreviewSize no vendorTag max_preview_size:");
- }
- if (mMaxPreviewSize[i] != null) {
- Log.d(TAG, " init cameraId :" + cameraId + ", i :" + i +
- ", maxPreviewSize :" + mMaxPreviewSize[i][0]+ "x" +
- mMaxPreviewSize[i][1]);
- }
- }
- } catch (CameraAccessException e) {
- e.printStackTrace();
- }
- }
-
- private void setAutoFlash(CaptureRequest.Builder requestBuilder) {
- if (true) {
- requestBuilder.set(CaptureRequest.CONTROL_AE_MODE,
- CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
- }
- }
+/*
+ * Copyright (c) 2019 The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.camera.multi;
+
+import android.content.Context;
+import android.content.ContentResolver;
+import android.content.SharedPreferences;
+import android.graphics.ImageFormat;
+import android.graphics.Point;
+import android.hardware.camera2.CameraDevice;
+import android.hardware.camera2.CameraManager;
+import android.hardware.camera2.CameraAccessException;
+import android.hardware.camera2.CameraCaptureSession;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CaptureFailure;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureResult;
+import android.hardware.camera2.TotalCaptureResult;
+import android.hardware.camera2.params.OutputConfiguration;
+import android.hardware.camera2.params.SessionConfiguration;
+import android.hardware.camera2.params.StreamConfigurationMap;
+import android.media.CameraProfile;
+import android.media.Image;
+import android.media.ImageReader;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.Message;
+import android.util.Log;
+import android.util.Size;
+import android.view.Surface;
+import android.view.SurfaceHolder;
+import android.widget.Toast;
+
+import java.nio.ByteBuffer;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.List;
+
+import com.android.camera.CameraActivity;
+import com.android.camera.CaptureModule;
+import com.android.camera.ComboPreferences;
+import com.android.camera.MediaSaveService;
+import com.android.camera.Exif;
+import com.android.camera.SoundClips;
+import com.android.camera.exif.ExifInterface;
+import com.android.camera.PhotoModule.NamedImages;
+import com.android.camera.PhotoModule.NamedImages.NamedEntity;
+import com.android.camera.util.CameraUtil;
+import com.android.camera.util.PersistUtil;
+import org.codeaurora.snapcam.R;
+
+public class MultiCaptureModule implements MultiCamera {
+
+ private static final String TAG = "SnapCam_MultiCaptureModule";
+
+ private static final boolean DEBUG =
+ (PersistUtil.getCamera2Debug() == PersistUtil.CAMERA2_DEBUG_DUMP_LOG) ||
+ (PersistUtil.getCamera2Debug() == PersistUtil.CAMERA2_DEBUG_DUMP_ALL);
+
+ private static final int WAIT_SURFACE = 0;
+ private static final int OPEN_CAMERA = 1;
+
+ private int mCameraListIndex = 0;
+
+ private static final int MAX_NUM_CAM = 16;
+
+ private CameraActivity mActivity;
+ private MultiCameraUI mMultiCameraUI;
+ private MultiCameraModule mMultiCameraModule;
+ private CameraDevice[] mCameraDevices = new CameraDevice[MAX_NUM_CAM];
+ private SharedPreferences mLocalSharedPref;
+ private ArrayList<CameraCharacteristics> mCharacteristics;
+
+ private ArrayList<String> mCameraIDList = new ArrayList<>();
+ private CameraCaptureSession[] mCameraCaptureSessions = new CameraCaptureSession[MAX_NUM_CAM];
+ private ImageReader[] mImageReaders = new ImageReader[MAX_NUM_CAM];
+
+ private Size mPreviewSizes[] = new Size[MAX_NUM_CAM];
+ private Size mPictureSizes[] = new Size[MAX_NUM_CAM];
+ private int[][] mMaxPreviewSize = new int[MAX_NUM_CAM][];
+
+ private Handler mCameraHandler;
+ private HandlerThread mCameraThread;
+
+ private static final CaptureRequest.Key<Byte> override_resource_cost_validation =
+ new CaptureRequest.Key<>(
+ "org.codeaurora.qcamera3.sessionParameters.overrideResourceCostValidation",
+ byte.class);
+
+ /**
+ * {@link CaptureRequest.Builder} for the camera preview
+ */
+ private CaptureRequest.Builder[] mPreviewRequestBuilders = new CaptureRequest.Builder[MAX_NUM_CAM];
+ /**
+ * {@link CaptureRequest} generated by {@link #mPreviewRequestBuilder}
+ */
+ private CaptureRequest mPreviewRequest;
+ /**
+ * A {@link Semaphore} make sure the camera open callback happens first before closing the
+ * camera.
+ */
+ private Semaphore mCameraOpenCloseLock = new Semaphore(3);
+
+ /**
+ * Orientation of the camera sensor
+ */
+ private int mSensorOrientation;
+
+ private long mCaptureStartTime;
+ private NamedImages mNamedImages;
+ private ContentResolver mContentResolver;
+ private SoundClips.Player mSoundPlayer;
+
+ public MultiCaptureModule(CameraActivity activity, MultiCameraUI ui, MultiCameraModule module) {
+ mActivity = activity;
+ mMultiCameraUI = ui;
+ mMultiCameraModule = module;
+ mContentResolver = mActivity.getContentResolver();
+ mNamedImages = new NamedImages();
+ mLocalSharedPref = mActivity.getSharedPreferences(
+ ComboPreferences.getLocalSharedPreferencesName(mActivity,
+ "multi" + mMultiCameraModule.getCurrenCameraMode()), Context.MODE_PRIVATE);
+ initCameraCharacteristics();
+ startBackgroundThread();
+ }
+
+ @Override
+ public void onResume(String[] ids) {
+ for (String id : ids) {
+ mCameraIDList.add(id);
+ }
+ // Set up sound playback for shutter button, video record and video stop
+ if (mSoundPlayer == null) {
+ mSoundPlayer = SoundClips.getPlayer(mActivity);
+ }
+ startBackgroundThread();
+ initCameraCharacteristics();
+ for (String id : ids) {
+ int cameraId = Integer.parseInt(id);
+ updatePictureSize(cameraId);
+ int index = mCameraIDList.indexOf(id);
+ mMultiCameraUI.setPreviewSize(index, mPreviewSizes[cameraId].getWidth(),
+ mPreviewSizes[cameraId].getHeight());
+ }
+ }
+
+ @Override
+ public void onPause() {
+ if (mSoundPlayer != null) {
+ mSoundPlayer.release();
+ mSoundPlayer = null;
+ }
+ closeCamera();
+ if (mCameraIDList != null) {
+ mCameraIDList.clear();
+ }
+ mCameraListIndex = 0;
+ stopBackgroundThread();
+ }
+
+ @Override
+ public boolean openCamera(String[] ids) {
+ Message msg = Message.obtain();
+ msg.what = OPEN_CAMERA;
+ if (mCameraHandler != null) {
+ mCameraHandler.sendMessage(msg);
+ }
+ return true;
+ }
+
+ @Override
+ public void startPreview() {
+
+ }
+
+ @Override
+ public void closeSession() {
+
+ }
+
+ @Override
+ public void closeCamera() {
+ Log.d(TAG, "closeCamera");
+ /* no need to set this in the callback and handle asynchronously. This is the same
+ reason as why we release the semaphore here, not in camera close callback function
+ as we don't have to protect the case where camera open() gets called during camera
+ close(). The low level framework/HAL handles the synchronization for open()
+ happens after close() */
+ try {
+ // Close camera starting with AUX first
+ for (int i = MAX_NUM_CAM - 1; i >= 0; i--) {
+ if (null != mCameraDevices[i]) {
+ if (!mCameraOpenCloseLock.tryAcquire(2000, TimeUnit.MILLISECONDS)) {
+ Log.d(TAG, "Time out waiting to lock camera closing.");
+ throw new RuntimeException("Time out waiting to lock camera closing");
+ }
+ Log.d(TAG, "Closing camera: " + mCameraDevices[i].getId());
+ mCameraDevices[i].close();
+ mCameraDevices[i] = null;
+ mCameraCaptureSessions[i] = null;
+ }
+ if (null != mImageReaders[i]) {
+ mImageReaders[i].close();
+ mImageReaders[i] = null;
+ }
+ }
+ } catch (InterruptedException e) {
+ mCameraOpenCloseLock.release();
+ throw new RuntimeException("Interrupted while trying to lock camera closing.", e);
+ } catch (IllegalStateException e) {
+ e.printStackTrace();
+ } finally {
+ mCameraOpenCloseLock.release();
+ }
+ }
+
+ private void openCameraInSequence(String id) {
+ CameraManager manager = (CameraManager) mActivity.getSystemService(Context.CAMERA_SERVICE);
+ CameraCharacteristics characteristics = null;
+ try {
+ characteristics = manager.getCameraCharacteristics(id);
+ } catch (CameraAccessException e) {
+ e.printStackTrace();
+ }
+ mSensorOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
+ Log.d(TAG, "openCameraInSequence " + id + ", mSensorOrientation :" + mSensorOrientation);
+ try {
+ if (!mCameraOpenCloseLock.tryAcquire(5000, TimeUnit.MILLISECONDS)) {
+ Log.d(TAG, "Time out waiting to lock camera opening.");
+ throw new RuntimeException("Time out waiting to lock camera opening");
+ }
+ manager.openCamera(id, mStateCallback, mMultiCameraModule.getMyCameraHandler());
+ } catch (CameraAccessException e) {
+ e.printStackTrace();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ manager = null;
+ characteristics = null;
+ }
+
+ private void startBackgroundThread() {
+ if (mCameraThread == null) {
+ mCameraThread = new HandlerThread("CameraBackground");
+ mCameraThread.start();
+ }
+ if (mCameraHandler == null) {
+ mCameraHandler = new MyCameraHandler(mCameraThread.getLooper());
+ }
+ }
+
+ private void stopBackgroundThread() {
+ mCameraThread.quitSafely();
+ try {
+ mCameraThread.join();
+ mCameraThread = null;
+ mCameraHandler = null;
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private Size[] getSupportedOutputSize(int cameraId, Class cl) {
+ StreamConfigurationMap map = mCharacteristics.get(cameraId).get(
+ CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
+ Size[] normal = map.getOutputSizes(cl);
+ Size[] high = map.getHighResolutionOutputSizes(ImageFormat.PRIVATE);
+ Size[] ret = new Size[normal.length + high.length];
+ System.arraycopy(normal, 0, ret, 0, normal.length);
+ System.arraycopy(high, 0, ret, normal.length, high.length);
+ return ret;
+ }
+
+ private Size getOptimalPreviewSize(int id, Size pictureSize, Size[] prevSizes) {
+ Point[] points = new Point[prevSizes.length];
+
+ double targetRatio = (double) pictureSize.getWidth() / pictureSize.getHeight();
+ int index = 0;
+ int point_max[] = mMaxPreviewSize[id];
+ int max_size = -1;
+ if (point_max != null){
+ max_size = point_max[0] * point_max[1];
+ }
+ for (Size s : prevSizes) {
+ if (max_size != -1){
+ int size = s.getWidth() * s.getHeight();
+ if (s.getWidth() == s.getHeight()){
+ if (s.getWidth() > Math.max(point_max[0],point_max[1]))
+ continue;
+ } else if (size > max_size || size == 0) {
+ continue;
+ }
+ }
+ points[index++] = new Point(s.getWidth(), s.getHeight());
+ }
+
+ int optimalPickIndex = CameraUtil.getOptimalPreviewSize(mActivity, points, targetRatio);
+ return (optimalPickIndex == -1) ? null :
+ new Size(points[optimalPickIndex].x,points[optimalPickIndex].y);
+ }
+
+ private class MyCameraHandler extends Handler {
+
+ public MyCameraHandler(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case WAIT_SURFACE:
+ int id = msg.arg1;
+ int index = mCameraIDList.indexOf(String.valueOf(id));
+ Log.v(TAG, "WAIT_SURFACE id :" + id + ", index :" + index);
+ if (index == -1) {
+ break;
+ }
+ Surface surface = mMultiCameraUI.getSurfaceViewList().get(index)
+ .getHolder().getSurface();
+ if (surface.isValid()) {
+ createCaptureSessions(id, surface);
+ } else {
+ mCameraHandler.sendMessageDelayed(msg, 200);
+ Log.v(TAG, "Surface is invalid, wait more 200ms surfaceCreated");
+ }
+ break;
+ case OPEN_CAMERA:
+ if (mCameraListIndex == mCameraIDList.size()) {
+ mCameraListIndex = 0;
+ } else {
+ String cameraId = mCameraIDList.get(mCameraListIndex);
+ openCameraInSequence(cameraId);
+ mCameraListIndex ++;
+ Log.v(TAG, " OPEN_CAMERA cameraId :" + cameraId + ", mCameraListIndex :"
+ + mCameraListIndex);
+ }
+ break;
+ }
+ }
+ }
+
+ private final CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {
+
+ @Override
+ public void onOpened(CameraDevice cameraDevice) {
+ final int id = Integer.parseInt(cameraDevice.getId());
+ mCameraDevices[id] = cameraDevice;
+ Log.d(TAG, "onOpened " + id);
+ mCameraOpenCloseLock.release();
+ //updatePictureSize(id);
+ createCameraPreviewSession(id);
+ mActivity.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ mMultiCameraUI.onCameraOpened(id);
+ }
+ });
+ }
+
+ @Override
+ public void onDisconnected(CameraDevice cameraDevice) {
+ int id = Integer.parseInt(cameraDevice.getId());
+ Log.d(TAG, "onDisconnected " + id);
+ mCameraOpenCloseLock.release();
+ mCameraDevices[id] = null;
+ }
+
+ @Override
+ public void onError(CameraDevice cameraDevice, int error) {
+ int id = Integer.parseInt(cameraDevice.getId());
+ Log.e(TAG, "onError " + id + " " + error);
+ mCameraOpenCloseLock.release();
+
+ if (null != mActivity) {
+ Toast.makeText(mActivity,"open camera error id =" + id,
+ Toast.LENGTH_LONG).show();
+ mActivity.finish();
+ }
+ }
+
+ @Override
+ public void onClosed(CameraDevice cameraDevice) {
+ int id = Integer.parseInt(cameraDevice.getId());
+ Log.d(TAG, "onClosed " + id);
+ mCameraOpenCloseLock.release();
+ mCameraDevices[id] = null;
+ }
+ };
+
+ /**
+ * Creates a new {@link CameraCaptureSession} for camera preview.
+ */
+ private void createCameraPreviewSession(int id) {
+ // This is the output Surface we need to start preview.
+ int index = mCameraIDList.indexOf(String.valueOf(id));
+ Log.v(TAG, "createCameraPreviewSession id :" + id + ", index :" + index);
+ Surface surface = mMultiCameraUI.getSurfaceViewList().get(index).getHolder().getSurface();
+ if (surface.isValid()) {
+ createCaptureSessions(id, surface);
+ } else {
+ Message msg = Message.obtain();
+ msg.what = WAIT_SURFACE;
+ msg.arg1 = id;
+ mCameraHandler.sendMessageDelayed(msg, 200);
+ Log.v(TAG, "Surface is invalid, wait 200ms surfaceCreated");
+ }
+ }
+
+ private void createCaptureSessions(final int id, Surface surface) {
+ try {
+ // We set up a CaptureRequest.Builder with the output Surface.
+ mPreviewRequestBuilders[id]
+ = mCameraDevices[id].createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
+ mPreviewRequestBuilders[id].addTarget(surface);
+ mPreviewRequestBuilders[id].setTag(id);
+ CameraCaptureSession.StateCallback stateCallback =
+ new CameraCaptureSession.StateCallback() {
+ @Override
+ public void onConfigured(CameraCaptureSession cameraCaptureSession) {
+ // The camera is already closed
+ if (null == mCameraDevices[id]) {
+ return;
+ }
+ Log.v(TAG, " CameraCaptureSession onConfigured id :" + id);
+ // When the session is ready, we start displaying the preview.
+ mCameraCaptureSessions[id] = cameraCaptureSession;
+ try {
+ // Auto focus should be continuous for camera preview.
+ mPreviewRequestBuilders[id].set(CaptureRequest.CONTROL_AF_MODE,
+ CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
+ // Finally, we start displaying the camera preview.
+ mCameraCaptureSessions[id].setRepeatingRequest(
+ mPreviewRequestBuilders[id].build(),
+ mCaptureCallback, mMultiCameraModule.getMyCameraHandler());
+ } catch (CameraAccessException e) {
+ e.printStackTrace();
+ }
+
+ Message msg = Message.obtain();
+ msg.what = OPEN_CAMERA;
+ if (mCameraHandler != null) {
+ mCameraHandler.sendMessage(msg);
+ }
+ }
+
+ @Override
+ public void onConfigureFailed(CameraCaptureSession cameraCaptureSession) {
+ showToast("onConfigureFailed");
+ }
+ };
+
+ try {
+ final byte enable = 1;
+ mPreviewRequestBuilders[id].set(override_resource_cost_validation, enable);
+ Log.v(TAG, " set" + override_resource_cost_validation + " is 1");
+ } catch (IllegalArgumentException e) {
+ e.printStackTrace();
+ }
+
+ List<OutputConfiguration> outConfigurations = new ArrayList<>(2);
+ outConfigurations.add(new OutputConfiguration(surface));
+ outConfigurations.add(new OutputConfiguration(mImageReaders[id].getSurface()));
+
+ SessionConfiguration sessionConfiguration = new SessionConfiguration(
+ SessionConfiguration.SESSION_REGULAR, outConfigurations,
+ new HandlerExecutor(mCameraHandler), stateCallback);
+ sessionConfiguration.setSessionParameters(mPreviewRequestBuilders[id].build());
+ mCameraDevices[id].createCaptureSession(sessionConfiguration);
+ try {
+ CaptureRequest captureRequest = sessionConfiguration.getSessionParameters();
+ Log.v(TAG, " override_resource_cost_validation result: " +
+ captureRequest.get(override_resource_cost_validation));
+ } catch (IllegalArgumentException e) {
+ e.printStackTrace();
+ }
+ } catch (CameraAccessException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private class HandlerExecutor implements Executor {
+ private final Handler ihandler;
+
+ public HandlerExecutor(Handler handler) {
+ ihandler = handler;
+ }
+
+ @Override
+ public void execute(Runnable runCmd) {
+ ihandler.post(runCmd);
+ }
+ }
+
+ /**
+ * A {@link CameraCaptureSession.CaptureCallback} that handles events related to JPEG capture.
+ */
+ private CameraCaptureSession.CaptureCallback mCaptureCallback
+ = new CameraCaptureSession.CaptureCallback() {
+
+ private void process(CaptureResult result) {
+ Integer afState = result.get(CaptureResult.CONTROL_AF_STATE);
+ Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);
+ if (DEBUG) {
+ Log.v(TAG, "process afState :" + afState + ", aeState :" + aeState);
+ }
+ }
+
+ @Override
+ public void onCaptureProgressed(CameraCaptureSession session, CaptureRequest request,
+ CaptureResult partialResult) {
+ process(partialResult);
+ }
+
+ @Override
+ public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request,
+ TotalCaptureResult result) {
+ process(result);
+ }
+
+ };
+
+ private void updatePictureSize(int id) {
+ String defaultSize = mActivity.getString(R.string.pref_multi_camera_picturesize_default);
+ int index = mCameraIDList.indexOf(String.valueOf(id));
+ String pictureSize = mLocalSharedPref.getString(
+ MultiSettingsActivity.KEY_PICTURE_SIZES.get(index), defaultSize);
+ mPictureSizes[id] = parsePictureSize(pictureSize);
+ Log.v(TAG, " updatePictureSize size :" + mPictureSizes[id].getWidth() + "x"
+ + mPictureSizes[id].getHeight());
+ mImageReaders[id] = ImageReader.newInstance(mPictureSizes[id].getWidth(),
+ mPictureSizes[id].getHeight(), ImageFormat.JPEG, /*maxImages*/2);
+ mImageReaders[id].setOnImageAvailableListener(
+ mOnImageAvailableListener, mMultiCameraModule.getMyCameraHandler());
+
+ Size[] prevSizes = getSupportedOutputSize(id, SurfaceHolder.class);
+ mPreviewSizes[id] = getOptimalPreviewSize(id, mPictureSizes[id], prevSizes);
+ }
+
+ private final ImageReader.OnImageAvailableListener mOnImageAvailableListener
+ = new ImageReader.OnImageAvailableListener() {
+
+ @Override
+ public void onImageAvailable(ImageReader reader) {
+ Log.v(TAG, "onImageAvailable ...");
+ Image image = reader.acquireNextImage();
+ mCaptureStartTime = System.currentTimeMillis();
+ mNamedImages.nameNewImage(mCaptureStartTime);
+ NamedEntity name = mNamedImages.getNextNameEntity();
+ String title = (name == null) ? null : name.title;
+ long date = (name == null) ? -1 : name.date;
+
+ byte[] bytes = getJpegData(image);
+ Log.i(TAG, "image format:" + image.getFormat());
+ if (image.getFormat() == ImageFormat.RAW10) {
+ mActivity.getMediaSaveService().addRawImage(bytes, title,
+ "raw");
+ image.close();
+ } else if (image.getFormat() == ImageFormat.YUV_420_888) {
+ Log.d(TAG, "YUV buffer received" );
+ image.close();
+ } else {
+ int orientation = 0;
+ ExifInterface exif = null;
+ if (image.getFormat() != ImageFormat.HEIC) {
+ exif = Exif.getExif(bytes);
+ orientation = Exif.getOrientation(exif);
+ }
+
+ String pictureFormat = "jpeg";
+ if (image.getFormat() == ImageFormat.HEIC) {
+ pictureFormat = "heic";
+ }
+ mActivity.getMediaSaveService().addImage(bytes, title, date,
+ null, image.getWidth(), image.getHeight(), orientation, exif,
+ mOnMediaSavedListener, mContentResolver, pictureFormat);
+
+ if (image.getFormat() != ImageFormat.HEIC) {
+ mActivity.updateThumbnail(bytes);
+ }
+ image.close();
+ mMultiCameraModule.updateTakingPicture();
+ }
+ }
+
+ };
+
+ /**
+ * Shows a {@link Toast} on the UI thread.
+ * @param text The message to show
+ */
+ private void showToast(final String text) {
+ if (mActivity != null) {
+ mActivity.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ Toast.makeText(mActivity, text, Toast.LENGTH_SHORT).show();
+ }
+ });
+ }
+ }
+
+ private byte[] getJpegData(Image image) {
+ ByteBuffer buffer = image.getPlanes()[0].getBuffer();
+ byte[] bytes = new byte[buffer.remaining()];
+ buffer.get(bytes);
+ return bytes;
+ }
+
+ @Override
+ public void onShutterButtonClick(String[] ids) {
+ checkAndPlayShutterSound();
+ mMultiCameraUI.enableShutter(false);
+ boolean halZSLCheck = mLocalSharedPref.getBoolean(MultiSettingsActivity.KEY_HAL_ZAL, false);
+ for (String id : ids) {
+ try {
+ int cameraId = Integer.parseInt(id);
+ final CaptureRequest.Builder captureBuilder =
+ mCameraDevices[cameraId].createCaptureRequest(
+ CameraDevice.TEMPLATE_STILL_CAPTURE);
+ captureBuilder.addTarget(mImageReaders[cameraId].getSurface());
+ int index = mCameraIDList.indexOf(String.valueOf(cameraId));
+ captureBuilder.addTarget(mMultiCameraUI.getSurfaceViewList().get(
+ index).getHolder().getSurface());
+ applySettingsForCapture(captureBuilder, cameraId);
+ // Use the same AE and AF modes as the preview.
+ captureBuilder.set(CaptureRequest.CONTROL_AF_MODE,
+ CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
+ if (halZSLCheck) {
+ captureBuilder.set(CaptureRequest.CONTROL_ENABLE_ZSL, true);
+ } else {
+ captureBuilder.set(CaptureRequest.CONTROL_ENABLE_ZSL, false);
+ }
+ setAutoFlash(captureBuilder);
+ // Orientation
+ int rotation = mActivity.getWindowManager().getDefaultDisplay().getRotation();
+ captureBuilder.set(CaptureRequest.JPEG_ORIENTATION,
+ CameraUtil.getJpegRotation(cameraId, rotation));
+ mCameraCaptureSessions[cameraId].capture(captureBuilder.build(),
+ mCaptureStillCallback, mMultiCameraModule.getMyCameraHandler());
+ Log.d(TAG, " cameraCaptureSession" + id + " captured ");
+ } catch (CameraAccessException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ @Override
+ public void onVideoButtonClick(String[] ids) {
+
+ }
+
+ @Override
+ public void onButtonPause(String[] ids) {
+
+ }
+
+ @Override
+ public void onButtonContinue(String[] ids) {
+
+ }
+
+ @Override
+ public void onOrientationChanged(int orientation) {
+
+ }
+
+ @Override
+ public boolean isRecordingVideo() {
+ return false;
+ }
+
+ private void checkAndPlayShutterSound() {
+ boolean isPlay = mLocalSharedPref.getBoolean(MultiSettingsActivity.KEY_SHUTTER_SOUND, true);
+ if (mSoundPlayer != null && isPlay) {
+ mSoundPlayer.play(SoundClips.SHUTTER_CLICK);
+ }
+ }
+
+ private MediaSaveService.OnMediaSavedListener mOnMediaSavedListener =
+ new MediaSaveService.OnMediaSavedListener() {
+ @Override
+ public void onMediaSaved(Uri uri) {
+ if (uri != null) {
+ mActivity.notifyNewMedia(uri);
+ }
+ }
+ };
+
+ private CameraCaptureSession.CaptureCallback mCaptureStillCallback
+ = new CameraCaptureSession.CaptureCallback() {
+
+ @Override
+ public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request,
+ TotalCaptureResult result) {
+ Log.d(TAG, " mCaptureCallback onCaptureCompleted ");
+ mMultiCameraModule.getMainHandler().post(new Runnable() {
+ @Override
+ public void run() {
+ Log.d(TAG, " enable Shutter " );
+ mMultiCameraUI.enableShutter(true);
+ }
+ });
+ }
+
+ @Override
+ public void onCaptureFailed(CameraCaptureSession session,
+ CaptureRequest request,
+ CaptureFailure result) {
+ Log.d(TAG, " mCaptureCallback onCaptureFailed " );
+ }
+
+
+ @Override
+ public void onCaptureSequenceCompleted(CameraCaptureSession session, int
+ sequenceId, long frameNumber) {
+ Log.d(TAG, " mCaptureCallback onCaptureSequenceCompleted ");
+ }
+ };
+
+ private void applySettingsForCapture(CaptureRequest.Builder builder, int id) {
+ builder.set(CaptureRequest.CONTROL_AF_TRIGGER, CaptureRequest.CONTROL_AF_TRIGGER_IDLE);
+ applyJpegQuality(builder);
+ }
+
+ private void applyJpegQuality(CaptureRequest.Builder request) {
+ String defaultValue = mActivity.getString(R.string.pref_camera_jpegquality_default);
+ String value = mLocalSharedPref.getString(MultiSettingsActivity.KEY_PICTURE_QUALITY,
+ defaultValue);
+ int jpegQuality = getQualityNumber(value);
+ request.set(CaptureRequest.JPEG_QUALITY, (byte) jpegQuality);
+ }
+
+ private int getQualityNumber(String jpegQuality) {
+ if (jpegQuality == null) {
+ return 85;
+ }
+ try {
+ int qualityPercentile = Integer.parseInt(jpegQuality);
+ if (qualityPercentile >= 0 && qualityPercentile <= 100)
+ return qualityPercentile;
+ else
+ return 85;
+ } catch (NumberFormatException nfe) {
+ //chosen quality is not a number, continue
+ }
+ int value = 0;
+ switch (jpegQuality) {
+ case "superfine":
+ value = CameraProfile.QUALITY_HIGH;
+ break;
+ case "fine":
+ value = CameraProfile.QUALITY_MEDIUM;
+ break;
+ case "normal":
+ value = CameraProfile.QUALITY_LOW;
+ break;
+ default:
+ return 85;
+ }
+ return CameraProfile.getJpegEncodingQualityParameter(value);
+ }
+
+ private Size parsePictureSize(String value) {
+ int indexX = value.indexOf('x');
+ int width = Integer.parseInt(value.substring(0, indexX));
+ int height = Integer.parseInt(value.substring(indexX + 1));
+ return new Size(width, height);
+ }
+
+ private void initCameraCharacteristics() {
+ mCharacteristics = new ArrayList<>();
+ CameraManager manager = (CameraManager) mActivity.getSystemService(Context.CAMERA_SERVICE);
+ try {
+ String[] cameraIdList = manager.getCameraIdList();
+ Log.d(TAG, "cameraIdList size =" + cameraIdList.length);
+ for (int i = 0; i < cameraIdList.length; i++) {
+ String cameraId = cameraIdList[i];
+ CameraCharacteristics characteristics
+ = manager.getCameraCharacteristics(cameraId);
+ mCharacteristics.add(i, characteristics);
+ try {
+ mMaxPreviewSize[i] = characteristics.get(CaptureModule.max_preview_size);
+ } catch (IllegalArgumentException e) {
+ Log.e(TAG, "getMaxPreviewSize no vendorTag max_preview_size:");
+ }
+ if (mMaxPreviewSize[i] != null) {
+ Log.d(TAG, " init cameraId :" + cameraId + ", i :" + i +
+ ", maxPreviewSize :" + mMaxPreviewSize[i][0]+ "x" +
+ mMaxPreviewSize[i][1]);
+ }
+ }
+ } catch (CameraAccessException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private void setAutoFlash(CaptureRequest.Builder requestBuilder) {
+ if (true) {
+ requestBuilder.set(CaptureRequest.CONTROL_AE_MODE,
+ CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
+ }
+ }
} \ No newline at end of file
diff --git a/src/com/android/camera/multi/MultiSettingsActivity.java b/src/com/android/camera/multi/MultiSettingsActivity.java
index a3bd75f80..a3bd75f80 100755..100644
--- a/src/com/android/camera/multi/MultiSettingsActivity.java
+++ b/src/com/android/camera/multi/MultiSettingsActivity.java
diff --git a/src/com/android/camera/multi/MultiVideoModule.java b/src/com/android/camera/multi/MultiVideoModule.java
index b07e7ca18..0caf30d30 100644
--- a/src/com/android/camera/multi/MultiVideoModule.java
+++ b/src/com/android/camera/multi/MultiVideoModule.java
@@ -1,1332 +1,1338 @@
-/*
- * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
- * Not a Contribution.
- *
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.camera.multi;
-
-import android.content.Context;
-import android.content.ContentResolver;
-import android.content.ContentValues;
-import android.content.SharedPreferences;
-import android.graphics.Bitmap;
-import android.graphics.ImageFormat;
-import android.graphics.Point;
-import android.hardware.camera2.CameraAccessException;
-import android.hardware.camera2.CameraCaptureSession;
-import android.hardware.camera2.CameraCharacteristics;
-import android.hardware.camera2.CameraDevice;
-import android.hardware.camera2.CaptureFailure;
-import android.hardware.camera2.CameraManager;
-import android.hardware.camera2.CameraMetadata;
-import android.hardware.camera2.CaptureRequest;
-import android.hardware.camera2.CaptureResult;
-import android.hardware.camera2.TotalCaptureResult;
-import android.hardware.camera2.params.OutputConfiguration;
-import android.hardware.camera2.params.SessionConfiguration;
-import android.hardware.camera2.params.StreamConfigurationMap;
-import android.location.Location;
-import android.media.AudioManager;
-import android.media.CamcorderProfile;
-import android.media.Image;
-import android.media.ImageReader;
-import android.media.MediaRecorder;
-import android.media.MediaMetadataRetriever;
-import android.net.Uri;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.Looper;
-import android.os.Message;
-import android.os.SystemClock;
-import android.os.ParcelFileDescriptor;
-import android.provider.MediaStore;
-import android.util.Log;
-import android.util.Size;
-import android.view.OrientationEventListener;
-import android.util.SparseIntArray;
-import android.view.Surface;
-import android.view.SurfaceHolder;
-import android.view.WindowManager;
-import android.widget.Toast;
-
-import java.io.File;
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.text.SimpleDateFormat;
-import java.util.Arrays;
-import java.util.ArrayList;
-import java.util.concurrent.Executor;
-import java.util.List;
-import java.util.Date;
-import java.util.concurrent.Semaphore;
-import java.util.concurrent.TimeUnit;
-
-import com.android.camera.CameraActivity;
-import com.android.camera.CaptureModule;
-import com.android.camera.CameraSettings;
-import com.android.camera.ComboPreferences;
-import com.android.camera.Exif;
-import com.android.camera.exif.ExifInterface;
-import com.android.camera.LocationManager;
-import com.android.camera.MediaSaveService;
-import com.android.camera.PhotoModule.NamedImages;
-import com.android.camera.PhotoModule.NamedImages.NamedEntity;
-import com.android.camera.SoundClips;
-import com.android.camera.Storage;
-import com.android.camera.Thumbnail;
-import com.android.camera.util.CameraUtil;
-import com.android.camera.util.SettingTranslation;
-import com.android.camera.util.PersistUtil;
-import com.android.camera.ui.RotateTextToast;
-
-import org.codeaurora.snapcam.R;
-
-public class MultiVideoModule implements MultiCamera, LocationManager.Listener,
- MediaRecorder.OnErrorListener, MediaRecorder.OnInfoListener {
-
- private static final String TAG = "SnapCam_MultiVideoModule";
-
- private static final boolean DEBUG =
- (PersistUtil.getCamera2Debug() == PersistUtil.CAMERA2_DEBUG_DUMP_LOG) ||
- (PersistUtil.getCamera2Debug() == PersistUtil.CAMERA2_DEBUG_DUMP_ALL);
-
- private static final int SENSOR_ORIENTATION_DEFAULT_DEGREES = 90;
- private static final int SENSOR_ORIENTATION_INVERSE_DEGREES = 270;
- private static final SparseIntArray DEFAULT_ORIENTATIONS = new SparseIntArray();
- private static final SparseIntArray INVERSE_ORIENTATIONS = new SparseIntArray();
-
- private static final int WAIT_SURFACE = 0;
- private static final int OPEN_CAMERA = 1;
-
- private static final int SCREEN_DELAY = 2 * 60 * 1000;
-
- private static final int MAX_NUM_CAM = 16;
-
- private int mCameraListIndex = 0;
-
- private static final CaptureRequest.Key<Byte> override_resource_cost_validation =
- new CaptureRequest.Key<>(
- "org.codeaurora.qcamera3.sessionParameters.overrideResourceCostValidation",
- byte.class);
-
- private CameraActivity mActivity;
- private MultiCameraUI mMultiCameraUI;
- private MultiCameraModule mMultiCameraModule;
- private SharedPreferences mLocalSharedPref;
- private ArrayList<CameraCharacteristics> mCharacteristics;
- private CameraDevice[] mCameraDevices = new CameraDevice[MAX_NUM_CAM];
- private CameraCaptureSession[] mCameraPreviewSessions = new CameraCaptureSession[MAX_NUM_CAM];
- private ContentValues[] mCurrentVideoValues = new ContentValues[MAX_NUM_CAM];
- private ImageReader[] mImageReaders = new ImageReader[MAX_NUM_CAM];
- private MediaRecorder[] mMediaRecorders = new MediaRecorder[MAX_NUM_CAM];
- private String[] mNextVideoAbsolutePaths = new String[MAX_NUM_CAM];
- private boolean mPaused = true;
-
- private NamedImages mNamedImages;
-
- private Uri mCurrentVideoUri;
-
- private boolean mMediaRecorderPausing = false;
-
- private boolean mRecordingTimeCountsDown = false;
-
- private LocationManager mLocationManager;
- private CamcorderProfile mProfile;
-
- private Size[] mVideoSize = new Size[MAX_NUM_CAM];
- private Size mPreviewSizes[] = new Size[MAX_NUM_CAM];
- private int[][] mMaxPreviewSize = new int[MAX_NUM_CAM][];
-
- private boolean mCaptureTimeLapse = false;
- // Default 0. If it is larger than 0, the camcorder is in time lapse mode.
- private int mTimeBetweenTimeLapseFrameCaptureMs = 0;
-
- private String[] mVideoFilenames = new String[MAX_NUM_CAM];
-
- private long mRecordingStartTime;
- private long mRecordingTotalTime;
-
- private ParcelFileDescriptor mVideoFileDescriptor;
-
- // The video duration limit. 0 means no limit.
- private int mMaxVideoDurationInMs;
-
- private int mAudioEncoder;
- private String mVideoRotation;
-
- private SoundClips.Player mSoundPlayer;
-
- /**
- * Whether the app is recording video now
- */
- private boolean[] mIsRecordingVideos = new boolean[MAX_NUM_CAM];
-
- private String[] mCameraIds;
- private ArrayList<String> mCameraIDList = new ArrayList<>();
-
- /**
- * Orientation of the camera sensor
- */
- private int mSensorOrientation;
- private int mOrientation = OrientationEventListener.ORIENTATION_UNKNOWN;
-
- /**
- * {@link CaptureRequest.Builder} for the camera preview
- */
- private CaptureRequest.Builder[] mPreviewRequestBuilders = new CaptureRequest.Builder[MAX_NUM_CAM];
-
- private Handler mCameraHandler;
- private HandlerThread mCameraThread;
-
- private ContentResolver mContentResolver;
- /**
- * A {@link Semaphore} make sure the camera open callback happens first before closing the
- * camera.
- */
- private Semaphore mCameraOpenCloseLock = new Semaphore(3);
-
- public MultiVideoModule(CameraActivity activity, MultiCameraUI ui, MultiCameraModule module) {
- mActivity = activity;
- mMultiCameraUI = ui;
- mMultiCameraModule = module;
- mContentResolver = mActivity.getContentResolver();
- mLocationManager = new LocationManager(mActivity, this);
- mNamedImages = new NamedImages();
- mLocalSharedPref = mActivity.getSharedPreferences(
- ComboPreferences.getLocalSharedPreferencesName(mActivity,
- "multi" + mMultiCameraModule.getCurrenCameraMode()), Context.MODE_PRIVATE);
- startBackgroundThread();
- initCameraCharacteristics();
- }
-
- @Override
- public void onResume(String[] ids) {
- for (String id : ids) {
- mCameraIDList.add(id);
- }
- // Set up sound playback for video record and video stop
- if (mSoundPlayer == null) {
- mSoundPlayer = SoundClips.getPlayer(mActivity);
- }
- mPaused = false;
- initializeValues();
- startBackgroundThread();
- for (String id : ids) {
- int cameraId = Integer.parseInt(id);
- updateVideoSize(cameraId);
- int index = mCameraIDList.indexOf(id);
- mMultiCameraUI.setPreviewSize(index, mPreviewSizes[cameraId].getWidth(),
- mPreviewSizes[cameraId].getHeight());
- }
- }
-
- @Override
- public void onPause() {
- mPaused = true;
- if (mSoundPlayer != null) {
- mSoundPlayer.release();
- mSoundPlayer = null;
- }
- for (String id : mCameraIds) {
- int cameraId = Integer.parseInt(id);
- Log.d(TAG, " onPause id :" + cameraId + " recording is :" +
- (mIsRecordingVideos[cameraId] ? "STOPED" : "START"));
- if (mIsRecordingVideos[cameraId]) {
- stopRecordingVideo(cameraId);
- }
- }
-
- if (mCameraIDList != null) {
- mCameraIDList.clear();
- }
- mCameraListIndex = 0;
- closeCamera();
- stopBackgroundThread();
- }
-
- @Override
- public boolean openCamera(String[] ids) {
- mCameraIds = ids;
- for (String id : ids) {
- mCameraIDList.add(id);
- }
- Message msg = Message.obtain();
- msg.what = OPEN_CAMERA;
- if (mCameraHandler != null) {
- mCameraHandler.sendMessage(msg);
- }
- return true;
- }
-
- @Override
- public void startPreview() {
-
- }
-
- @Override
- public void closeSession() {
-
- }
-
- @Override
- public void closeCamera() {
- Log.d(TAG, "closeCamera");
- /* no need to set this in the callback and handle asynchronously. This is the same
- reason as why we release the semaphore here, not in camera close callback function
- as we don't have to protect the case where camera open() gets called during camera
- close(). The low level framework/HAL handles the synchronization for open()
- happens after close() */
- try {
- // Close camera starting with AUX first
- for (int i = MAX_NUM_CAM - 1; i >= 0; i--) {
- if (null != mCameraDevices[i]) {
- if (!mCameraOpenCloseLock.tryAcquire(2000, TimeUnit.MILLISECONDS)) {
- Log.d(TAG, "Time out waiting to lock camera closing.");
- throw new RuntimeException("Time out waiting to lock camera closing");
- }
- Log.d(TAG, "Closing camera: " + mCameraDevices[i].getId());
- mCameraDevices[i].close();
- mCameraDevices[i] = null;
- mCameraPreviewSessions[i] = null;
- }
- if (null != mImageReaders[i]) {
- mImageReaders[i].close();
- mImageReaders[i] = null;
- }
- }
- } catch (InterruptedException e) {
- mCameraOpenCloseLock.release();
- throw new RuntimeException("Interrupted while trying to lock camera closing.", e);
- } catch (IllegalStateException e) {
- e.printStackTrace();
- } finally {
- mCameraOpenCloseLock.release();
- }
- }
-
- @Override
- public void onVideoButtonClick(String[] ids) {
- checkAndPlayShutterSound(mIsRecordingVideos[0]);
- for (String id : ids) {
- int cameraId = Integer.parseInt(id);
- Log.d(TAG, " onVideoButtonClick id :" + cameraId + " recording is :" +
- (mIsRecordingVideos[cameraId] ? "STOPED" : "START"));
- if (mIsRecordingVideos[cameraId]) {
- stopRecordingVideo(cameraId);
- } else {
- startRecordingVideo(cameraId);
- }
- }
- }
-
- @Override
- public void onShutterButtonClick(String[] ids) {
- checkAndPlayCaptureSound();
- mMultiCameraUI.enableShutter(false);
- for (String id : ids) {
- Log.d(TAG, "onShutterButtonClick id :" + id);
- try {
- int cameraId = Integer.parseInt(id);
- if (null == mActivity || null == mCameraDevices[cameraId]) {
- warningToast("Camera is not ready yet to take a video snapshot.");
- return;
- }
- final CaptureRequest.Builder captureBuilder =
- mCameraDevices[cameraId].createCaptureRequest(
- CameraDevice.TEMPLATE_VIDEO_SNAPSHOT);
- captureBuilder.addTarget(mImageReaders[cameraId].getSurface());
- int index = mCameraIDList.indexOf(String.valueOf(cameraId));
- captureBuilder.addTarget(mMultiCameraUI.getSurfaceViewList().get(
- index).getHolder().getSurface());
- // Use the same AE and AF modes as the preview.
- captureBuilder.set(CaptureRequest.CONTROL_AF_MODE,
- CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
- captureBuilder.set(CaptureRequest.JPEG_THUMBNAIL_QUALITY, (byte) 80);
- captureBuilder.set(CaptureRequest.CONTROL_MODE, CaptureRequest.CONTROL_MODE_AUTO);
- captureBuilder.set(CaptureRequest.CONTROL_AE_MODE,
- CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
-
- // Orientation
- int rotation = mActivity.getWindowManager().getDefaultDisplay().getRotation();
- captureBuilder.set(CaptureRequest.JPEG_ORIENTATION,
- CameraUtil.getJpegRotation(cameraId, rotation));
- mCameraPreviewSessions[cameraId].capture(captureBuilder.build(),
- mCaptureStillCallback, mMultiCameraModule.getMyCameraHandler());
- Log.d(TAG, " cameraCaptureSession" + id + " captured ");
- } catch (CameraAccessException e) {
- e.printStackTrace();
- }
- }
- }
-
- @Override
- public void onButtonPause(String[] ids) {
- mRecordingTotalTime += SystemClock.uptimeMillis() - mRecordingStartTime;
- mMediaRecorderPausing = true;
- for (String id : ids) {
- int cameraId = Integer.parseInt(id);
- mMediaRecorders[cameraId].pause();
- }
- }
-
- @Override
- public void onButtonContinue(String[] ids) {
- mMediaRecorderPausing = false;
- for (String id : ids) {
- int cameraId = Integer.parseInt(id);
- mMediaRecorders[cameraId].resume();
- mRecordingStartTime = SystemClock.uptimeMillis();
- updateRecordingTime(cameraId);
- }
- }
-
- @Override
- public void onErrorListener(int error) {
- enableRecordingLocation(false);
- }
-
- // from MediaRecorder.OnErrorListener
- @Override
- public void onError(MediaRecorder mr, int what, int extra) {
- Log.e(TAG, "MediaRecorder error. what=" + what + ". extra=" + extra);
- String[] ids = {"0", "1"};
- for (String id : ids) {
- int cameraId = Integer.parseInt(id);
- stopRecordingVideo(cameraId);
- }
- if (what == MediaRecorder.MEDIA_RECORDER_ERROR_UNKNOWN) {
- // We may have run out of space on the sdcard.
- mActivity.updateStorageSpaceAndHint();
- } else {
- warningToast("MediaRecorder error. what=" + what + ". extra=" + extra);
- }
- }
-
- // from MediaRecorder.OnInfoListener
- @Override
- public void onInfo(MediaRecorder mr, int what, int extra) {
- String[] ids = {"0", "1"};
- if (what == MediaRecorder.MEDIA_RECORDER_INFO_MAX_DURATION_REACHED) {
- for (String id : ids) {
- int cameraId = Integer.parseInt(id);
- if (mIsRecordingVideos[cameraId]) {
- stopRecordingVideo(cameraId);
- }
- }
- } else if (what == MediaRecorder.MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED) {
- for (String id : ids) {
- int cameraId = Integer.parseInt(id);
- if (mIsRecordingVideos[cameraId]) {
- stopRecordingVideo(cameraId);
- }
- }
- // Show the toast.
- RotateTextToast.makeText(mActivity, R.string.video_reach_size_limit,
- Toast.LENGTH_LONG).show();
- }
- }
-
- @Override
- public void onOrientationChanged(int orientation) {
- mOrientation = orientation;
- }
-
- @Override
- public boolean isRecordingVideo() {
- for (int i = 0; i < mIsRecordingVideos.length; i++) {
- if (mIsRecordingVideos[i]) return true;
- }
- return false;
- }
-
- private void openCameraInSequence(String id) {
- CameraManager manager = (CameraManager) mActivity.getSystemService(Context.CAMERA_SERVICE);
- CameraCharacteristics characteristics = null;
- try {
- characteristics = manager.getCameraCharacteristics(id);
- } catch (CameraAccessException e) {
- e.printStackTrace();
- }
- mSensorOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
- Log.d(TAG, "openCameraInSequence " + id + ", mSensorOrientation :" + mSensorOrientation);
- try {
- if (!mCameraOpenCloseLock.tryAcquire(5000, TimeUnit.MILLISECONDS)) {
- Log.d(TAG, "Time out waiting to lock camera opening.");
- throw new RuntimeException("Time out waiting to lock camera opening");
- }
- manager.openCamera(id, mStateCallback, mMultiCameraModule.getMyCameraHandler());
- } catch (CameraAccessException e) {
- e.printStackTrace();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- manager = null;
- characteristics = null;
- }
-
- private void initCameraCharacteristics() {
- mCharacteristics = new ArrayList<>();
- CameraManager manager = (CameraManager) mActivity.getSystemService(Context.CAMERA_SERVICE);
- try {
- String[] cameraIdList = manager.getCameraIdList();
- Log.d(TAG, "cameraIdList size =" + cameraIdList.length);
- for (int i = 0; i < cameraIdList.length; i++) {
- String cameraId = cameraIdList[i];
- CameraCharacteristics characteristics
- = manager.getCameraCharacteristics(cameraId);
- mCharacteristics.add(i, characteristics);
- try {
- mMaxPreviewSize[i] = characteristics.get(CaptureModule.max_preview_size);
- } catch (IllegalArgumentException e) {
- Log.e(TAG, "getMaxPreviewSize no vendorTag max_preview_size:");
- }
- if (mMaxPreviewSize[i] != null) {
- Log.d(TAG, " init cameraId :" + cameraId + ", i :" + i +
- ", maxPreviewSize :" + mMaxPreviewSize[i][0]+ "x" +
- mMaxPreviewSize[i][1]);
- }
- }
- } catch (CameraAccessException e) {
- e.printStackTrace();
- }
- }
-
- private void startBackgroundThread() {
- if (mCameraThread == null) {
- mCameraThread = new HandlerThread("CameraBackground");
- mCameraThread.start();
- }
- if (mCameraHandler == null) {
- mCameraHandler = new MyCameraHandler(mCameraThread.getLooper());
- }
- }
-
- private void stopBackgroundThread() {
- mCameraThread.quitSafely();
- try {
- mCameraThread.join();
- mCameraThread = null;
- mCameraHandler = null;
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
-
- private class MyCameraHandler extends Handler {
-
- public MyCameraHandler(Looper looper) {
- super(looper);
- }
-
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case WAIT_SURFACE:
- int id = msg.arg1;
- int index = mCameraIDList.indexOf(String.valueOf(id));
- Log.v(TAG, "WAIT_SURFACE id :" + id + ", index :" + index);
- if (index == -1) {
- break;
- }
- Surface surface = mMultiCameraUI.getSurfaceViewList().get(index)
- .getHolder().getSurface();
- if (surface.isValid()) {
- createCaptureSessions(id, surface);
- } else {
- mCameraHandler.sendMessageDelayed(msg, 200);
- Log.v(TAG, "Surface is invalid, wait more 200ms surfaceCreated");
- }
- break;
- case OPEN_CAMERA:
- if (mCameraListIndex == mCameraIDList.size()) {
- mCameraListIndex = 0;
- } else {
- String cameraId = mCameraIDList.get(mCameraListIndex);
- openCameraInSequence(cameraId);
- mCameraListIndex ++;
- Log.v(TAG, " OPEN_CAMERA cameraId :" + cameraId + ", mCameraListIndex :"
- + mCameraListIndex);
- }
- break;
- }
- }
- }
-
- private void createVideoSnapshotImageReader(int id) {
- if (mImageReaders[id] != null) {
- mImageReaders[id].close();
- }
- mImageReaders[id] = ImageReader.newInstance(mVideoSize[id].getWidth(),
- mVideoSize[id].getHeight(),
- ImageFormat.JPEG, /*maxImages*/2);
- mImageReaders[id].setOnImageAvailableListener(
- mOnImageAvailableListener, mMultiCameraModule.getMyCameraHandler());
- }
-
- private final CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {
-
- @Override
- public void onOpened(CameraDevice cameraDevice) {
- int id = Integer.parseInt(cameraDevice.getId());
- mCameraDevices[id] = cameraDevice;
- Log.d(TAG, "onOpened " + id);
- mCameraOpenCloseLock.release();
- createCameraPreviewSession(id);
- mActivity.runOnUiThread(new Runnable() {
- @Override
- public void run() {
- mMultiCameraUI.onCameraOpened(id);
- }
- });
- }
-
- @Override
- public void onDisconnected(CameraDevice cameraDevice) {
- int id = Integer.parseInt(cameraDevice.getId());
- Log.d(TAG, "onDisconnected " + id);
- mCameraOpenCloseLock.release();
- mCameraDevices[id] = null;
- }
-
- @Override
- public void onError(CameraDevice cameraDevice, int error) {
- int id = Integer.parseInt(cameraDevice.getId());
- Log.e(TAG, "onError " + id + " " + error);
- mCameraOpenCloseLock.release();
-
- if (null != mActivity) {
- Toast.makeText(mActivity,"open camera error id =" + id,
- Toast.LENGTH_LONG).show();
- mActivity.finish();
- }
- }
-
- @Override
- public void onClosed(CameraDevice cameraDevice) {
- int id = Integer.parseInt(cameraDevice.getId());
- Log.d(TAG, "onClosed " + id);
- mCameraOpenCloseLock.release();
- mCameraDevices[id] = null;
- }
- };
-
- private CameraCaptureSession.CaptureCallback mCaptureStillCallback
- = new CameraCaptureSession.CaptureCallback() {
-
- @Override
- public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request,
- TotalCaptureResult result) {
- Log.d(TAG, " mCaptureCallback onCaptureCompleted ");
- mMultiCameraModule.getMainHandler().post(new Runnable() {
- @Override
- public void run() {
- Log.d(TAG, " enable Shutter " );
- mMultiCameraUI.enableShutter(true);
- }
- });
- }
-
- @Override
- public void onCaptureFailed(CameraCaptureSession session,
- CaptureRequest request,
- CaptureFailure result) {
- Log.d(TAG, " mCaptureCallback onCaptureFailed " );
- }
-
-
- @Override
- public void onCaptureSequenceCompleted(CameraCaptureSession session, int
- sequenceId, long frameNumber) {
- Log.d(TAG, " mCaptureCallback onCaptureSequenceCompleted ");
- }
- };
-
- private MediaSaveService.OnMediaSavedListener mOnMediaSavedListener =
- new MediaSaveService.OnMediaSavedListener() {
- @Override
- public void onMediaSaved(Uri uri) {
- if (uri != null) {
- mActivity.notifyNewMedia(uri);
- }
- }
- };
-
- public void enableRecordingLocation(boolean enable) {
- mLocationManager.recordLocation(enable);
- }
-
- private Size parsePictureSize(String value) {
- int indexX = value.indexOf('x');
- int width = Integer.parseInt(value.substring(0, indexX));
- int height = Integer.parseInt(value.substring(indexX + 1));
- return new Size(width, height);
- }
-
- private void updateVideoSize(int id) {
- String defaultSize = mActivity.getString(R.string.pref_multi_camera_video_quality_default);
- int index = mCameraIDList.indexOf(String.valueOf(id));
- String videoSize = mLocalSharedPref.getString(
- MultiSettingsActivity.KEY_VIDEO_SIZES.get(index), defaultSize);
- Size size = parsePictureSize(videoSize);
- mVideoSize[id] = size;
- Log.v(TAG, " updateVideoSize size :" + mVideoSize[id].getWidth() + "x" +
- mVideoSize[id].getHeight());
-
- Size[] prevSizes = getSupportedOutputSize(id, MediaRecorder.class);
- mPreviewSizes[id] = getOptimalVideoPreviewSize(id, mVideoSize[id], prevSizes);
- }
-
- private Size[] getSupportedOutputSize(int cameraId, Class cl) {
- StreamConfigurationMap map = mCharacteristics.get(cameraId).get(
- CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
- Size[] normal = map.getOutputSizes(cl);
- Size[] high = map.getHighResolutionOutputSizes(ImageFormat.PRIVATE);
- Size[] ret = new Size[normal.length + high.length];
- System.arraycopy(normal, 0, ret, 0, normal.length);
- System.arraycopy(high, 0, ret, normal.length, high.length);
- return ret;
- }
-
- private Size getOptimalVideoPreviewSize(int id, Size VideoSize, Size[] prevSizes) {
- Point[] points = new Point[prevSizes.length];
-
- int index = 0;
- int point_max[] = mMaxPreviewSize[id];
- int max_size = -1;
- if (point_max != null) {
- max_size = point_max[0] * point_max[1];
- }
- for (Size s : prevSizes) {
- if (max_size != -1) {
- int size = s.getWidth() * s.getHeight();
- if (s.getWidth() == s.getHeight()) {
- if (s.getWidth() > Math.max(point_max[0], point_max[1]))
- continue;
- } else if (size > max_size || size == 0) {
- continue;
- }
- }
- points[index++] = new Point(s.getWidth(), s.getHeight());
- }
-
- int optimalPickIndex = CameraUtil.getOptimalVideoPreviewSize(mActivity, points, VideoSize);
- return (optimalPickIndex == -1) ? null :
- new Size(points[optimalPickIndex].x, points[optimalPickIndex].y);
- }
-
- /**
- * Creates a new {@link CameraCaptureSession} for camera preview.
- */
- private void createCameraPreviewSession(int id) {
- // This is the output Surface we need to start preview.
- int index = mCameraIDList.indexOf(String.valueOf(id));
- Log.v(TAG, "createCameraPreviewSession id :" + id + ", index :" + index);
- Surface surface = mMultiCameraUI.getSurfaceViewList().get(index).getHolder().getSurface();
-
- if (surface.isValid()) {
- createCaptureSessions(id, surface);
- } else {
- Message msg = Message.obtain();
- msg.what = WAIT_SURFACE;
- msg.arg1 = id;
- mCameraHandler.sendMessageDelayed(msg, 200);
- Log.v(TAG, "Surface is invalid, wait 200ms surfaceCreated");
- }
-
- }
-
- private void createCaptureSessions(int id, Surface surface) {
- try {
- // We set up a CaptureRequest.Builder with the output Surface.
- mPreviewRequestBuilders[id]
- = mCameraDevices[id].createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
- mPreviewRequestBuilders[id].addTarget(surface);
- mPreviewRequestBuilders[id].setTag(id);
-
- CameraCaptureSession.StateCallback stateCallback =
- new CameraCaptureSession.StateCallback() {
- @Override
- public void onConfigured(CameraCaptureSession cameraCaptureSession) {
- // The camera is already closed
- if (null == mCameraDevices[id]) {
- return;
- }
- Log.v(TAG, " CameraCaptureSession onConfigured id :" + id);
- // When the session is ready, we start displaying the preview.
- mCameraPreviewSessions[id] = cameraCaptureSession;
- try {
- // Auto focus should be continuous for camera preview.
- mPreviewRequestBuilders[id].set(CaptureRequest.CONTROL_AF_MODE,
- CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
- // Finally, we start displaying the camera preview.
- mCameraPreviewSessions[id].setRepeatingRequest(
- mPreviewRequestBuilders[id].build(),
- mCaptureCallback, mMultiCameraModule.getMyCameraHandler());
- } catch (CameraAccessException e) {
- e.printStackTrace();
- }
-
- if (mCameraDevices[mCameraListIndex] == null) {
- Message msg = Message.obtain();
- msg.what = OPEN_CAMERA;
- if (mCameraHandler != null) {
- mCameraHandler.sendMessage(msg);
- }
- }
- }
-
- @Override
- public void onConfigureFailed(CameraCaptureSession cameraCaptureSession) {
- showToast("onConfigureFailed");
- }
- };
-
- try {
- final byte enable = 1;
- mPreviewRequestBuilders[id].set(override_resource_cost_validation, enable);
- Log.v(TAG, " set" + override_resource_cost_validation + " is 1");
- } catch (IllegalArgumentException e) {
- e.printStackTrace();
- }
-
- List<OutputConfiguration> outConfigurations = new ArrayList<>(1);
- outConfigurations.add(new OutputConfiguration(surface));
-
- SessionConfiguration sessionConfiguration = new SessionConfiguration(
- SessionConfiguration.SESSION_REGULAR, outConfigurations,
- new HandlerExecutor(mCameraHandler), stateCallback);
- sessionConfiguration.setSessionParameters(mPreviewRequestBuilders[id].build());
- mCameraDevices[id].createCaptureSession(sessionConfiguration);
-
- } catch (CameraAccessException e) {
- e.printStackTrace();
- }
- }
-
- private class HandlerExecutor implements Executor {
- private final Handler ihandler;
-
- public HandlerExecutor(Handler handler) {
- ihandler = handler;
- }
-
- @Override
- public void execute(Runnable runCmd) {
- ihandler.post(runCmd);
- }
- }
-
- /**
- * A {@link CameraCaptureSession.CaptureCallback} that handles events related to JPEG capture.
- */
- private CameraCaptureSession.CaptureCallback mCaptureCallback
- = new CameraCaptureSession.CaptureCallback() {
-
- private void process(CaptureResult result) {
- Integer afState = result.get(CaptureResult.CONTROL_AF_STATE);
- Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);
- if (DEBUG) {
- Log.v(TAG, "process afState :" + afState + ", aeState :" + aeState);
- }
- }
-
- @Override
- public void onCaptureProgressed(CameraCaptureSession session, CaptureRequest request,
- CaptureResult partialResult) {
- process(partialResult);
- }
-
- @Override
- public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request,
- TotalCaptureResult result) {
- process(result);
- }
-
- };
-
- private final ImageReader.OnImageAvailableListener mOnImageAvailableListener
- = new ImageReader.OnImageAvailableListener() {
-
- @Override
- public void onImageAvailable(ImageReader reader) {
- Log.v(TAG, " onImageAvailable ...");
- Image image = reader.acquireNextImage();
- long imageTime = System.currentTimeMillis();
- mNamedImages.nameNewImage(imageTime);
- NamedEntity name = mNamedImages.getNextNameEntity();
- String title = (name == null) ? null : name.title;
- long date = (name == null) ? -1 : name.date;
-
- ByteBuffer buffer = image.getPlanes()[0].getBuffer();
- byte[] bytes = new byte[buffer.remaining()];
- buffer.get(bytes);
-
- int orientation = 0;
- ExifInterface exif = Exif.getExif(bytes);
- orientation = Exif.getOrientation(exif);
- String saveFormat = "jpeg";
- mActivity.getMediaSaveService().addImage(bytes, title, date,
- null, image.getWidth(), image.getHeight(), orientation, exif,
- mOnMediaSavedListener, mContentResolver, saveFormat);
- mActivity.updateThumbnail(bytes);
- image.close();
- mMultiCameraModule.updateTakingPicture();
- }
- };
-
- private void initializeValues() {
- updateAudioEncoder();
- updateVideoRotation();
- }
-
- private void checkAndPlayShutterSound(boolean isStarted) {
- if (mSoundPlayer != null) {
- mSoundPlayer.play(isStarted? SoundClips.STOP_VIDEO_RECORDING
- : SoundClips.START_VIDEO_RECORDING);
- }
- }
-
- private void checkAndPlayCaptureSound() {
- if (mSoundPlayer != null) {
- mSoundPlayer.play(SoundClips.SHUTTER_CLICK);
- }
- }
-
- private void closePreviewSession(int id) {
- if (mCameraPreviewSessions[id] != null) {
- Log.v(TAG, "closePreviewSession id :" + id);
- mCameraPreviewSessions[id].close();
- mCameraPreviewSessions[id] = null;
- }
- }
-
- private void startRecordingVideo(final int id) {
- int index = mCameraIDList.indexOf(String.valueOf(id));
- if (null == mCameraDevices[id] ||
- !mMultiCameraUI.getSurfaceViewList().get(index).isEnabled()) {
- return;
- }
- Log.v(TAG, " startRecordingVideo " + id);
- try {
- closePreviewSession(id);
- setUpMediaRecorder(id);
- createVideoSnapshotImageReader(id);
- mPreviewRequestBuilders[id] = mCameraDevices[id].createCaptureRequest(
- CameraDevice.TEMPLATE_RECORD);
- if (true) {
- mPreviewRequestBuilders[id].set(CaptureRequest.NOISE_REDUCTION_MODE,
- CaptureRequest.NOISE_REDUCTION_MODE_FAST);
- } else {
- mPreviewRequestBuilders[id].set(CaptureRequest.NOISE_REDUCTION_MODE,
- CaptureRequest.NOISE_REDUCTION_MODE_HIGH_QUALITY);
- }
- List<Surface> surfaces = new ArrayList<>();
-
- // Set up Surface for the camera preview
- Surface previewSurface = mMultiCameraUI.getSurfaceViewList().get(index).getHolder()
- .getSurface();
- surfaces.add(previewSurface);
- mPreviewRequestBuilders[id].addTarget(previewSurface);
-
- // Set up Surface for the MediaRecorder
- Surface recorderSurface = mMediaRecorders[id].getSurface();
- surfaces.add(recorderSurface);
- mPreviewRequestBuilders[id].addTarget(recorderSurface);
- surfaces.add(mImageReaders[id].getSurface());
-
- // Start a capture session
- // Once the session starts, we can update the UI and start recording
- mCameraDevices[id].createCaptureSession(surfaces, new CameraCaptureSession.StateCallback() {
-
- @Override
- public void onConfigured(CameraCaptureSession cameraCaptureSession) {
- mCameraPreviewSessions[id] = cameraCaptureSession;
- updatePreview(id);
- mActivity.runOnUiThread(new Runnable() {
- @Override
- public void run() {
- mIsRecordingVideos[id] = true;
- // Start recording
- mMediaRecorders[id].start();
- requestAudioFocus();
- mRecordingTotalTime = 0L;
- mRecordingStartTime = SystemClock.uptimeMillis();
- mMediaRecorderPausing = false;
- mMultiCameraUI.resetPauseButton();
- mMultiCameraUI.showRecordingUI(true);
- updateRecordingTime(id);
- keepScreenOn();
- Log.v(TAG, " startRecordingVideo done " + id);
- }
- });
- }
-
- @Override
- public void onConfigureFailed(CameraCaptureSession cameraCaptureSession) {
- if (null != mActivity) {
- Toast.makeText(mActivity, "Configure Failed", Toast.LENGTH_SHORT).show();
- }
- }
- }, mMultiCameraModule.getMyCameraHandler());
- } catch (CameraAccessException | IllegalStateException | IOException e) {
- e.printStackTrace();
- }
- }
-
- public void stopRecordingVideo(int id) {
- Log.v(TAG, " stopRecordingVideo " + id);
- mIsRecordingVideos[id] = false;
- try {
- mMediaRecorders[id].setOnErrorListener(null);
- mMediaRecorders[id].setOnInfoListener(null);
- // Stop recording
- mMediaRecorders[id].stop();
- mMediaRecorders[id].reset();
- saveVideo(id);
- keepScreenOnAwhile();
- // release media recorder
- releaseMediaRecorder(id);
- releaseAudioFocus();
- } catch (RuntimeException e) {
- Log.w(TAG, "MediaRecoder stop fail", e);
- if (mVideoFilenames[id] != null) deleteVideoFile(mVideoFilenames[id]);
- }
-
- mMultiCameraUI.showRecordingUI(false);
- if (null != mActivity) {
- Toast.makeText(mActivity, "Video saved: " + mNextVideoAbsolutePaths[id],
- Toast.LENGTH_SHORT).show();
- Log.d(TAG, "Video saved: " + mNextVideoAbsolutePaths[id]);
- }
- mNextVideoAbsolutePaths[id] = null;
- if(!mPaused) {
- createCameraPreviewSession(id);
- }
- }
-
- private final MediaSaveService.OnMediaSavedListener mOnVideoSavedListener =
- new MediaSaveService.OnMediaSavedListener() {
- @Override
- public void onMediaSaved(Uri uri) {
- if (uri != null) {
- mActivity.notifyNewMedia(uri);
- mCurrentVideoUri = uri;
- }
- }
- };
-
- private void keepScreenOn() {
- mMultiCameraModule.getMainHandler().removeMessages(MultiCameraModule.CLEAR_SCREEN_DELAY);
- mActivity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
- }
-
- private void keepScreenOnAwhile() {
- mMultiCameraModule.getMainHandler().removeMessages(MultiCameraModule.CLEAR_SCREEN_DELAY);
- mActivity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
- mMultiCameraModule.getMainHandler().sendEmptyMessageDelayed(
- MultiCameraModule.CLEAR_SCREEN_DELAY, SCREEN_DELAY);
- }
-
- private void releaseMediaRecorder(int id) {
- Log.v(TAG, "Releasing media recorder.");
- cleanupEmptyFile(id);
- if (mMediaRecorders[id] != null) {
- try{
- mMediaRecorders[id].reset();
- mMediaRecorders[id].release();
- }catch (RuntimeException e) {
- e.printStackTrace();
- }
- mMediaRecorders[id] = null;
- }
- }
-
- /*
- * Make sure we're not recording music playing in the background, ask the
- * MediaPlaybackService to pause playback.
- */
- private void requestAudioFocus() {
- AudioManager am = (AudioManager)mActivity.getSystemService(Context.AUDIO_SERVICE);
- // Send request to obtain audio focus. This will stop other
- // music stream.
- int result = am.requestAudioFocus(null, AudioManager.STREAM_MUSIC,
- AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
- if (result == AudioManager.AUDIOFOCUS_REQUEST_FAILED) {
- Log.v(TAG, "Audio focus request failed");
- }
- }
-
- private void releaseAudioFocus() {
- AudioManager am = (AudioManager)mActivity.getSystemService(Context.AUDIO_SERVICE);
- int result = am.abandonAudioFocus(null);
- if (result == AudioManager.AUDIOFOCUS_REQUEST_FAILED) {
- Log.v(TAG, "Audio focus release failed");
- }
- }
-
- private void cleanupEmptyFile(int id) {
- if (mVideoFilenames[id] != null) {
- File f = new File(mVideoFilenames[id]);
- if (f.length() == 0 && f.delete()) {
- Log.v(TAG, "Empty video file deleted: " + mVideoFilenames[id]);
- mVideoFilenames[id] = null;
- }
- }
- }
-
- private void updateAudioEncoder() {
- String audioEncoderStr = mActivity.getResources().getString(
- R.string.pref_camera_audioencoder_default);
- if (mLocalSharedPref != null) {
- audioEncoderStr = mLocalSharedPref.getString(MultiSettingsActivity.KEY_AUDIO_ENCODER,
- audioEncoderStr);
- }
- mAudioEncoder = SettingTranslation.getAudioEncoder(audioEncoderStr);
- }
-
- private void updateVideoRotation() {
- String defaultValue = mActivity.getResources().getString(
- R.string.pref_camera_video_rotation_default);
- if (mLocalSharedPref != null) {
- mVideoRotation = mLocalSharedPref.getString(MultiSettingsActivity.KEY_VIDEO_ROTATION,
- defaultValue);
- }
- }
-
- private void deleteVideoFile(String fileName) {
- Log.v(TAG, "Deleting video " + fileName);
- File f = new File(fileName);
- if (!f.delete()) {
- Log.v(TAG, "Could not delete " + fileName);
- }
- }
-
- private void saveVideo(int id) {
- File origFile = new File(mVideoFilenames[id]);
- if (!origFile.exists() || origFile.length() <= 0) {
- Log.e(TAG, "Invalid file");
- mCurrentVideoValues[id] = null;
- return;
- }
-
- long duration = 0L;
- MediaMetadataRetriever retriever = new MediaMetadataRetriever();
- try {
- retriever.setDataSource(mVideoFilenames[id]);
- duration = Long.valueOf(retriever.extractMetadata(
- MediaMetadataRetriever.METADATA_KEY_DURATION));
- } catch (IllegalArgumentException e) {
- Log.e(TAG, "cannot access the file");
- }
- retriever.release();
- mActivity.getMediaSaveService().addVideo(mVideoFilenames[id],
- duration, mCurrentVideoValues[id],
- mOnVideoSavedListener, mContentResolver);
- Log.v(TAG, "saveVideo mVideoFilenames[id] :" + mVideoFilenames[id]);
- mCurrentVideoValues[id] = null;
- }
-
- private void updateRecordingTime(int id) {
- if (!mIsRecordingVideos[id] || id == 0) {
- return;
- }
-
- if (mMediaRecorderPausing) {
- return;
- }
-
- long now = SystemClock.uptimeMillis();
- long delta = now - mRecordingStartTime + mRecordingTotalTime;
-
- // Starting a minute before reaching the max duration
- // limit, we'll countdown the remaining time instead.
- boolean countdownRemainingTime = (mMaxVideoDurationInMs != 0
- && delta >= mMaxVideoDurationInMs - 60000);
-
- long deltaAdjusted = delta;
- if (countdownRemainingTime) {
- deltaAdjusted = Math.max(0, mMaxVideoDurationInMs - deltaAdjusted) + 999;
- }
- String text;
- long targetNextUpdateDelay;
- if (!mCaptureTimeLapse) {
- text = CameraUtil.millisecondToTimeString(deltaAdjusted, false);
- targetNextUpdateDelay = 1000;
- } else {
- // The length of time lapse video is different from the length
- // of the actual wall clock time elapsed. Display the video length
- // only in format hh:mm:ss.dd, where dd are the centi seconds.
- text = CameraUtil.millisecondToTimeString(getTimeLapseVideoLength(delta), true);
- targetNextUpdateDelay = mTimeBetweenTimeLapseFrameCaptureMs;
- }
- mMultiCameraUI.setRecordingTime(text);
- if (mRecordingTimeCountsDown != countdownRemainingTime) {
- // Avoid setting the color on every update, do it only
- // when it needs changing.
- mRecordingTimeCountsDown = countdownRemainingTime;
-
- int color = mActivity.getResources().getColor(countdownRemainingTime
- ? R.color.recording_time_remaining_text
- : R.color.recording_time_elapsed_text);
-
- mMultiCameraUI.setRecordingTimeTextColor(color);
- }
- long actualNextUpdateDelay = targetNextUpdateDelay - (delta % targetNextUpdateDelay);
- mMultiCameraModule.getMainHandler().postDelayed(new Runnable() {
- @Override
- public void run() {
- updateRecordingTime(id);
- }
- }, actualNextUpdateDelay);
- }
-
- private long getTimeLapseVideoLength(long deltaMs) {
- // For better approximation calculate fractional number of frames captured.
- // This will update the video time at a higher resolution.
- double numberOfFrames = (double) deltaMs / mTimeBetweenTimeLapseFrameCaptureMs;
- return (long) (numberOfFrames / mProfile.videoFrameRate * 1000);
- }
-
- /**
- * Update the camera preview. {@link #startPreview()} needs to be called in advance.
- */
- private void updatePreview(int id) {
- if (null == mCameraDevices[id]) {
- return;
- }
- try {
- setUpCaptureRequestBuilder(mPreviewRequestBuilders[id]);
- mCameraPreviewSessions[id].setRepeatingRequest(mPreviewRequestBuilders[id].build(),
- null, mMultiCameraModule.getMyCameraHandler());
- } catch (CameraAccessException e) {
- e.printStackTrace();
- }
- }
-
- private void setUpCaptureRequestBuilder(CaptureRequest.Builder builder) {
- builder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);
- }
-
- private String generateVideoFilename(int outputFileFormat, int id) {
- long dateTaken = System.currentTimeMillis();
- String title = createName(dateTaken);
- String filename = title + "_"+ id + CameraUtil.convertOutputFormatToFileExt(outputFileFormat);
- String mime = CameraUtil.convertOutputFormatToMimeType(outputFileFormat);
- String path = Storage.DIRECTORY + '/' + filename;
- mCurrentVideoValues[id] = new ContentValues(9);
- mCurrentVideoValues[id].put(MediaStore.Video.Media.TITLE, title);
- mCurrentVideoValues[id].put(MediaStore.Video.Media.DISPLAY_NAME, filename);
- mCurrentVideoValues[id].put(MediaStore.Video.Media.DATE_TAKEN, dateTaken);
- mCurrentVideoValues[id].put(MediaStore.MediaColumns.DATE_MODIFIED, dateTaken / 1000);
- mCurrentVideoValues[id].put(MediaStore.Video.Media.MIME_TYPE, mime);
- mCurrentVideoValues[id].put(MediaStore.Video.Media.DATA, path);
- mCurrentVideoValues[id].put(MediaStore.Video.Media.RESOLUTION,
- "" + mVideoSize[id].getWidth() + "x" + mVideoSize[id].getHeight());
- Location loc = mLocationManager.getCurrentLocation();
- if (loc != null) {
- mCurrentVideoValues[id].put(MediaStore.Video.Media.LATITUDE, loc.getLatitude());
- mCurrentVideoValues[id].put(MediaStore.Video.Media.LONGITUDE, loc.getLongitude());
- }
- mVideoFilenames[id] = path;
- return path;
- }
-
- private String createName(long dateTaken) {
- Date date = new Date(dateTaken);
- SimpleDateFormat dateFormat = new SimpleDateFormat(
- mActivity.getString(R.string.video_file_name_format));
- return dateFormat.format(date);
- }
-
- private void setUpMediaRecorder(int id) throws IOException {
- if (null == mActivity) {
- return;
- }
- Log.v(TAG, " setUpMediaRecorder " + id);
- int size = CameraSettings.VIDEO_QUALITY_TABLE.get(mVideoSize[id].getWidth() + "x"
- + mVideoSize[id].getHeight());
- if (CamcorderProfile.hasProfile(id, size)) {
- mProfile = CamcorderProfile.get(id, size);
- } else {
- warningToast(R.string.error_app_unsupported_profile);
- throw new IllegalArgumentException("error_app_unsupported_profile");
- }
-
- if (mMediaRecorders[id] == null) {
- mMediaRecorders[id] = new MediaRecorder();
- }
- mMediaRecorders[id].setAudioSource(MediaRecorder.AudioSource.MIC);
- mMediaRecorders[id].setVideoSource(MediaRecorder.VideoSource.SURFACE);
- mMediaRecorders[id].setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
- if (mNextVideoAbsolutePaths[id] == null || mNextVideoAbsolutePaths[id].isEmpty()) {
- mNextVideoAbsolutePaths[id] = generateVideoFilename(mProfile.fileFormat, id);
- }
-
- mMediaRecorders[id].setMaxDuration(mMaxVideoDurationInMs);
- mMediaRecorders[id].setOutputFile(mNextVideoAbsolutePaths[id]);
- mMediaRecorders[id].setVideoEncodingBitRate(10000000);
- mMediaRecorders[id].setVideoFrameRate(30);
- mMediaRecorders[id].setVideoSize(mVideoSize[id].getWidth(), mVideoSize[id].getHeight());
- mMediaRecorders[id].setVideoEncoder(MediaRecorder.VideoEncoder.H264);
- mMediaRecorders[id].setAudioEncoder(mAudioEncoder);
- int rotation = CameraUtil.getJpegRotation(id, mOrientation);
- if (mVideoRotation != null) {
- rotation += Integer.parseInt(mVideoRotation);
- rotation = rotation % 360;
- }
- mMediaRecorders[id].setOrientationHint(rotation);
- mMediaRecorders[id].prepare();
- mMediaRecorders[id].setOnErrorListener(this);
- mMediaRecorders[id].setOnInfoListener(this);
- }
-
- private void warningToast(final String msg) {
- mActivity.runOnUiThread(new Runnable() {
- public void run() {
- RotateTextToast.makeText(mActivity, msg,
- Toast.LENGTH_SHORT).show();
- }
- });
- }
-
- private void warningToast(final int sourceId) {
- warningToast(sourceId, true);
- }
-
- private void warningToast(final int sourceId, boolean isLongShow) {
- mActivity.runOnUiThread(new Runnable() {
- public void run() {
- RotateTextToast.makeText(mActivity, sourceId,
- isLongShow ? Toast.LENGTH_LONG : Toast.LENGTH_SHORT).show();
- }
- });
- }
-
- /**
- * Shows a {@link Toast} on the UI thread.
- * @param text The message to show
- */
- private void showToast(final String text) {
- if (mActivity != null) {
- mActivity.runOnUiThread(new Runnable() {
- @Override
- public void run() {
- Toast.makeText(mActivity, text, Toast.LENGTH_SHORT).show();
- }
- });
- }
- }
-}
+/*
+ * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.camera.multi;
+
+import android.content.Context;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.SharedPreferences;
+import android.graphics.Bitmap;
+import android.graphics.ImageFormat;
+import android.graphics.Point;
+import android.hardware.camera2.CameraAccessException;
+import android.hardware.camera2.CameraCaptureSession;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraDevice;
+import android.hardware.camera2.CaptureFailure;
+import android.hardware.camera2.CameraManager;
+import android.hardware.camera2.CameraMetadata;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureResult;
+import android.hardware.camera2.TotalCaptureResult;
+import android.hardware.camera2.params.OutputConfiguration;
+import android.hardware.camera2.params.SessionConfiguration;
+import android.hardware.camera2.params.StreamConfigurationMap;
+import android.location.Location;
+import android.media.AudioManager;
+import android.media.CamcorderProfile;
+import android.media.Image;
+import android.media.ImageReader;
+import android.media.MediaRecorder;
+import android.media.MediaMetadataRetriever;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.Message;
+import android.os.SystemClock;
+import android.os.ParcelFileDescriptor;
+import android.provider.MediaStore;
+import android.util.Log;
+import android.util.Size;
+import android.view.OrientationEventListener;
+import android.util.SparseIntArray;
+import android.view.Surface;
+import android.view.SurfaceHolder;
+import android.view.WindowManager;
+import android.widget.Toast;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.text.SimpleDateFormat;
+import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.concurrent.Executor;
+import java.util.List;
+import java.util.Date;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+
+import com.android.camera.CameraActivity;
+import com.android.camera.CaptureModule;
+import com.android.camera.CameraSettings;
+import com.android.camera.ComboPreferences;
+import com.android.camera.Exif;
+import com.android.camera.exif.ExifInterface;
+import com.android.camera.LocationManager;
+import com.android.camera.MediaSaveService;
+import com.android.camera.PhotoModule.NamedImages;
+import com.android.camera.PhotoModule.NamedImages.NamedEntity;
+import com.android.camera.SDCard;
+import com.android.camera.SoundClips;
+import com.android.camera.Storage;
+import com.android.camera.Thumbnail;
+import com.android.camera.util.CameraUtil;
+import com.android.camera.util.SettingTranslation;
+import com.android.camera.util.PersistUtil;
+import com.android.camera.ui.RotateTextToast;
+
+import org.codeaurora.snapcam.R;
+
+public class MultiVideoModule implements MultiCamera, LocationManager.Listener,
+ MediaRecorder.OnErrorListener, MediaRecorder.OnInfoListener {
+
+ private static final String TAG = "SnapCam_MultiVideoModule";
+
+ private static final boolean DEBUG =
+ (PersistUtil.getCamera2Debug() == PersistUtil.CAMERA2_DEBUG_DUMP_LOG) ||
+ (PersistUtil.getCamera2Debug() == PersistUtil.CAMERA2_DEBUG_DUMP_ALL);
+
+ private static final int SENSOR_ORIENTATION_DEFAULT_DEGREES = 90;
+ private static final int SENSOR_ORIENTATION_INVERSE_DEGREES = 270;
+ private static final SparseIntArray DEFAULT_ORIENTATIONS = new SparseIntArray();
+ private static final SparseIntArray INVERSE_ORIENTATIONS = new SparseIntArray();
+
+ private static final int WAIT_SURFACE = 0;
+ private static final int OPEN_CAMERA = 1;
+
+ private static final int SCREEN_DELAY = 2 * 60 * 1000;
+
+ private static final int MAX_NUM_CAM = 16;
+
+ private int mCameraListIndex = 0;
+
+ private static final CaptureRequest.Key<Byte> override_resource_cost_validation =
+ new CaptureRequest.Key<>(
+ "org.codeaurora.qcamera3.sessionParameters.overrideResourceCostValidation",
+ byte.class);
+
+ private CameraActivity mActivity;
+ private MultiCameraUI mMultiCameraUI;
+ private MultiCameraModule mMultiCameraModule;
+ private SharedPreferences mLocalSharedPref;
+ private ArrayList<CameraCharacteristics> mCharacteristics;
+ private CameraDevice[] mCameraDevices = new CameraDevice[MAX_NUM_CAM];
+ private CameraCaptureSession[] mCameraPreviewSessions = new CameraCaptureSession[MAX_NUM_CAM];
+ private ContentValues[] mCurrentVideoValues = new ContentValues[MAX_NUM_CAM];
+ private ImageReader[] mImageReaders = new ImageReader[MAX_NUM_CAM];
+ private MediaRecorder[] mMediaRecorders = new MediaRecorder[MAX_NUM_CAM];
+ private String[] mNextVideoAbsolutePaths = new String[MAX_NUM_CAM];
+ private boolean mPaused = true;
+
+ private NamedImages mNamedImages;
+
+ private Uri mCurrentVideoUri;
+
+ private boolean mMediaRecorderPausing = false;
+
+ private boolean mRecordingTimeCountsDown = false;
+
+ private LocationManager mLocationManager;
+ private CamcorderProfile mProfile;
+
+ private Size[] mVideoSize = new Size[MAX_NUM_CAM];
+ private Size mPreviewSizes[] = new Size[MAX_NUM_CAM];
+ private int[][] mMaxPreviewSize = new int[MAX_NUM_CAM][];
+
+ private boolean mCaptureTimeLapse = false;
+ // Default 0. If it is larger than 0, the camcorder is in time lapse mode.
+ private int mTimeBetweenTimeLapseFrameCaptureMs = 0;
+
+ private String[] mVideoFilenames = new String[MAX_NUM_CAM];
+
+ private long mRecordingStartTime;
+ private long mRecordingTotalTime;
+
+ private ParcelFileDescriptor mVideoFileDescriptor;
+
+ // The video duration limit. 0 means no limit.
+ private int mMaxVideoDurationInMs;
+
+ private int mAudioEncoder;
+ private String mVideoRotation;
+
+ private SoundClips.Player mSoundPlayer;
+
+ /**
+ * Whether the app is recording video now
+ */
+ private boolean[] mIsRecordingVideos = new boolean[MAX_NUM_CAM];
+
+ private String[] mCameraIds;
+ private ArrayList<String> mCameraIDList = new ArrayList<>();
+
+ /**
+ * Orientation of the camera sensor
+ */
+ private int mSensorOrientation;
+ private int mOrientation = OrientationEventListener.ORIENTATION_UNKNOWN;
+
+ /**
+ * {@link CaptureRequest.Builder} for the camera preview
+ */
+ private CaptureRequest.Builder[] mPreviewRequestBuilders = new CaptureRequest.Builder[MAX_NUM_CAM];
+
+ private Handler mCameraHandler;
+ private HandlerThread mCameraThread;
+
+ private ContentResolver mContentResolver;
+ /**
+ * A {@link Semaphore} make sure the camera open callback happens first before closing the
+ * camera.
+ */
+ private Semaphore mCameraOpenCloseLock = new Semaphore(3);
+
+ public MultiVideoModule(CameraActivity activity, MultiCameraUI ui, MultiCameraModule module) {
+ mActivity = activity;
+ mMultiCameraUI = ui;
+ mMultiCameraModule = module;
+ mContentResolver = mActivity.getContentResolver();
+ mLocationManager = new LocationManager(mActivity, this);
+ mNamedImages = new NamedImages();
+ mLocalSharedPref = mActivity.getSharedPreferences(
+ ComboPreferences.getLocalSharedPreferencesName(mActivity,
+ "multi" + mMultiCameraModule.getCurrenCameraMode()), Context.MODE_PRIVATE);
+ startBackgroundThread();
+ initCameraCharacteristics();
+ }
+
+ @Override
+ public void onResume(String[] ids) {
+ for (String id : ids) {
+ mCameraIDList.add(id);
+ }
+ // Set up sound playback for video record and video stop
+ if (mSoundPlayer == null) {
+ mSoundPlayer = SoundClips.getPlayer(mActivity);
+ }
+ mPaused = false;
+ initializeValues();
+ startBackgroundThread();
+ for (String id : ids) {
+ int cameraId = Integer.parseInt(id);
+ updateVideoSize(cameraId);
+ int index = mCameraIDList.indexOf(id);
+ mMultiCameraUI.setPreviewSize(index, mPreviewSizes[cameraId].getWidth(),
+ mPreviewSizes[cameraId].getHeight());
+ }
+ }
+
+ @Override
+ public void onPause() {
+ mPaused = true;
+ if (mSoundPlayer != null) {
+ mSoundPlayer.release();
+ mSoundPlayer = null;
+ }
+ for (String id : mCameraIds) {
+ int cameraId = Integer.parseInt(id);
+ Log.d(TAG, " onPause id :" + cameraId + " recording is :" +
+ (mIsRecordingVideos[cameraId] ? "STOPED" : "START"));
+ if (mIsRecordingVideos[cameraId]) {
+ stopRecordingVideo(cameraId);
+ }
+ }
+
+ if (mCameraIDList != null) {
+ mCameraIDList.clear();
+ }
+ mCameraListIndex = 0;
+ closeCamera();
+ stopBackgroundThread();
+ }
+
+ @Override
+ public boolean openCamera(String[] ids) {
+ mCameraIds = ids;
+ for (String id : ids) {
+ mCameraIDList.add(id);
+ }
+ Message msg = Message.obtain();
+ msg.what = OPEN_CAMERA;
+ if (mCameraHandler != null) {
+ mCameraHandler.sendMessage(msg);
+ }
+ return true;
+ }
+
+ @Override
+ public void startPreview() {
+
+ }
+
+ @Override
+ public void closeSession() {
+
+ }
+
+ @Override
+ public void closeCamera() {
+ Log.d(TAG, "closeCamera");
+ /* no need to set this in the callback and handle asynchronously. This is the same
+ reason as why we release the semaphore here, not in camera close callback function
+ as we don't have to protect the case where camera open() gets called during camera
+ close(). The low level framework/HAL handles the synchronization for open()
+ happens after close() */
+ try {
+ // Close camera starting with AUX first
+ for (int i = MAX_NUM_CAM - 1; i >= 0; i--) {
+ if (null != mCameraDevices[i]) {
+ if (!mCameraOpenCloseLock.tryAcquire(2000, TimeUnit.MILLISECONDS)) {
+ Log.d(TAG, "Time out waiting to lock camera closing.");
+ throw new RuntimeException("Time out waiting to lock camera closing");
+ }
+ Log.d(TAG, "Closing camera: " + mCameraDevices[i].getId());
+ mCameraDevices[i].close();
+ mCameraDevices[i] = null;
+ mCameraPreviewSessions[i] = null;
+ }
+ if (null != mImageReaders[i]) {
+ mImageReaders[i].close();
+ mImageReaders[i] = null;
+ }
+ }
+ } catch (InterruptedException e) {
+ mCameraOpenCloseLock.release();
+ throw new RuntimeException("Interrupted while trying to lock camera closing.", e);
+ } catch (IllegalStateException e) {
+ e.printStackTrace();
+ } finally {
+ mCameraOpenCloseLock.release();
+ }
+ }
+
+ @Override
+ public void onVideoButtonClick(String[] ids) {
+ checkAndPlayShutterSound(mIsRecordingVideos[0]);
+ for (String id : ids) {
+ int cameraId = Integer.parseInt(id);
+ Log.d(TAG, " onVideoButtonClick id :" + cameraId + " recording is :" +
+ (mIsRecordingVideos[cameraId] ? "STOPED" : "START"));
+ if (mIsRecordingVideos[cameraId]) {
+ stopRecordingVideo(cameraId);
+ } else {
+ startRecordingVideo(cameraId);
+ }
+ }
+ }
+
+ @Override
+ public void onShutterButtonClick(String[] ids) {
+ checkAndPlayCaptureSound();
+ mMultiCameraUI.enableShutter(false);
+ for (String id : ids) {
+ Log.d(TAG, "onShutterButtonClick id :" + id);
+ try {
+ int cameraId = Integer.parseInt(id);
+ if (null == mActivity || null == mCameraDevices[cameraId]) {
+ warningToast("Camera is not ready yet to take a video snapshot.");
+ return;
+ }
+ final CaptureRequest.Builder captureBuilder =
+ mCameraDevices[cameraId].createCaptureRequest(
+ CameraDevice.TEMPLATE_VIDEO_SNAPSHOT);
+ captureBuilder.addTarget(mImageReaders[cameraId].getSurface());
+ int index = mCameraIDList.indexOf(String.valueOf(cameraId));
+ captureBuilder.addTarget(mMultiCameraUI.getSurfaceViewList().get(
+ index).getHolder().getSurface());
+ // Use the same AE and AF modes as the preview.
+ captureBuilder.set(CaptureRequest.CONTROL_AF_MODE,
+ CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
+ captureBuilder.set(CaptureRequest.JPEG_THUMBNAIL_QUALITY, (byte) 80);
+ captureBuilder.set(CaptureRequest.CONTROL_MODE, CaptureRequest.CONTROL_MODE_AUTO);
+ captureBuilder.set(CaptureRequest.CONTROL_AE_MODE,
+ CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
+
+ // Orientation
+ int rotation = mActivity.getWindowManager().getDefaultDisplay().getRotation();
+ captureBuilder.set(CaptureRequest.JPEG_ORIENTATION,
+ CameraUtil.getJpegRotation(cameraId, rotation));
+ mCameraPreviewSessions[cameraId].capture(captureBuilder.build(),
+ mCaptureStillCallback, mMultiCameraModule.getMyCameraHandler());
+ Log.d(TAG, " cameraCaptureSession" + id + " captured ");
+ } catch (CameraAccessException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ @Override
+ public void onButtonPause(String[] ids) {
+ mRecordingTotalTime += SystemClock.uptimeMillis() - mRecordingStartTime;
+ mMediaRecorderPausing = true;
+ for (String id : ids) {
+ int cameraId = Integer.parseInt(id);
+ mMediaRecorders[cameraId].pause();
+ }
+ }
+
+ @Override
+ public void onButtonContinue(String[] ids) {
+ mMediaRecorderPausing = false;
+ for (String id : ids) {
+ int cameraId = Integer.parseInt(id);
+ mMediaRecorders[cameraId].resume();
+ mRecordingStartTime = SystemClock.uptimeMillis();
+ updateRecordingTime(cameraId);
+ }
+ }
+
+ @Override
+ public void onErrorListener(int error) {
+ enableRecordingLocation(false);
+ }
+
+ // from MediaRecorder.OnErrorListener
+ @Override
+ public void onError(MediaRecorder mr, int what, int extra) {
+ Log.e(TAG, "MediaRecorder error. what=" + what + ". extra=" + extra);
+ String[] ids = {"0", "1"};
+ for (String id : ids) {
+ int cameraId = Integer.parseInt(id);
+ stopRecordingVideo(cameraId);
+ }
+ if (what == MediaRecorder.MEDIA_RECORDER_ERROR_UNKNOWN) {
+ // We may have run out of space on the sdcard.
+ mActivity.updateStorageSpaceAndHint();
+ } else {
+ warningToast("MediaRecorder error. what=" + what + ". extra=" + extra);
+ }
+ }
+
+ // from MediaRecorder.OnInfoListener
+ @Override
+ public void onInfo(MediaRecorder mr, int what, int extra) {
+ String[] ids = {"0", "1"};
+ if (what == MediaRecorder.MEDIA_RECORDER_INFO_MAX_DURATION_REACHED) {
+ for (String id : ids) {
+ int cameraId = Integer.parseInt(id);
+ if (mIsRecordingVideos[cameraId]) {
+ stopRecordingVideo(cameraId);
+ }
+ }
+ } else if (what == MediaRecorder.MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED) {
+ for (String id : ids) {
+ int cameraId = Integer.parseInt(id);
+ if (mIsRecordingVideos[cameraId]) {
+ stopRecordingVideo(cameraId);
+ }
+ }
+ // Show the toast.
+ RotateTextToast.makeText(mActivity, R.string.video_reach_size_limit,
+ Toast.LENGTH_LONG).show();
+ }
+ }
+
+ @Override
+ public void onOrientationChanged(int orientation) {
+ mOrientation = orientation;
+ }
+
+ @Override
+ public boolean isRecordingVideo() {
+ for (int i = 0; i < mIsRecordingVideos.length; i++) {
+ if (mIsRecordingVideos[i]) return true;
+ }
+ return false;
+ }
+
+ private void openCameraInSequence(String id) {
+ CameraManager manager = (CameraManager) mActivity.getSystemService(Context.CAMERA_SERVICE);
+ CameraCharacteristics characteristics = null;
+ try {
+ characteristics = manager.getCameraCharacteristics(id);
+ } catch (CameraAccessException e) {
+ e.printStackTrace();
+ }
+ mSensorOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
+ Log.d(TAG, "openCameraInSequence " + id + ", mSensorOrientation :" + mSensorOrientation);
+ try {
+ if (!mCameraOpenCloseLock.tryAcquire(5000, TimeUnit.MILLISECONDS)) {
+ Log.d(TAG, "Time out waiting to lock camera opening.");
+ throw new RuntimeException("Time out waiting to lock camera opening");
+ }
+ manager.openCamera(id, mStateCallback, mMultiCameraModule.getMyCameraHandler());
+ } catch (CameraAccessException e) {
+ e.printStackTrace();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ manager = null;
+ characteristics = null;
+ }
+
+ private void initCameraCharacteristics() {
+ mCharacteristics = new ArrayList<>();
+ CameraManager manager = (CameraManager) mActivity.getSystemService(Context.CAMERA_SERVICE);
+ try {
+ String[] cameraIdList = manager.getCameraIdList();
+ Log.d(TAG, "cameraIdList size =" + cameraIdList.length);
+ for (int i = 0; i < cameraIdList.length; i++) {
+ String cameraId = cameraIdList[i];
+ CameraCharacteristics characteristics
+ = manager.getCameraCharacteristics(cameraId);
+ mCharacteristics.add(i, characteristics);
+ try {
+ mMaxPreviewSize[i] = characteristics.get(CaptureModule.max_preview_size);
+ } catch (IllegalArgumentException e) {
+ Log.e(TAG, "getMaxPreviewSize no vendorTag max_preview_size:");
+ }
+ if (mMaxPreviewSize[i] != null) {
+ Log.d(TAG, " init cameraId :" + cameraId + ", i :" + i +
+ ", maxPreviewSize :" + mMaxPreviewSize[i][0]+ "x" +
+ mMaxPreviewSize[i][1]);
+ }
+ }
+ } catch (CameraAccessException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private void startBackgroundThread() {
+ if (mCameraThread == null) {
+ mCameraThread = new HandlerThread("CameraBackground");
+ mCameraThread.start();
+ }
+ if (mCameraHandler == null) {
+ mCameraHandler = new MyCameraHandler(mCameraThread.getLooper());
+ }
+ }
+
+ private void stopBackgroundThread() {
+ mCameraThread.quitSafely();
+ try {
+ mCameraThread.join();
+ mCameraThread = null;
+ mCameraHandler = null;
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private class MyCameraHandler extends Handler {
+
+ public MyCameraHandler(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case WAIT_SURFACE:
+ int id = msg.arg1;
+ int index = mCameraIDList.indexOf(String.valueOf(id));
+ Log.v(TAG, "WAIT_SURFACE id :" + id + ", index :" + index);
+ if (index == -1) {
+ break;
+ }
+ Surface surface = mMultiCameraUI.getSurfaceViewList().get(index)
+ .getHolder().getSurface();
+ if (surface.isValid()) {
+ createCaptureSessions(id, surface);
+ } else {
+ mCameraHandler.sendMessageDelayed(msg, 200);
+ Log.v(TAG, "Surface is invalid, wait more 200ms surfaceCreated");
+ }
+ break;
+ case OPEN_CAMERA:
+ if (mCameraListIndex == mCameraIDList.size()) {
+ mCameraListIndex = 0;
+ } else {
+ String cameraId = mCameraIDList.get(mCameraListIndex);
+ openCameraInSequence(cameraId);
+ mCameraListIndex ++;
+ Log.v(TAG, " OPEN_CAMERA cameraId :" + cameraId + ", mCameraListIndex :"
+ + mCameraListIndex);
+ }
+ break;
+ }
+ }
+ }
+
+ private void createVideoSnapshotImageReader(int id) {
+ if (mImageReaders[id] != null) {
+ mImageReaders[id].close();
+ }
+ mImageReaders[id] = ImageReader.newInstance(mVideoSize[id].getWidth(),
+ mVideoSize[id].getHeight(),
+ ImageFormat.JPEG, /*maxImages*/2);
+ mImageReaders[id].setOnImageAvailableListener(
+ mOnImageAvailableListener, mMultiCameraModule.getMyCameraHandler());
+ }
+
+ private final CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {
+
+ @Override
+ public void onOpened(CameraDevice cameraDevice) {
+ int id = Integer.parseInt(cameraDevice.getId());
+ mCameraDevices[id] = cameraDevice;
+ Log.d(TAG, "onOpened " + id);
+ mCameraOpenCloseLock.release();
+ createCameraPreviewSession(id);
+ mActivity.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ mMultiCameraUI.onCameraOpened(id);
+ }
+ });
+ }
+
+ @Override
+ public void onDisconnected(CameraDevice cameraDevice) {
+ int id = Integer.parseInt(cameraDevice.getId());
+ Log.d(TAG, "onDisconnected " + id);
+ mCameraOpenCloseLock.release();
+ mCameraDevices[id] = null;
+ }
+
+ @Override
+ public void onError(CameraDevice cameraDevice, int error) {
+ int id = Integer.parseInt(cameraDevice.getId());
+ Log.e(TAG, "onError " + id + " " + error);
+ mCameraOpenCloseLock.release();
+
+ if (null != mActivity) {
+ Toast.makeText(mActivity,"open camera error id =" + id,
+ Toast.LENGTH_LONG).show();
+ mActivity.finish();
+ }
+ }
+
+ @Override
+ public void onClosed(CameraDevice cameraDevice) {
+ int id = Integer.parseInt(cameraDevice.getId());
+ Log.d(TAG, "onClosed " + id);
+ mCameraOpenCloseLock.release();
+ mCameraDevices[id] = null;
+ }
+ };
+
+ private CameraCaptureSession.CaptureCallback mCaptureStillCallback
+ = new CameraCaptureSession.CaptureCallback() {
+
+ @Override
+ public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request,
+ TotalCaptureResult result) {
+ Log.d(TAG, " mCaptureCallback onCaptureCompleted ");
+ mMultiCameraModule.getMainHandler().post(new Runnable() {
+ @Override
+ public void run() {
+ Log.d(TAG, " enable Shutter " );
+ mMultiCameraUI.enableShutter(true);
+ }
+ });
+ }
+
+ @Override
+ public void onCaptureFailed(CameraCaptureSession session,
+ CaptureRequest request,
+ CaptureFailure result) {
+ Log.d(TAG, " mCaptureCallback onCaptureFailed " );
+ }
+
+
+ @Override
+ public void onCaptureSequenceCompleted(CameraCaptureSession session, int
+ sequenceId, long frameNumber) {
+ Log.d(TAG, " mCaptureCallback onCaptureSequenceCompleted ");
+ }
+ };
+
+ private MediaSaveService.OnMediaSavedListener mOnMediaSavedListener =
+ new MediaSaveService.OnMediaSavedListener() {
+ @Override
+ public void onMediaSaved(Uri uri) {
+ if (uri != null) {
+ mActivity.notifyNewMedia(uri);
+ }
+ }
+ };
+
+ public void enableRecordingLocation(boolean enable) {
+ mLocationManager.recordLocation(enable);
+ }
+
+ private Size parsePictureSize(String value) {
+ int indexX = value.indexOf('x');
+ int width = Integer.parseInt(value.substring(0, indexX));
+ int height = Integer.parseInt(value.substring(indexX + 1));
+ return new Size(width, height);
+ }
+
+ private void updateVideoSize(int id) {
+ String defaultSize = mActivity.getString(R.string.pref_multi_camera_video_quality_default);
+ int index = mCameraIDList.indexOf(String.valueOf(id));
+ String videoSize = mLocalSharedPref.getString(
+ MultiSettingsActivity.KEY_VIDEO_SIZES.get(index), defaultSize);
+ Size size = parsePictureSize(videoSize);
+ mVideoSize[id] = size;
+ Log.v(TAG, " updateVideoSize size :" + mVideoSize[id].getWidth() + "x" +
+ mVideoSize[id].getHeight());
+
+ Size[] prevSizes = getSupportedOutputSize(id, MediaRecorder.class);
+ mPreviewSizes[id] = getOptimalVideoPreviewSize(id, mVideoSize[id], prevSizes);
+ }
+
+ private Size[] getSupportedOutputSize(int cameraId, Class cl) {
+ StreamConfigurationMap map = mCharacteristics.get(cameraId).get(
+ CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
+ Size[] normal = map.getOutputSizes(cl);
+ Size[] high = map.getHighResolutionOutputSizes(ImageFormat.PRIVATE);
+ Size[] ret = new Size[normal.length + high.length];
+ System.arraycopy(normal, 0, ret, 0, normal.length);
+ System.arraycopy(high, 0, ret, normal.length, high.length);
+ return ret;
+ }
+
+ private Size getOptimalVideoPreviewSize(int id, Size VideoSize, Size[] prevSizes) {
+ Point[] points = new Point[prevSizes.length];
+
+ int index = 0;
+ int point_max[] = mMaxPreviewSize[id];
+ int max_size = -1;
+ if (point_max != null) {
+ max_size = point_max[0] * point_max[1];
+ }
+ for (Size s : prevSizes) {
+ if (max_size != -1) {
+ int size = s.getWidth() * s.getHeight();
+ if (s.getWidth() == s.getHeight()) {
+ if (s.getWidth() > Math.max(point_max[0], point_max[1]))
+ continue;
+ } else if (size > max_size || size == 0) {
+ continue;
+ }
+ }
+ points[index++] = new Point(s.getWidth(), s.getHeight());
+ }
+
+ int optimalPickIndex = CameraUtil.getOptimalVideoPreviewSize(mActivity, points, VideoSize);
+ return (optimalPickIndex == -1) ? null :
+ new Size(points[optimalPickIndex].x, points[optimalPickIndex].y);
+ }
+
+ /**
+ * Creates a new {@link CameraCaptureSession} for camera preview.
+ */
+ private void createCameraPreviewSession(int id) {
+ // This is the output Surface we need to start preview.
+ int index = mCameraIDList.indexOf(String.valueOf(id));
+ Log.v(TAG, "createCameraPreviewSession id :" + id + ", index :" + index);
+ Surface surface = mMultiCameraUI.getSurfaceViewList().get(index).getHolder().getSurface();
+
+ if (surface.isValid()) {
+ createCaptureSessions(id, surface);
+ } else {
+ Message msg = Message.obtain();
+ msg.what = WAIT_SURFACE;
+ msg.arg1 = id;
+ mCameraHandler.sendMessageDelayed(msg, 200);
+ Log.v(TAG, "Surface is invalid, wait 200ms surfaceCreated");
+ }
+
+ }
+
+ private void createCaptureSessions(int id, Surface surface) {
+ try {
+ // We set up a CaptureRequest.Builder with the output Surface.
+ mPreviewRequestBuilders[id]
+ = mCameraDevices[id].createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
+ mPreviewRequestBuilders[id].addTarget(surface);
+ mPreviewRequestBuilders[id].setTag(id);
+
+ CameraCaptureSession.StateCallback stateCallback =
+ new CameraCaptureSession.StateCallback() {
+ @Override
+ public void onConfigured(CameraCaptureSession cameraCaptureSession) {
+ // The camera is already closed
+ if (null == mCameraDevices[id]) {
+ return;
+ }
+ Log.v(TAG, " CameraCaptureSession onConfigured id :" + id);
+ // When the session is ready, we start displaying the preview.
+ mCameraPreviewSessions[id] = cameraCaptureSession;
+ try {
+ // Auto focus should be continuous for camera preview.
+ mPreviewRequestBuilders[id].set(CaptureRequest.CONTROL_AF_MODE,
+ CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
+ // Finally, we start displaying the camera preview.
+ mCameraPreviewSessions[id].setRepeatingRequest(
+ mPreviewRequestBuilders[id].build(),
+ mCaptureCallback, mMultiCameraModule.getMyCameraHandler());
+ } catch (CameraAccessException e) {
+ e.printStackTrace();
+ }
+
+ if (mCameraDevices[mCameraListIndex] == null) {
+ Message msg = Message.obtain();
+ msg.what = OPEN_CAMERA;
+ if (mCameraHandler != null) {
+ mCameraHandler.sendMessage(msg);
+ }
+ }
+ }
+
+ @Override
+ public void onConfigureFailed(CameraCaptureSession cameraCaptureSession) {
+ showToast("onConfigureFailed");
+ }
+ };
+
+ try {
+ final byte enable = 1;
+ mPreviewRequestBuilders[id].set(override_resource_cost_validation, enable);
+ Log.v(TAG, " set" + override_resource_cost_validation + " is 1");
+ } catch (IllegalArgumentException e) {
+ e.printStackTrace();
+ }
+
+ List<OutputConfiguration> outConfigurations = new ArrayList<>(1);
+ outConfigurations.add(new OutputConfiguration(surface));
+
+ SessionConfiguration sessionConfiguration = new SessionConfiguration(
+ SessionConfiguration.SESSION_REGULAR, outConfigurations,
+ new HandlerExecutor(mCameraHandler), stateCallback);
+ sessionConfiguration.setSessionParameters(mPreviewRequestBuilders[id].build());
+ mCameraDevices[id].createCaptureSession(sessionConfiguration);
+
+ } catch (CameraAccessException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private class HandlerExecutor implements Executor {
+ private final Handler ihandler;
+
+ public HandlerExecutor(Handler handler) {
+ ihandler = handler;
+ }
+
+ @Override
+ public void execute(Runnable runCmd) {
+ ihandler.post(runCmd);
+ }
+ }
+
+ /**
+ * A {@link CameraCaptureSession.CaptureCallback} that handles events related to JPEG capture.
+ */
+ private CameraCaptureSession.CaptureCallback mCaptureCallback
+ = new CameraCaptureSession.CaptureCallback() {
+
+ private void process(CaptureResult result) {
+ Integer afState = result.get(CaptureResult.CONTROL_AF_STATE);
+ Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);
+ if (DEBUG) {
+ Log.v(TAG, "process afState :" + afState + ", aeState :" + aeState);
+ }
+ }
+
+ @Override
+ public void onCaptureProgressed(CameraCaptureSession session, CaptureRequest request,
+ CaptureResult partialResult) {
+ process(partialResult);
+ }
+
+ @Override
+ public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request,
+ TotalCaptureResult result) {
+ process(result);
+ }
+
+ };
+
+ private final ImageReader.OnImageAvailableListener mOnImageAvailableListener
+ = new ImageReader.OnImageAvailableListener() {
+
+ @Override
+ public void onImageAvailable(ImageReader reader) {
+ Log.v(TAG, " onImageAvailable ...");
+ Image image = reader.acquireNextImage();
+ long imageTime = System.currentTimeMillis();
+ mNamedImages.nameNewImage(imageTime);
+ NamedEntity name = mNamedImages.getNextNameEntity();
+ String title = (name == null) ? null : name.title;
+ long date = (name == null) ? -1 : name.date;
+
+ ByteBuffer buffer = image.getPlanes()[0].getBuffer();
+ byte[] bytes = new byte[buffer.remaining()];
+ buffer.get(bytes);
+
+ int orientation = 0;
+ ExifInterface exif = Exif.getExif(bytes);
+ orientation = Exif.getOrientation(exif);
+ String saveFormat = "jpeg";
+ mActivity.getMediaSaveService().addImage(bytes, title, date,
+ null, image.getWidth(), image.getHeight(), orientation, exif,
+ mOnMediaSavedListener, mContentResolver, saveFormat);
+ mActivity.updateThumbnail(bytes);
+ image.close();
+ mMultiCameraModule.updateTakingPicture();
+ }
+ };
+
+ private void initializeValues() {
+ updateAudioEncoder();
+ updateVideoRotation();
+ }
+
+ private void checkAndPlayShutterSound(boolean isStarted) {
+ if (mSoundPlayer != null) {
+ mSoundPlayer.play(isStarted? SoundClips.STOP_VIDEO_RECORDING
+ : SoundClips.START_VIDEO_RECORDING);
+ }
+ }
+
+ private void checkAndPlayCaptureSound() {
+ if (mSoundPlayer != null) {
+ mSoundPlayer.play(SoundClips.SHUTTER_CLICK);
+ }
+ }
+
+ private void closePreviewSession(int id) {
+ if (mCameraPreviewSessions[id] != null) {
+ Log.v(TAG, "closePreviewSession id :" + id);
+ mCameraPreviewSessions[id].close();
+ mCameraPreviewSessions[id] = null;
+ }
+ }
+
+ private void startRecordingVideo(final int id) {
+ int index = mCameraIDList.indexOf(String.valueOf(id));
+ if (null == mCameraDevices[id] ||
+ !mMultiCameraUI.getSurfaceViewList().get(index).isEnabled()) {
+ return;
+ }
+ Log.v(TAG, " startRecordingVideo " + id);
+ try {
+ closePreviewSession(id);
+ setUpMediaRecorder(id);
+ createVideoSnapshotImageReader(id);
+ mPreviewRequestBuilders[id] = mCameraDevices[id].createCaptureRequest(
+ CameraDevice.TEMPLATE_RECORD);
+ if (true) {
+ mPreviewRequestBuilders[id].set(CaptureRequest.NOISE_REDUCTION_MODE,
+ CaptureRequest.NOISE_REDUCTION_MODE_FAST);
+ } else {
+ mPreviewRequestBuilders[id].set(CaptureRequest.NOISE_REDUCTION_MODE,
+ CaptureRequest.NOISE_REDUCTION_MODE_HIGH_QUALITY);
+ }
+ List<Surface> surfaces = new ArrayList<>();
+
+ // Set up Surface for the camera preview
+ Surface previewSurface = mMultiCameraUI.getSurfaceViewList().get(index).getHolder()
+ .getSurface();
+ surfaces.add(previewSurface);
+ mPreviewRequestBuilders[id].addTarget(previewSurface);
+
+ // Set up Surface for the MediaRecorder
+ Surface recorderSurface = mMediaRecorders[id].getSurface();
+ surfaces.add(recorderSurface);
+ mPreviewRequestBuilders[id].addTarget(recorderSurface);
+ surfaces.add(mImageReaders[id].getSurface());
+
+ // Start a capture session
+ // Once the session starts, we can update the UI and start recording
+ mCameraDevices[id].createCaptureSession(surfaces, new CameraCaptureSession.StateCallback() {
+
+ @Override
+ public void onConfigured(CameraCaptureSession cameraCaptureSession) {
+ mCameraPreviewSessions[id] = cameraCaptureSession;
+ updatePreview(id);
+ mActivity.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ mIsRecordingVideos[id] = true;
+ // Start recording
+ mMediaRecorders[id].start();
+ requestAudioFocus();
+ mRecordingTotalTime = 0L;
+ mRecordingStartTime = SystemClock.uptimeMillis();
+ mMediaRecorderPausing = false;
+ mMultiCameraUI.resetPauseButton();
+ mMultiCameraUI.showRecordingUI(true);
+ updateRecordingTime(id);
+ keepScreenOn();
+ Log.v(TAG, " startRecordingVideo done " + id);
+ }
+ });
+ }
+
+ @Override
+ public void onConfigureFailed(CameraCaptureSession cameraCaptureSession) {
+ if (null != mActivity) {
+ Toast.makeText(mActivity, "Configure Failed", Toast.LENGTH_SHORT).show();
+ }
+ }
+ }, mMultiCameraModule.getMyCameraHandler());
+ } catch (CameraAccessException | IllegalStateException | IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void stopRecordingVideo(int id) {
+ Log.v(TAG, " stopRecordingVideo " + id);
+ mIsRecordingVideos[id] = false;
+ try {
+ mMediaRecorders[id].setOnErrorListener(null);
+ mMediaRecorders[id].setOnInfoListener(null);
+ // Stop recording
+ mMediaRecorders[id].stop();
+ mMediaRecorders[id].reset();
+ saveVideo(id);
+ keepScreenOnAwhile();
+ // release media recorder
+ releaseMediaRecorder(id);
+ releaseAudioFocus();
+ } catch (RuntimeException e) {
+ Log.w(TAG, "MediaRecoder stop fail", e);
+ if (mVideoFilenames[id] != null) deleteVideoFile(mVideoFilenames[id]);
+ }
+
+ mMultiCameraUI.showRecordingUI(false);
+ if (null != mActivity) {
+ Toast.makeText(mActivity, "Video saved: " + mNextVideoAbsolutePaths[id],
+ Toast.LENGTH_SHORT).show();
+ Log.d(TAG, "Video saved: " + mNextVideoAbsolutePaths[id]);
+ }
+ mNextVideoAbsolutePaths[id] = null;
+ if(!mPaused) {
+ createCameraPreviewSession(id);
+ }
+ }
+
+ private final MediaSaveService.OnMediaSavedListener mOnVideoSavedListener =
+ new MediaSaveService.OnMediaSavedListener() {
+ @Override
+ public void onMediaSaved(Uri uri) {
+ if (uri != null) {
+ mActivity.notifyNewMedia(uri);
+ mCurrentVideoUri = uri;
+ }
+ }
+ };
+
+ private void keepScreenOn() {
+ mMultiCameraModule.getMainHandler().removeMessages(MultiCameraModule.CLEAR_SCREEN_DELAY);
+ mActivity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+ }
+
+ private void keepScreenOnAwhile() {
+ mMultiCameraModule.getMainHandler().removeMessages(MultiCameraModule.CLEAR_SCREEN_DELAY);
+ mActivity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+ mMultiCameraModule.getMainHandler().sendEmptyMessageDelayed(
+ MultiCameraModule.CLEAR_SCREEN_DELAY, SCREEN_DELAY);
+ }
+
+ private void releaseMediaRecorder(int id) {
+ Log.v(TAG, "Releasing media recorder.");
+ cleanupEmptyFile(id);
+ if (mMediaRecorders[id] != null) {
+ try{
+ mMediaRecorders[id].reset();
+ mMediaRecorders[id].release();
+ }catch (RuntimeException e) {
+ e.printStackTrace();
+ }
+ mMediaRecorders[id] = null;
+ }
+ }
+
+ /*
+ * Make sure we're not recording music playing in the background, ask the
+ * MediaPlaybackService to pause playback.
+ */
+ private void requestAudioFocus() {
+ AudioManager am = (AudioManager)mActivity.getSystemService(Context.AUDIO_SERVICE);
+ // Send request to obtain audio focus. This will stop other
+ // music stream.
+ int result = am.requestAudioFocus(null, AudioManager.STREAM_MUSIC,
+ AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
+ if (result == AudioManager.AUDIOFOCUS_REQUEST_FAILED) {
+ Log.v(TAG, "Audio focus request failed");
+ }
+ }
+
+ private void releaseAudioFocus() {
+ AudioManager am = (AudioManager)mActivity.getSystemService(Context.AUDIO_SERVICE);
+ int result = am.abandonAudioFocus(null);
+ if (result == AudioManager.AUDIOFOCUS_REQUEST_FAILED) {
+ Log.v(TAG, "Audio focus release failed");
+ }
+ }
+
+ private void cleanupEmptyFile(int id) {
+ if (mVideoFilenames[id] != null) {
+ File f = new File(mVideoFilenames[id]);
+ if (f.length() == 0 && f.delete()) {
+ Log.v(TAG, "Empty video file deleted: " + mVideoFilenames[id]);
+ mVideoFilenames[id] = null;
+ }
+ }
+ }
+
+ private void updateAudioEncoder() {
+ String audioEncoderStr = mActivity.getResources().getString(
+ R.string.pref_camera_audioencoder_default);
+ if (mLocalSharedPref != null) {
+ audioEncoderStr = mLocalSharedPref.getString(MultiSettingsActivity.KEY_AUDIO_ENCODER,
+ audioEncoderStr);
+ }
+ mAudioEncoder = SettingTranslation.getAudioEncoder(audioEncoderStr);
+ }
+
+ private void updateVideoRotation() {
+ String defaultValue = mActivity.getResources().getString(
+ R.string.pref_camera_video_rotation_default);
+ if (mLocalSharedPref != null) {
+ mVideoRotation = mLocalSharedPref.getString(MultiSettingsActivity.KEY_VIDEO_ROTATION,
+ defaultValue);
+ }
+ }
+
+ private void deleteVideoFile(String fileName) {
+ Log.v(TAG, "Deleting video " + fileName);
+ File f = new File(fileName);
+ if (!f.delete()) {
+ Log.v(TAG, "Could not delete " + fileName);
+ }
+ }
+
+ private void saveVideo(int id) {
+ File origFile = new File(mVideoFilenames[id]);
+ if (!origFile.exists() || origFile.length() <= 0) {
+ Log.e(TAG, "Invalid file");
+ mCurrentVideoValues[id] = null;
+ return;
+ }
+
+ long duration = 0L;
+ MediaMetadataRetriever retriever = new MediaMetadataRetriever();
+ try {
+ retriever.setDataSource(mVideoFilenames[id]);
+ duration = Long.valueOf(retriever.extractMetadata(
+ MediaMetadataRetriever.METADATA_KEY_DURATION));
+ } catch (IllegalArgumentException e) {
+ Log.e(TAG, "cannot access the file");
+ }
+ retriever.release();
+ mActivity.getMediaSaveService().addVideo(mVideoFilenames[id],
+ duration, mCurrentVideoValues[id],
+ mOnVideoSavedListener, mContentResolver);
+ Log.v(TAG, "saveVideo mVideoFilenames[id] :" + mVideoFilenames[id]);
+ mCurrentVideoValues[id] = null;
+ }
+
+ private void updateRecordingTime(int id) {
+ if (!mIsRecordingVideos[id] || id == 0) {
+ return;
+ }
+
+ if (mMediaRecorderPausing) {
+ return;
+ }
+
+ long now = SystemClock.uptimeMillis();
+ long delta = now - mRecordingStartTime + mRecordingTotalTime;
+
+ // Starting a minute before reaching the max duration
+ // limit, we'll countdown the remaining time instead.
+ boolean countdownRemainingTime = (mMaxVideoDurationInMs != 0
+ && delta >= mMaxVideoDurationInMs - 60000);
+
+ long deltaAdjusted = delta;
+ if (countdownRemainingTime) {
+ deltaAdjusted = Math.max(0, mMaxVideoDurationInMs - deltaAdjusted) + 999;
+ }
+ String text;
+ long targetNextUpdateDelay;
+ if (!mCaptureTimeLapse) {
+ text = CameraUtil.millisecondToTimeString(deltaAdjusted, false);
+ targetNextUpdateDelay = 1000;
+ } else {
+ // The length of time lapse video is different from the length
+ // of the actual wall clock time elapsed. Display the video length
+ // only in format hh:mm:ss.dd, where dd are the centi seconds.
+ text = CameraUtil.millisecondToTimeString(getTimeLapseVideoLength(delta), true);
+ targetNextUpdateDelay = mTimeBetweenTimeLapseFrameCaptureMs;
+ }
+ mMultiCameraUI.setRecordingTime(text);
+ if (mRecordingTimeCountsDown != countdownRemainingTime) {
+ // Avoid setting the color on every update, do it only
+ // when it needs changing.
+ mRecordingTimeCountsDown = countdownRemainingTime;
+
+ int color = mActivity.getResources().getColor(countdownRemainingTime
+ ? R.color.recording_time_remaining_text
+ : R.color.recording_time_elapsed_text);
+
+ mMultiCameraUI.setRecordingTimeTextColor(color);
+ }
+ long actualNextUpdateDelay = targetNextUpdateDelay - (delta % targetNextUpdateDelay);
+ mMultiCameraModule.getMainHandler().postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ updateRecordingTime(id);
+ }
+ }, actualNextUpdateDelay);
+ }
+
+ private long getTimeLapseVideoLength(long deltaMs) {
+ // For better approximation calculate fractional number of frames captured.
+ // This will update the video time at a higher resolution.
+ double numberOfFrames = (double) deltaMs / mTimeBetweenTimeLapseFrameCaptureMs;
+ return (long) (numberOfFrames / mProfile.videoFrameRate * 1000);
+ }
+
+ /**
+ * Update the camera preview. {@link #startPreview()} needs to be called in advance.
+ */
+ private void updatePreview(int id) {
+ if (null == mCameraDevices[id]) {
+ return;
+ }
+ try {
+ setUpCaptureRequestBuilder(mPreviewRequestBuilders[id]);
+ mCameraPreviewSessions[id].setRepeatingRequest(mPreviewRequestBuilders[id].build(),
+ null, mMultiCameraModule.getMyCameraHandler());
+ } catch (CameraAccessException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private void setUpCaptureRequestBuilder(CaptureRequest.Builder builder) {
+ builder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);
+ }
+
+ private String generateVideoFilename(int outputFileFormat, int id) {
+ long dateTaken = System.currentTimeMillis();
+ String title = createName(dateTaken);
+ String filename = title + "_"+ id + CameraUtil.convertOutputFormatToFileExt(outputFileFormat);
+ String mime = CameraUtil.convertOutputFormatToMimeType(outputFileFormat);
+ String path;
+ if (Storage.isSaveSDCard() && SDCard.instance().isWriteable()) {
+ path = SDCard.instance().getDirectory() + '/' + filename;
+ } else {
+ path = Storage.DIRECTORY + '/' + filename;
+ }
+ mCurrentVideoValues[id] = new ContentValues(9);
+ mCurrentVideoValues[id].put(MediaStore.Video.Media.TITLE, title);
+ mCurrentVideoValues[id].put(MediaStore.Video.Media.DISPLAY_NAME, filename);
+ mCurrentVideoValues[id].put(MediaStore.Video.Media.DATE_TAKEN, dateTaken);
+ mCurrentVideoValues[id].put(MediaStore.MediaColumns.DATE_MODIFIED, dateTaken / 1000);
+ mCurrentVideoValues[id].put(MediaStore.Video.Media.MIME_TYPE, mime);
+ mCurrentVideoValues[id].put(MediaStore.Video.Media.DATA, path);
+ mCurrentVideoValues[id].put(MediaStore.Video.Media.RESOLUTION,
+ "" + mVideoSize[id].getWidth() + "x" + mVideoSize[id].getHeight());
+ Location loc = mLocationManager.getCurrentLocation();
+ if (loc != null) {
+ mCurrentVideoValues[id].put(MediaStore.Video.Media.LATITUDE, loc.getLatitude());
+ mCurrentVideoValues[id].put(MediaStore.Video.Media.LONGITUDE, loc.getLongitude());
+ }
+ mVideoFilenames[id] = path;
+ return path;
+ }
+
+ private String createName(long dateTaken) {
+ Date date = new Date(dateTaken);
+ SimpleDateFormat dateFormat = new SimpleDateFormat(
+ mActivity.getString(R.string.video_file_name_format));
+ return dateFormat.format(date);
+ }
+
+ private void setUpMediaRecorder(int id) throws IOException {
+ if (null == mActivity) {
+ return;
+ }
+ Log.v(TAG, " setUpMediaRecorder " + id);
+ int size = CameraSettings.VIDEO_QUALITY_TABLE.get(mVideoSize[id].getWidth() + "x"
+ + mVideoSize[id].getHeight());
+ if (CamcorderProfile.hasProfile(id, size)) {
+ mProfile = CamcorderProfile.get(id, size);
+ } else {
+ warningToast(R.string.error_app_unsupported_profile);
+ throw new IllegalArgumentException("error_app_unsupported_profile");
+ }
+
+ if (mMediaRecorders[id] == null) {
+ mMediaRecorders[id] = new MediaRecorder();
+ }
+ mMediaRecorders[id].setAudioSource(MediaRecorder.AudioSource.MIC);
+ mMediaRecorders[id].setVideoSource(MediaRecorder.VideoSource.SURFACE);
+ mMediaRecorders[id].setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
+ if (mNextVideoAbsolutePaths[id] == null || mNextVideoAbsolutePaths[id].isEmpty()) {
+ mNextVideoAbsolutePaths[id] = generateVideoFilename(mProfile.fileFormat, id);
+ }
+
+ mMediaRecorders[id].setMaxDuration(mMaxVideoDurationInMs);
+ mMediaRecorders[id].setOutputFile(mNextVideoAbsolutePaths[id]);
+ mMediaRecorders[id].setVideoEncodingBitRate(10000000);
+ mMediaRecorders[id].setVideoFrameRate(30);
+ mMediaRecorders[id].setVideoSize(mVideoSize[id].getWidth(), mVideoSize[id].getHeight());
+ mMediaRecorders[id].setVideoEncoder(MediaRecorder.VideoEncoder.H264);
+ mMediaRecorders[id].setAudioEncoder(mAudioEncoder);
+ int rotation = CameraUtil.getJpegRotation(id, mOrientation);
+ if (mVideoRotation != null) {
+ rotation += Integer.parseInt(mVideoRotation);
+ rotation = rotation % 360;
+ }
+ mMediaRecorders[id].setOrientationHint(rotation);
+ mMediaRecorders[id].prepare();
+ mMediaRecorders[id].setOnErrorListener(this);
+ mMediaRecorders[id].setOnInfoListener(this);
+ }
+
+ private void warningToast(final String msg) {
+ mActivity.runOnUiThread(new Runnable() {
+ public void run() {
+ RotateTextToast.makeText(mActivity, msg,
+ Toast.LENGTH_SHORT).show();
+ }
+ });
+ }
+
+ private void warningToast(final int sourceId) {
+ warningToast(sourceId, true);
+ }
+
+ private void warningToast(final int sourceId, boolean isLongShow) {
+ mActivity.runOnUiThread(new Runnable() {
+ public void run() {
+ RotateTextToast.makeText(mActivity, sourceId,
+ isLongShow ? Toast.LENGTH_LONG : Toast.LENGTH_SHORT).show();
+ }
+ });
+ }
+
+ /**
+ * Shows a {@link Toast} on the UI thread.
+ * @param text The message to show
+ */
+ private void showToast(final String text) {
+ if (mActivity != null) {
+ mActivity.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ Toast.makeText(mActivity, text, Toast.LENGTH_SHORT).show();
+ }
+ });
+ }
+ }
+}
diff --git a/src/com/android/camera/ui/Camera2FaceView.java b/src/com/android/camera/ui/Camera2FaceView.java
index ced3245af..ced3245af 100755..100644
--- a/src/com/android/camera/ui/Camera2FaceView.java
+++ b/src/com/android/camera/ui/Camera2FaceView.java
diff --git a/src/com/android/camera/ui/CountDownView.java b/src/com/android/camera/ui/CountDownView.java
index 069d0b3d8..069d0b3d8 100755..100644
--- a/src/com/android/camera/ui/CountDownView.java
+++ b/src/com/android/camera/ui/CountDownView.java
diff --git a/src/com/android/camera/ui/FaceView.java b/src/com/android/camera/ui/FaceView.java
index 37b7c8c51..37b7c8c51 100755..100644
--- a/src/com/android/camera/ui/FaceView.java
+++ b/src/com/android/camera/ui/FaceView.java
diff --git a/src/com/android/camera/ui/FlashToggleButton.java b/src/com/android/camera/ui/FlashToggleButton.java
index 18bd26d31..a1e3f9ba9 100755..100644
--- a/src/com/android/camera/ui/FlashToggleButton.java
+++ b/src/com/android/camera/ui/FlashToggleButton.java
@@ -30,6 +30,7 @@
package com.android.camera.ui;
import android.content.Context;
+import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
@@ -42,8 +43,8 @@ import org.codeaurora.snapcam.R;
public class FlashToggleButton extends RotateImageView {
private SettingsManager mSettingsManager;
- private int[] cameraFlashIcon = {R.drawable.flash_off, R.drawable.flash_auto, R.drawable.flash};
- private int[] videoFlashIcon = {R.drawable.flash_off, R.drawable.flash};
+ TypedArray cameraFlashIcon;
+ TypedArray videoFlashIcon;
private int mIndex;
private boolean mIsVideoFlash;
private Context mContext;
@@ -51,11 +52,13 @@ public class FlashToggleButton extends RotateImageView {
public FlashToggleButton(Context context) {
super(context);
mContext = context;
+ initFlashIcons();
}
public FlashToggleButton(Context context, AttributeSet attrs) {
super(context, attrs);
mContext = context;
+ initFlashIcons();
}
public void init(boolean videoFlash) {
@@ -85,32 +88,37 @@ public class FlashToggleButton extends RotateImageView {
}
update();
- this.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- int[] icons;
- String key;
- if (mIsVideoFlash) {
- icons = videoFlashIcon;
- key = SettingsManager.KEY_VIDEO_FLASH_MODE;
- } else {
- icons = cameraFlashIcon;
- key = SettingsManager.KEY_FLASH_MODE;
- }
- mIndex = (mIndex + 1) % icons.length;
- mSettingsManager.setValueIndex(key, mIndex);
- update();
- }
- });
+ }
+
+ public void handleClick() {
+ TypedArray icons;
+ String key;
+ if (mIsVideoFlash) {
+ icons = videoFlashIcon;
+ key = SettingsManager.KEY_VIDEO_FLASH_MODE;
+ } else {
+ icons = cameraFlashIcon;
+ key = SettingsManager.KEY_FLASH_MODE;
+ }
+ mIndex = (mIndex + 1) % icons.length();
+ mSettingsManager.setValueIndex(key, mIndex);
+ update();
+ }
+
+ private void initFlashIcons() {
+ cameraFlashIcon = mContext.getResources()
+ .obtainTypedArray(R.array.flash_modes_camera);
+ videoFlashIcon = mContext.getResources()
+ .obtainTypedArray(R.array.flash_modes_video);
}
private void update() {
- int[] icons;
+ TypedArray icons;
if (mIsVideoFlash) {
icons = videoFlashIcon;
} else {
icons = cameraFlashIcon;
}
- setImageResource(icons[mIndex]);
+ setImageResource(icons.getResourceId(mIndex, 0));
}
}
diff --git a/src/com/android/camera/ui/ModuleSwitcher.java b/src/com/android/camera/ui/ModuleSwitcher.java
index 3bcb494cb..3bcb494cb 100755..100644
--- a/src/com/android/camera/ui/ModuleSwitcher.java
+++ b/src/com/android/camera/ui/ModuleSwitcher.java
diff --git a/src/com/android/camera/ui/OneUICameraControls.java b/src/com/android/camera/ui/OneUICameraControls.java
index 669565d52..b84f9065a 100755..100644
--- a/src/com/android/camera/ui/OneUICameraControls.java
+++ b/src/com/android/camera/ui/OneUICameraControls.java
@@ -25,17 +25,21 @@ import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point;
+import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.util.TypedValue;
+import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.Display;
import android.widget.FrameLayout;
+import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.SeekBar;
import android.widget.TextView;
import com.android.camera.CaptureModule;
+import com.android.camera.CaptureUI;
import com.android.camera.Storage;
import com.android.camera.imageprocessor.filter.BeautificationFilter;
@@ -45,7 +49,7 @@ public class OneUICameraControls extends RotatableLayout {
private static final String TAG = "CAM_Controls";
- private static final float TOP_PANEL_SPACE_NUM = 4f;
+ private static final float TOP_PANEL_SPACE_NUM = 5f;
private static final float BOTTOM_PANEL_SPACE_NUM = 5f;
private static final float PANEL_INDEX_0 = 0f;
private static final float PANEL_INDEX_1 = 1f;
@@ -68,9 +72,11 @@ public class OneUICameraControls extends RotatableLayout {
private View mMakeupSeekBarHighText;
private View mMakeupSeekBarLayout;
private View mCancelButton;
+ private View mModeSwitcher;
private ViewGroup mProModeLayout;
private View mSettingsButton;
+ private RecyclerView mModeSelectLayout;
private ArrowTextView mRefocusToast;
private static final int WIDTH_GRID = 5;
@@ -110,6 +116,8 @@ public class OneUICameraControls extends RotatableLayout {
private RotateLayout mIsoRotateLayout;
private RotateLayout mZoomSeekBarLayout;
+ private CaptureUI mCUI;
+
public OneUICameraControls(Context context, AttributeSet attrs) {
super(context, attrs);
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
@@ -167,6 +175,7 @@ public class OneUICameraControls extends RotatableLayout {
mRemainingPhotos = (LinearLayout) findViewById(R.id.remaining_photos);
mRemainingPhotosText = (TextView) findViewById(R.id.remaining_photos_text);
mCancelButton = findViewById(R.id.cancel_button);
+ mModeSwitcher = findViewById(R.id.mode_switcher);
mProModeLayout = (ViewGroup) findViewById(R.id.pro_mode_layout);
mExposureText = (TextView) findViewById(R.id.exposure_value);
@@ -183,75 +192,13 @@ public class OneUICameraControls extends RotatableLayout {
mIsoRotateLayout = (RotateLayout) findViewById(R.id.iso_rotate_layout);
mZoomSeekBarLayout = (RotateLayout) findViewById(R.id.zoom_seekbar_layout);
- mExposureText.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- resetProModeIcons();
- int mode = mProMode.getMode();
- if (mode == ProMode.EXPOSURE_MODE) {
- mProMode.setMode(ProMode.NO_MODE);
- } else {
- mExposureText.setSelected(true);
- mProMode.setMode(ProMode.EXPOSURE_MODE);
- }
- }
- });
- mManualText.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- resetProModeIcons();
- int mode = mProMode.getMode();
- if (mode == ProMode.MANUAL_MODE) {
- mProMode.setMode(ProMode.NO_MODE);
- } else {
- mManualText.setSelected(true);
- mProMode.setMode(ProMode.MANUAL_MODE);
- }
- }
- });
- mWhiteBalanceText.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- resetProModeIcons();
- int mode = mProMode.getMode();
- if (mode == ProMode.WHITE_BALANCE_MODE) {
- mProMode.setMode(ProMode.NO_MODE);
- } else {
- mWhiteBalanceText.setSelected(true);
- mProMode.setMode(ProMode.WHITE_BALANCE_MODE);
- }
- }
- });
- mIsoText.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- resetProModeIcons();
- int mode = mProMode.getMode();
- if (mode == ProMode.ISO_MODE) {
- mProMode.setMode(ProMode.NO_MODE);
- } else {
- mIsoText.setSelected(true);
- mProMode.setMode(ProMode.ISO_MODE);
- }
- }
- });
- mZoomSeekbarText.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- resetProModeIcons();
- int mode = mProMode.getMode();
- if (mode == ProMode.ZOOM_MODE) {
- mProMode.setMode(ProMode.NO_MODE);
- } else {
- mZoomSeekbarText.setSelected(true);
- mProMode.setMode(ProMode.ZOOM_MODE);
- }
- }
- });
+ mModeSelectLayout = (RecyclerView) findViewById(R.id.mode_select_layout);
+ mModeSelectLayout.setVisibility(View.INVISIBLE);
+
mViews = new View[]{
mSceneModeSwitcher, mFilterModeSwitcher, mFrontBackSwitcher,
- mFlashButton,
- mPreview, mPauseButton, mCancelButton, mSettingsButton
+ mFlashButton, mPreview, mPauseButton, mCancelButton,
+ mSettingsButton, mModeSwitcher
};
mBottomLargeSize = getResources().getDimensionPixelSize(
R.dimen.one_ui_bottom_large);
@@ -320,24 +267,80 @@ public class OneUICameraControls extends RotatableLayout {
}
}
+ public void onExposureTextClick() {
+ resetProModeIcons();
+ int mode = mProMode.getMode();
+ if (mode == ProMode.EXPOSURE_MODE) {
+ mProMode.setMode(ProMode.NO_MODE);
+ } else {
+ mExposureText.setSelected(true);
+ mProMode.setMode(ProMode.EXPOSURE_MODE);
+ }
+ }
+
+ public void onManualTextClick() {
+ resetProModeIcons();
+ int mode = mProMode.getMode();
+ if (mode == ProMode.MANUAL_MODE) {
+ mProMode.setMode(ProMode.NO_MODE);
+ } else {
+ mManualText.setSelected(true);
+ mProMode.setMode(ProMode.MANUAL_MODE);
+ }
+ }
+
+ public void onWhiteBalanceTextClick() {
+ resetProModeIcons();
+ int mode = mProMode.getMode();
+ if (mode == ProMode.WHITE_BALANCE_MODE) {
+ mProMode.setMode(ProMode.NO_MODE);
+ } else {
+ mWhiteBalanceText.setSelected(true);
+ mProMode.setMode(ProMode.WHITE_BALANCE_MODE);
+ }
+ }
+
+ public void onIsoTextClick() {
+ resetProModeIcons();
+ int mode = mProMode.getMode();
+ if (mode == ProMode.ISO_MODE) {
+ mProMode.setMode(ProMode.NO_MODE);
+ } else {
+ mIsoText.setSelected(true);
+ mProMode.setMode(ProMode.ISO_MODE);
+ }
+ }
+
+ public void onZoomSeekbarTextClick() {
+ resetProModeIcons();
+ int mode = mProMode.getMode();
+ if (mode == ProMode.ZOOM_MODE) {
+ mProMode.setMode(ProMode.NO_MODE);
+ } else {
+ mZoomSeekbarText.setSelected(true);
+ mProMode.setMode(ProMode.ZOOM_MODE);
+ }
+ }
+
+ public void initialize(CaptureUI cUI) {
+ mCUI = cUI;
+ }
+
+ public void closeModeSwitcher(boolean animate) {
+ mCUI.closeModeSwitcher(animate);
+ }
+
private void setLocation(View v, boolean top, float idx) {
if(v == null) {
return;
}
- int w = v.getMeasuredWidth();
int h = v.getMeasuredHeight();
if (top) {
v.setY((mTop - h) / 2);
} else {
v.setY(mHeight - mBottom + (mBottom - h) / 2);
}
- float bW;
- if (top) {
- bW = mWidth / TOP_PANEL_SPACE_NUM;
- } else {
- bW = mWidth / BOTTOM_PANEL_SPACE_NUM;
- }
- v.setX(bW * idx + (bW - w) / 2);
+ v.setX(getLocationX(v, top, idx));
}
private void setLocationCustomBottom(View v, float x, float y) {
@@ -352,10 +355,32 @@ public class OneUICameraControls extends RotatableLayout {
v.setX(bW * x);
}
+ private float getLocationX(View v, boolean top, float idx) {
+ int w = v.getMeasuredWidth();
+ float bW;
+ if (top) {
+ bW = mWidth / TOP_PANEL_SPACE_NUM;
+ } else {
+ bW = mWidth / BOTTOM_PANEL_SPACE_NUM;
+ }
+ return (bW * idx + (bW - w) / 2);
+ }
+
+ private void setLocationCameraModePanel() {
+ if(mModeSelectLayout == null) {
+ return;
+ }
+ mModeSelectLayout.setY(mModeSwitcher.getY() - mModeSelectLayout.getMeasuredHeight()
+ + mModeSwitcher.getMeasuredHeight());
+ mModeSelectLayout.setX(getLocationX(mModeSelectLayout, true, 4f));
+ }
+
private void setLocation(int w, int h) {
int rotation = getUnifiedRotation();
setLocation(mSceneModeSwitcher, true, PANEL_INDEX_0);
setLocation(mFilterModeSwitcher, true, PANEL_INDEX_1);
+ setLocation(mModeSwitcher, false, 4f);
+ setLocationCameraModePanel();
if (mIsVideoMode) {
setLocation(mMute, true, PANEL_INDEX_1);
setLocation(mFlashButton, true, PANEL_INDEX_2);
@@ -365,9 +390,9 @@ public class OneUICameraControls extends RotatableLayout {
setLocation(mVideoShutter, false, PANEL_INDEX_2);
setLocation(mExitBestPhotpMode ,false, PANEL_INDEX_4);
} else {
- setLocation(mFlashButton, true, PANEL_INDEX_2);
- setLocation(mSettingsButton,true, PANEL_INDEX_3);
- setLocation(mFrontBackSwitcher, false, 3.15f);
+ setLocation(mFlashButton, true, PANEL_INDEX_3);
+ setLocation(mSettingsButton,true, PANEL_INDEX_4);
+ setLocation(mFrontBackSwitcher, true, PANEL_INDEX_2);
if (mIntentMode == CaptureModule.INTENT_MODE_CAPTURE) {
setLocation(mShutter, false, PANEL_INDEX_2);
setLocation(mCancelButton, false, 0.85f);
@@ -518,7 +543,7 @@ public class OneUICameraControls extends RotatableLayout {
mSceneModeSwitcher, mFilterModeSwitcher, mFrontBackSwitcher,
mFlashButton, mSettingsButton, mPreview,
mMute, mMakeupSeekBarLowText, mMakeupSeekBarHighText,
- mPauseButton, mExitBestPhotpMode
+ mPauseButton, mExitBestPhotpMode, mModeSwitcher
};
for (View v : views) {
@@ -532,6 +557,13 @@ public class OneUICameraControls extends RotatableLayout {
mIsoRotateLayout.setOrientation(orientation, animation);
mZoomSeekBarLayout.setOrientation(orientation, animation);
mProMode.setOrientation(orientation);
+
+ // Reorient the camera modes
+ for (int i = 0; i < ((ViewGroup) mModeSelectLayout).getChildCount(); i++) {
+ ((Rotatable) ((ViewGroup) mModeSelectLayout.getChildAt(i))
+ .getChildAt(0)).setOrientation(orientation, animation);
+ }
+
layoutRemaingPhotos();
}
diff --git a/src/com/android/camera/ui/PieRenderer.java b/src/com/android/camera/ui/PieRenderer.java
index d9e947dab..d9e947dab 100755..100644
--- a/src/com/android/camera/ui/PieRenderer.java
+++ b/src/com/android/camera/ui/PieRenderer.java
diff --git a/src/com/android/camera/ui/ProMode.java b/src/com/android/camera/ui/ProMode.java
index d1ad0fade..3ff9ae2be 100755..100644
--- a/src/com/android/camera/ui/ProMode.java
+++ b/src/com/android/camera/ui/ProMode.java
@@ -62,10 +62,9 @@ public class ProMode extends View {
private static final int BLUE = 0xff4693fb;
private static final int SELECTED_DOT_SIZE = 20;
private static final int DOT_SIZE = 10;
- private static final int[] wbIcons = {R.drawable.auto, R.drawable.incandecent,
- R.drawable.fluorescent, R.drawable.sunlight, R.drawable.cloudy};
- private static final int[] wbIconsBlue = {R.drawable.auto_blue, R.drawable.incandecent_blue,
- R.drawable.fluorescent_blue, R.drawable.sunlight_blue, R.drawable.cloudy_blue};
+ private static final int[] wbIcons = {R.drawable.ic_scene_mode_auto_wb,
+ R.drawable.ic_scene_mode_backlight, R.drawable.ic_scene_mode_fluorescent,
+ R.drawable.ic_scene_mode_sunset, R.drawable.ic_scene_mode_cloudy};
private static final int WB_ICON_SIZE = 80;
private PathMeasure mCurveMeasure;
private int mCurveLeft;
@@ -350,7 +349,7 @@ public class ProMode extends View {
((TextView) v).setTextColor(Color.WHITE);
} else if (v instanceof ImageView) {
if (mMode == WHITE_BALANCE_MODE) {
- ((ImageView) v).setImageResource(wbIcons[mIndex]);
+ ((ImageView) v).setColorFilter(null);
}
}
}
@@ -362,7 +361,7 @@ public class ProMode extends View {
((TextView) v).setTextColor(BLUE);
} else if (v instanceof ImageView) {
if (mMode == WHITE_BALANCE_MODE) {
- ((ImageView) v).setImageResource(wbIconsBlue[mIndex]);
+ ((ImageView) v).setColorFilter(BLUE);
}
}
if (key != null) mSettingsManager.setValueIndex(key, mIndex);
@@ -383,6 +382,7 @@ public class ProMode extends View {
@Override
public boolean onTouchEvent(MotionEvent event) {
+ mUI.closeModeSwitcher(true);
if (mMode == MANUAL_MODE) {
float slider = getSlider(event.getX(), event.getY());
if (slider >= 0) {
diff --git a/src/com/android/camera/ui/TouchTrackFocusRenderer.java b/src/com/android/camera/ui/TouchTrackFocusRenderer.java
index 60c27d389..60c27d389 100755..100644
--- a/src/com/android/camera/ui/TouchTrackFocusRenderer.java
+++ b/src/com/android/camera/ui/TouchTrackFocusRenderer.java
diff --git a/src/com/android/camera/ui/ZoomRenderer.java b/src/com/android/camera/ui/ZoomRenderer.java
index c9678f008..c9678f008 100755..100644
--- a/src/com/android/camera/ui/ZoomRenderer.java
+++ b/src/com/android/camera/ui/ZoomRenderer.java
diff --git a/src/com/android/camera/util/ApiHelper.java b/src/com/android/camera/util/ApiHelper.java
index d1144956f..d1144956f 100755..100644
--- a/src/com/android/camera/util/ApiHelper.java
+++ b/src/com/android/camera/util/ApiHelper.java
diff --git a/src/com/android/camera/util/AutoTestUtil.java b/src/com/android/camera/util/AutoTestUtil.java
index 4d8cc107e..4d8cc107e 100755..100644
--- a/src/com/android/camera/util/AutoTestUtil.java
+++ b/src/com/android/camera/util/AutoTestUtil.java
diff --git a/src/com/android/camera/util/CameraUtil.java b/src/com/android/camera/util/CameraUtil.java
index 89e877087..89e877087 100755..100644
--- a/src/com/android/camera/util/CameraUtil.java
+++ b/src/com/android/camera/util/CameraUtil.java
diff --git a/src/com/android/camera/util/PersistUtil.java b/src/com/android/camera/util/PersistUtil.java
index ce4466d4a..d2165ce42 100644..100755
--- a/src/com/android/camera/util/PersistUtil.java
+++ b/src/com/android/camera/util/PersistUtil.java
@@ -91,6 +91,8 @@ public class PersistUtil {
getInt("persist.sys.camera.perf.memlimit", 120);
private static final boolean PERSIST_CAMERA_UI_AUTO_TEST_ENABLED =
getBoolean("persist.sys.camera.ui.auto_test", false);
+ private static final boolean PERSIST_CAMERA_SAVE_IN_SD_ENABLED =
+ getBoolean("persist.sys.env.camera.saveinsd", false);
private static final boolean PERSIST_LONG_SAVE_ENABLED =
getBoolean("persist.sys.camera.longshot.save", false);
private static final boolean PERSIST_CAMERA_PREVIEW_RESTART_ENABLED =
@@ -315,6 +317,10 @@ public class PersistUtil {
return PERSIST_CAMERA_UI_AUTO_TEST_ENABLED;
}
+ public static boolean isSaveInSdEnabled(){
+ return PERSIST_CAMERA_SAVE_IN_SD_ENABLED;
+ }
+
public static boolean isLongSaveEnabled(){
return PERSIST_LONG_SAVE_ENABLED;
}
diff --git a/src/com/android/camera/util/SettingTranslation.java b/src/com/android/camera/util/SettingTranslation.java
index f873799d6..f873799d6 100755..100644
--- a/src/com/android/camera/util/SettingTranslation.java
+++ b/src/com/android/camera/util/SettingTranslation.java
diff --git a/src/com/android/camera/util/VendorTagUtil.java b/src/com/android/camera/util/VendorTagUtil.java
index 1c3160312..1c3160312 100755..100644
--- a/src/com/android/camera/util/VendorTagUtil.java
+++ b/src/com/android/camera/util/VendorTagUtil.java