Skip to content

Commit

Permalink
Added option to select location of saved videos / photos
Browse files Browse the repository at this point in the history
Change-Id: I9843e94fe30d20911b5b294ecf128c80503c1147
  • Loading branch information
Jesus David authored and pawitp committed Apr 23, 2012
1 parent afdc7cf commit 236537b
Show file tree
Hide file tree
Showing 11 changed files with 129 additions and 48 deletions.
3 changes: 3 additions & 0 deletions res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,9 @@
<string name="pref_camera_power_shutter_title">Power shutter</string>
<string name="pref_camera_power_shutter_default">off</string>

<!-- More Settings screen, storage title -->
<string name="pref_camera_storage_title">Storage</string>

<!-- Settings screen, Picture size title -->
<string name="pref_camera_picturesize_title">Picture size</string>

Expand Down
3 changes: 3 additions & 0 deletions res/xml/camera_preferences.xml
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@
camera:title="@string/pref_camera_power_shutter_title"
camera:entries="@array/pref_switch_entries"
camera:entryValues="@array/pref_switch_entryvalues" />
<ListPreference
camera:key="pref_camera_storage_key"
camera:title="@string/pref_camera_storage_title" />
<ListPreference
camera:key="pref_camera_picturesize_key"
camera:title="@string/pref_camera_picturesize_title"
Expand Down
3 changes: 3 additions & 0 deletions res/xml/video_preferences.xml
Original file line number Diff line number Diff line change
Expand Up @@ -76,4 +76,7 @@
camera:title="@string/pref_camera_power_shutter_title"
camera:entries="@array/pref_switch_entries"
camera:entryValues="@array/pref_switch_entryvalues" />
<ListPreference
camera:key="pref_camera_storage_key"
camera:title="@string/pref_camera_storage_title" />
</PreferenceGroup>
21 changes: 16 additions & 5 deletions src/com/android/camera/Camera.java
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,8 @@ public class Camera extends ActivityBase implements FocusManager.Listener,

private CameraSound mCameraSound;

private String mStorage;

private Runnable mDoSnapRunnable = new Runnable() {
public void run() {
onShutterButtonClick();
Expand Down Expand Up @@ -425,7 +427,7 @@ private void addIdleHandler() {
MessageQueue queue = Looper.myQueue();
queue.addIdleHandler(new MessageQueue.IdleHandler() {
public boolean queueIdle() {
Storage.ensureOSXCompatible();
Storage.ensureOSXCompatible(mStorage);
return false;
}
});
Expand All @@ -441,7 +443,8 @@ private void updateThumbnailButton() {
// Update last image if URI is invalid and the storage is ready.
if ((mThumbnail == null || !Util.isUriValid(mThumbnail.getUri(), mContentResolver))
&& mPicturesRemaining >= 0) {
mThumbnail = Thumbnail.getLastThumbnail(mContentResolver);
mThumbnail = Thumbnail.getLastThumbnail(mContentResolver,
Storage.generateBucketId(mStorage));
}
if (mThumbnail != null) {
mThumbnailView.setBitmap(mThumbnail.getBitmap());
Expand Down Expand Up @@ -1010,7 +1013,7 @@ private void storeImage(final byte[] data, Location loc, int width,
int height, long dateTaken, int previewWidth) {
String title = Util.createJpegName(dateTaken);
int orientation = Exif.getOrientation(data);
Uri uri = Storage.addImage(mContentResolver, title, dateTaken,
Uri uri = Storage.addImage(mContentResolver, mStorage, title, dateTaken,
loc, orientation, data, width, height);
if (uri != null) {
boolean needThumbnail;
Expand Down Expand Up @@ -1135,6 +1138,7 @@ public void run() {
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
getPreferredCameraId();
mStorage = CameraSettings.readStorage(mPreferences);
powerShutter(mPreferences);
String[] defaultFocusModes = getResources().getStringArray(
R.array.pref_camera_focusmode_default_array);
Expand Down Expand Up @@ -1275,6 +1279,7 @@ private void initializeIndicatorControl() {
final String[] OTHER_SETTING_KEYS = {
CameraSettings.KEY_RECORD_LOCATION,
CameraSettings.KEY_POWER_SHUTTER,
CameraSettings.KEY_STORAGE,
CameraSettings.KEY_PICTURE_SIZE,
CameraSettings.KEY_FOCUS_MODE};

Expand Down Expand Up @@ -1352,7 +1357,7 @@ public void onStop() {
}

private void checkStorage() {
mPicturesRemaining = Storage.getAvailableSpace();
mPicturesRemaining = Storage.getAvailableSpace(mStorage);
if (mPicturesRemaining > Storage.LOW_STORAGE_THRESHOLD) {
mPicturesRemaining = (mPicturesRemaining - Storage.LOW_STORAGE_THRESHOLD)
/ Storage.PICTURE_SIZE;
Expand Down Expand Up @@ -2199,7 +2204,7 @@ private void setCameraParametersWhenIdle(int additionalUpdateSet) {
}

private void gotoGallery() {
MenuHelper.gotoCameraImageGallery(this);
MenuHelper.gotoCameraImageGallery(this, Storage.generateBucketId(mStorage));
}

private boolean isCameraIdle() {
Expand Down Expand Up @@ -2318,6 +2323,12 @@ public void onSharedPreferenceChanged() {
mPreferences, getContentResolver());
mLocationManager.recordLocation(recordLocation);

String storage = CameraSettings.readStorage(mPreferences);
if (!storage.equals(mStorage)) {
mStorage = storage;
checkStorage();
}

int cameraId = CameraSettings.readPreferredCameraId(mPreferences);
if (mCameraId != cameraId) {
// Restart the activity to have a crossfade animation.
Expand Down
31 changes: 31 additions & 0 deletions src/com/android/camera/CameraSettings.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@
import android.hardware.Camera.Parameters;
import android.hardware.Camera.Size;
import android.media.CamcorderProfile;
import android.os.Environment;
import android.os.storage.StorageManager;
import android.os.storage.StorageVolume;
import android.util.Log;

import java.util.ArrayList;
Expand Down Expand Up @@ -53,6 +56,7 @@ public class CameraSettings {
public static final String KEY_CAMERA_FIRST_USE_HINT_SHOWN = "pref_camera_first_use_hint_shown_key";
public static final String KEY_VIDEO_FIRST_USE_HINT_SHOWN = "pref_video_first_use_hint_shown_key";
public static final String KEY_POWER_SHUTTER = "pref_power_shutter";
public static final String KEY_STORAGE = "pref_camera_storage_key";

public static final String EXPOSURE_DEFAULT_VALUE = "0";

Expand Down Expand Up @@ -156,6 +160,7 @@ private void initPreference(PreferenceGroup group) {
ListPreference videoFlashMode =
group.findPreference(KEY_VIDEOCAMERA_FLASH_MODE);
ListPreference videoEffect = group.findPreference(KEY_VIDEO_EFFECT);
ListPreference storage = group.findPreference(KEY_STORAGE);

// Since the screen could be loaded from different resources, we need
// to check if the preference is available here
Expand Down Expand Up @@ -200,6 +205,7 @@ private void initPreference(PreferenceGroup group) {
initVideoEffect(group, videoEffect);
resetIfInvalid(videoEffect);
}
if (storage != null) buildStorage(storage);
}

private void buildExposureCompensation(
Expand Down Expand Up @@ -249,6 +255,27 @@ private void buildCameraId(
preference.setEntryValues(entryValues);
}

private void buildStorage(ListPreference storage) {
StorageManager sm = (StorageManager) mContext.getSystemService(Context.STORAGE_SERVICE);
StorageVolume[] volumes = sm.getVolumeList();
String[] entries = new String[volumes.length];
String[] entryValues = new String[volumes.length];

for (int i = 0; i < volumes.length; i++) {
StorageVolume v = volumes[i];
entries[i] = v.getDescription();
entryValues[i] = v.getPath();
}
storage.setEntries(entries);
storage.setEntryValues(entryValues);

// Filter saved invalid value
if (storage.findIndexOfValue(storage.getValue()) < 0) {
// Default to the primary storage
storage.setValueIndex(0);
}
}

private static boolean removePreference(PreferenceGroup group, String key) {
for (int i = 0, n = group.size(); i < n; i++) {
CameraPreference child = group.get(i);
Expand Down Expand Up @@ -434,6 +461,10 @@ public static Object readEffectParameter(SharedPreferences pref) {
return null;
}

public static String readStorage(SharedPreferences pref) {
return pref.getString(KEY_STORAGE,
Environment.getExternalStorageDirectory().toString());
}

public static void restorePreferences(Context context,
ComboPreferences preferences, Parameters parameters) {
Expand Down
4 changes: 3 additions & 1 deletion src/com/android/camera/ComboPreferences.java
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,9 @@ private static boolean isGlobal(String key) {
|| key.equals(CameraSettings.KEY_RECORD_LOCATION)
|| key.equals(CameraSettings.KEY_CAMERA_FIRST_USE_HINT_SHOWN)
|| key.equals(CameraSettings.KEY_VIDEO_FIRST_USE_HINT_SHOWN)
|| key.equals(CameraSettings.KEY_VIDEO_EFFECT);
|| key.equals(CameraSettings.KEY_VIDEO_EFFECT)
|| key.equals(CameraSettings.KEY_POWER_SHUTTER)
|| key.equals(CameraSettings.KEY_STORAGE);
}

public String getString(String key, String defValue) {
Expand Down
12 changes: 6 additions & 6 deletions src/com/android/camera/MenuHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -137,18 +137,18 @@ public static void gotoCameraMode(Activity activity, Intent intent) {
startCameraActivity(activity, intent, CAMERA_CLASS);
}

public static void gotoCameraImageGallery(Activity activity) {
gotoGallery(activity, R.string.gallery_camera_bucket_name, INCLUDE_IMAGES);
public static void gotoCameraImageGallery(Activity activity, String bucketId) {
gotoGallery(activity, R.string.gallery_camera_bucket_name, INCLUDE_IMAGES, bucketId);
}

public static void gotoCameraVideoGallery(Activity activity) {
gotoGallery(activity, R.string.gallery_camera_videos_bucket_name, INCLUDE_VIDEOS);
public static void gotoCameraVideoGallery(Activity activity, String bucketId) {
gotoGallery(activity, R.string.gallery_camera_videos_bucket_name, INCLUDE_VIDEOS, bucketId);
}

private static void gotoGallery(Activity activity, int windowTitleId,
int mediaTypes) {
int mediaTypes, String bucketId) {
Uri target = Images.Media.EXTERNAL_CONTENT_URI.buildUpon()
.appendQueryParameter("bucketId", Storage.BUCKET_ID).build();
.appendQueryParameter("bucketId", bucketId).build();
Intent intent = new Intent(Intent.ACTION_VIEW, target);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.putExtra("windowTitle", activity.getString(windowTitleId));
Expand Down
43 changes: 24 additions & 19 deletions src/com/android/camera/Storage.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,6 @@
public class Storage {
private static final String TAG = "CameraStorage";

public static final String DCIM =
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).toString();

public static final String DIRECTORY = DCIM + "/Camera";

// Match the code in MediaProvider.computeBucketValues().
public static final String BUCKET_ID =
String.valueOf(DIRECTORY.toLowerCase().hashCode());

public static final long UNAVAILABLE = -1L;
public static final long PREPARING = -2L;
public static final long UNKNOWN_SIZE = -3L;
Expand All @@ -49,10 +40,10 @@ public class Storage {

private static final int BUFSIZE = 4096;

public static Uri addImage(ContentResolver resolver, String title, long date,
public static Uri addImage(ContentResolver resolver, String storage, String title, long date,
Location location, int orientation, byte[] jpeg, int width, int height) {
// Save the image.
String path = generateFilepath(title);
String path = generateFilepath(storage, title);
FileOutputStream out = null;
try {
out = new FileOutputStream(path);
Expand Down Expand Up @@ -98,12 +89,25 @@ public static Uri addImage(ContentResolver resolver, String title, long date,
return uri;
}

public static String generateFilepath(String title) {
return DIRECTORY + '/' + title + ".jpg";
public static String generateDCIM(String storage) {
return new File(storage, Environment.DIRECTORY_DCIM).toString();
}

public static String generateDirectory(String storage) {
return generateDCIM(storage) + "/Camera";
}

public static String generateFilepath(String storage, String title) {
return generateDirectory(storage) + '/' + title + ".jpg";
}

public static String generateBucketId(String storage) {
// Match the code in MediaProvider.computeBucketValues().
return String.valueOf(generateDirectory(storage).toLowerCase().hashCode());
}

public static long getAvailableSpace() {
String state = Environment.getExternalStorageState();
public static long getAvailableSpace(String storage) {
String state = Environment.getExternalStorageState(storage);
Log.d(TAG, "External storage state=" + state);
if (Environment.MEDIA_CHECKING.equals(state)) {
return PREPARING;
Expand All @@ -112,14 +116,15 @@ public static long getAvailableSpace() {
return UNAVAILABLE;
}

File dir = new File(DIRECTORY);
String directory = generateDirectory(storage);
File dir = new File(directory);
dir.mkdirs();
if (!dir.isDirectory() || !dir.canWrite()) {
return UNAVAILABLE;
}

try {
StatFs stat = new StatFs(DIRECTORY);
StatFs stat = new StatFs(directory);
return stat.getAvailableBlocks() * (long) stat.getBlockSize();
} catch (Exception e) {
Log.i(TAG, "Fail to access external storage", e);
Expand All @@ -131,8 +136,8 @@ public static long getAvailableSpace() {
* OSX requires plugged-in USB storage to have path /DCIM/NNNAAAAA to be
* imported. This is a temporary fix for bug#1655552.
*/
public static void ensureOSXCompatible() {
File nnnAAAAA = new File(DCIM, "100ANDRO");
public static void ensureOSXCompatible(String storage) {
File nnnAAAAA = new File(generateDCIM(storage), "100ANDRO");
if (!(nnnAAAAA.exists() || nnnAAAAA.mkdirs())) {
Log.e(TAG, "Failed to create " + nnnAAAAA.getPath());
}
Expand Down
14 changes: 7 additions & 7 deletions src/com/android/camera/Thumbnail.java
Original file line number Diff line number Diff line change
Expand Up @@ -152,9 +152,9 @@ public static Thumbnail loadFrom(File file) {
return thumbnail;
}

public static Thumbnail getLastThumbnail(ContentResolver resolver) {
Media image = getLastImageThumbnail(resolver);
Media video = getLastVideoThumbnail(resolver);
public static Thumbnail getLastThumbnail(ContentResolver resolver, String bucketId) {
Media image = getLastImageThumbnail(resolver, bucketId);
Media video = getLastVideoThumbnail(resolver, bucketId);
if (image == null && video == null) return null;

Bitmap bitmap = null;
Expand Down Expand Up @@ -192,14 +192,14 @@ public Media(long id, int orientation, long dateTaken, Uri uri) {
public final Uri uri;
}

public static Media getLastImageThumbnail(ContentResolver resolver) {
public static Media getLastImageThumbnail(ContentResolver resolver, String bucketId) {
Uri baseUri = Images.Media.EXTERNAL_CONTENT_URI;

Uri query = baseUri.buildUpon().appendQueryParameter("limit", "1").build();
String[] projection = new String[] {ImageColumns._ID, ImageColumns.ORIENTATION,
ImageColumns.DATE_TAKEN};
String selection = ImageColumns.MIME_TYPE + "='image/jpeg' AND " +
ImageColumns.BUCKET_ID + '=' + Storage.BUCKET_ID;
ImageColumns.BUCKET_ID + '=' + bucketId;
String order = ImageColumns.DATE_TAKEN + " DESC," + ImageColumns._ID + " DESC";

Cursor cursor = null;
Expand All @@ -218,13 +218,13 @@ public static Media getLastImageThumbnail(ContentResolver resolver) {
return null;
}

private static Media getLastVideoThumbnail(ContentResolver resolver) {
private static Media getLastVideoThumbnail(ContentResolver resolver, String bucketId) {
Uri baseUri = Video.Media.EXTERNAL_CONTENT_URI;

Uri query = baseUri.buildUpon().appendQueryParameter("limit", "1").build();
String[] projection = new String[] {VideoColumns._ID, MediaColumns.DATA,
VideoColumns.DATE_TAKEN};
String selection = VideoColumns.BUCKET_ID + '=' + Storage.BUCKET_ID;
String selection = VideoColumns.BUCKET_ID + '=' + bucketId;
String order = VideoColumns.DATE_TAKEN + " DESC," + VideoColumns._ID + " DESC";

Cursor cursor = null;
Expand Down

0 comments on commit 236537b

Please sign in to comment.