summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordcalandria <dcalandria@gmail.com>2015-04-25 18:09:25 +0200
committerGerrit Code Review <gerrit@cyanogenmod.org>2015-05-31 00:47:56 +0000
commitd981627b4fe8b5d58cf6363768b6c4607f6e2683 (patch)
tree02395f0f355ca57c8b90b4f82b6e9fef58d78fad
parentd4e6548e0ee391f841e28b7cd7056f0205f76d4d (diff)
downloadandroid_packages_apps_Camera2-d981627b4fe8b5d58cf6363768b6c4607f6e2683.tar.gz
android_packages_apps_Camera2-d981627b4fe8b5d58cf6363768b6c4607f6e2683.tar.bz2
android_packages_apps_Camera2-d981627b4fe8b5d58cf6363768b6c4607f6e2683.zip
Add Storage preference (1/2)
This patch allows the user to change the default storage path. As in CM11, when the path is changed it sends an intent to the Gallery to set the default camera folder. Change-Id: I319decc3fdceca61050cf64f7e59afb06fedbf80
-rw-r--r--Android.mk2
-rw-r--r--AndroidManifest.xml1
-rw-r--r--res/values/cm_strings.xml2
-rw-r--r--res/xml/camera_preferences.xml5
-rw-r--r--src/com/android/camera/CameraActivity.java103
-rw-r--r--src/com/android/camera/Storage.java46
-rw-r--r--src/com/android/camera/VideoModule.java2
-rw-r--r--src/com/android/camera/data/LocalMediaData.java4
-rw-r--r--src/com/android/camera/settings/CameraSettingsActivity.java47
-rw-r--r--src/com/android/camera/settings/Keys.java8
-rw-r--r--src/com/android/camera/settings/SettingsUtil.java11
11 files changed, 209 insertions, 22 deletions
diff --git a/Android.mk b/Android.mk
index 7ea428200..d14b741ac 100644
--- a/Android.mk
+++ b/Android.mk
@@ -32,6 +32,8 @@ LOCAL_AAPT_FLAGS := \
LOCAL_PACKAGE_NAME := Camera2
+LOCAL_CERTIFICATE := platform
+
#LOCAL_SDK_VERSION := current
LOCAL_PROGUARD_FLAG_FILES := proguard.flags
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 086e0bccd..9912f141d 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -33,6 +33,7 @@
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS" />
<uses-permission android:name="android.permission.PREVENT_POWER_KEY" />
+ <uses-permission android:name="com.android.gallery3d.permission.STORAGE_CHANGE" />
<supports-screens
android:anyDensity="true"
diff --git a/res/values/cm_strings.xml b/res/values/cm_strings.xml
index a42f411ee..be628f8f7 100644
--- a/res/values/cm_strings.xml
+++ b/res/values/cm_strings.xml
@@ -19,4 +19,6 @@
<string name="pref_camera_power_shutter_title">Power shutter</string>
<!-- More Settings screen, max brightness title -->
<string name="pref_camera_max_brightness_title">Bright screen</string>
+ <!-- More Settings screen, storage title -->
+ <string name="pref_camera_storage_title">Storage location</string>
</resources>
diff --git a/res/xml/camera_preferences.xml b/res/xml/camera_preferences.xml
index 3474d2c9c..a15c61691 100644
--- a/res/xml/camera_preferences.xml
+++ b/res/xml/camera_preferences.xml
@@ -59,6 +59,11 @@
android:key="pref_camera_recordlocation_key"
android:title="@string/pref_camera_save_location_title" />
+ <!-- Storage -->
+ <ListPreference
+ android:key="pref_camera_storage_key"
+ android:title="@string/pref_camera_storage_title" />
+
<!-- Advanced -->
<PreferenceScreen
android:key="pref_category_advanced"
diff --git a/src/com/android/camera/CameraActivity.java b/src/com/android/camera/CameraActivity.java
index e9056d2d2..4467cdd94 100644
--- a/src/com/android/camera/CameraActivity.java
+++ b/src/com/android/camera/CameraActivity.java
@@ -45,10 +45,14 @@ import android.nfc.NfcEvent;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
+import android.os.Environment;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
+import android.os.storage.StorageEventListener;
+import android.os.storage.StorageManager;
+import android.os.storage.StorageVolume;
import android.provider.MediaStore;
import android.provider.Settings;
import android.text.TextUtils;
@@ -168,6 +172,8 @@ public class CameraActivity extends QuickActivity
"android.media.action.STILL_IMAGE_CAMERA_SECURE";
public static final String ACTION_IMAGE_CAPTURE_SECURE =
"android.media.action.IMAGE_CAPTURE_SECURE";
+ public static final String INTENT_GALLERY3D_STORAGE_CHANGE =
+ "com.android.gallery3d.STORAGE_CHANGE";
// The intent extra for camera from secure lock screen. True if the gallery
// should only show newly captured pictures. sSecureAlbumId does not
@@ -221,6 +227,8 @@ public class CameraActivity extends QuickActivity
private Intent mResultDataForTesting;
private OnScreenHint mStorageHint;
private final Object mStorageSpaceLock = new Object();
+ private String mStoragePath;
+ private StorageManager mStorageManager;
private long mStorageSpaceBytes = Storage.LOW_STORAGE_THRESHOLD_BYTES;
private boolean mAutoRotateScreen;
private boolean mSecureCamera;
@@ -580,6 +588,10 @@ public class CameraActivity extends QuickActivity
initPowerShutter();
} else if (key.equals(Keys.KEY_MAX_BRIGHTNESS)) {
initMaxBrightness();
+ } else if (key.equals(Keys.KEY_STORAGE)) {
+ if (setStoragePath()) {
+ updateStorageSpaceAndHint(null);
+ }
}
}
@@ -1529,14 +1541,6 @@ public class CameraActivity extends QuickActivity
if (!mSecureCamera) {
mFilmstripController.setDataAdapter(mDataAdapter);
- if (!isCaptureIntent()) {
- mDataAdapter.requestLoad(new Callback<Void>() {
- @Override
- public void onCallback(Void result) {
- fillTemporarySessions();
- }
- });
- }
} else {
// Put a lock placeholder as the last image by setting its date to
// 0.
@@ -1589,6 +1593,8 @@ public class CameraActivity extends QuickActivity
}
});
mMotionManager = getServices().getMotionManager();
+
+ syncStorageSettings();
}
/**
@@ -1755,6 +1761,8 @@ public class CameraActivity extends QuickActivity
Log.v(TAG, "Build info: " + Build.DISPLAY);
mPaused = false;
+
+ setStoragePath();
updateStorageSpaceAndHint(null);
mLastLayoutOrientation = getResources().getConfiguration().orientation;
@@ -1942,6 +1950,9 @@ public class CameraActivity extends QuickActivity
if (mSecureCamera) {
unregisterReceiver(mShutdownReceiver);
}
+ if (mStorageManager != null) {
+ mStorageManager.unregisterListener(mStorageEventListener);
+ }
mSettingsManager.removeAllListeners();
mCameraController.removeCallbackReceiver();
mCameraController.setCameraExceptionHandler(null);
@@ -2915,4 +2926,80 @@ public class CameraActivity extends QuickActivity
boolean showDetails = (type == LocalData.LOCAL_IMAGE) || (type == LocalData.LOCAL_VIDEO);
detailsMenuItem.setVisible(showDetails);
}
+
+ protected boolean setStoragePath() {
+ String storagePath = mSettingsManager.getString(SettingsManager.SCOPE_GLOBAL,
+ Keys.KEY_STORAGE);
+ Storage.setRoot(storagePath);
+ if (storagePath.equals(mStoragePath)) {
+ return false;
+ }
+ mStoragePath = storagePath;
+
+ // Sync the swipe preview with the right path
+ if (mDataAdapter != null) {
+ mDataAdapter.flush();
+ if (!mSecureCamera) {
+ mDataAdapter.requestLoad(new Callback<Void>() {
+ @Override
+ public void onCallback(Void result) {
+ fillTemporarySessions();
+ }
+ });
+ }
+ }
+
+ // Update the gallery app
+ Intent intent = new Intent(INTENT_GALLERY3D_STORAGE_CHANGE);
+ intent.putExtra(Keys.KEY_STORAGE, mStoragePath);
+ sendBroadcast(intent);
+ return true;
+ }
+
+ protected void syncStorageSettings() {
+ if (mStorageManager == null) {
+ mStorageManager = (StorageManager) getSystemService(Context.STORAGE_SERVICE);
+ mStorageManager.registerListener(mStorageEventListener);
+ }
+ StorageVolume[] volumes = mStorageManager.getVolumeList();
+ List<String> values = new ArrayList<String>(volumes.length);
+ List<StorageVolume> mountedVolumes = new ArrayList<StorageVolume>(volumes.length);
+
+ // Find all mounted volumes
+ String defaultValue = Environment.getExternalStorageDirectory().toString();
+ for (int i = 0; i < volumes.length; i++) {
+ StorageVolume v = volumes[i];
+ if (mStorageManager.getVolumeState(v.getPath()).equals(Environment.MEDIA_MOUNTED)) {
+ values.add(v.getPath());
+ mountedVolumes.add(v);
+ if (v.isPrimary()) {
+ defaultValue = v.getPath();
+ }
+ }
+ }
+ SettingsUtil.setMountedStorageVolumes(mountedVolumes);
+
+ mSettingsManager.setDefaults(Keys.KEY_STORAGE, defaultValue,
+ values.toArray(new String[values.size()]));
+
+ // Check if current volume is mounted. If not, restore the default storage path.
+ try {
+ mSettingsManager.getIndexOfCurrentValue(SettingsManager.SCOPE_GLOBAL,
+ Keys.KEY_STORAGE);
+ } catch (IllegalStateException e) {
+ mSettingsManager.setToDefault(SettingsManager.SCOPE_GLOBAL, Keys.KEY_STORAGE);
+ }
+
+ if (setStoragePath()) {
+ updateStorageSpaceAndHint(null);
+ }
+ }
+
+ private StorageEventListener mStorageEventListener = new StorageEventListener () {
+ @Override
+ public void onStorageStateChanged(String path, String oldState, String newState) {
+ Log.v(TAG, "onStorageStateChanged: " + path + "(" + oldState + "->" + newState + ")");
+ syncStorageSettings();
+ }
+ };
}
diff --git a/src/com/android/camera/Storage.java b/src/com/android/camera/Storage.java
index d4a1790d9..b7d79fe2f 100644
--- a/src/com/android/camera/Storage.java
+++ b/src/com/android/camera/Storage.java
@@ -41,13 +41,8 @@ import java.util.UUID;
import java.util.concurrent.TimeUnit;
public class Storage {
- public static final String DCIM =
- Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).toString();
- public static final String DIRECTORY = DCIM + "/Camera";
public static final String JPEG_POSTFIX = ".jpg";
- // 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;
@@ -55,12 +50,25 @@ public class Storage {
public static final String CAMERA_SESSION_SCHEME = "camera_session";
private static final Log.Tag TAG = new Log.Tag("Storage");
private static final String GOOGLE_COM = "google.com";
+
private static HashMap<Uri, Uri> sSessionsToContentUris = new HashMap<Uri, Uri>();
private static HashMap<Uri, Uri> sContentUrisToSessions = new HashMap<Uri, Uri>();
private static HashMap<Uri, byte[]> sSessionsToPlaceholderBytes = new HashMap<Uri, byte[]>();
private static HashMap<Uri, Point> sSessionsToSizes = new HashMap<Uri, Point>();
private static HashMap<Uri, Integer> sSessionsToPlaceholderVersions =
new HashMap<Uri, Integer>();
+ private static String sRoot = Environment.getExternalStorageDirectory().toString();
+
+ public static void setRoot(String root) {
+ if (!root.equals(sRoot)) {
+ sSessionsToContentUris.clear();
+ sContentUrisToSessions.clear();
+ sSessionsToPlaceholderBytes.clear();
+ sSessionsToSizes.clear();
+ sSessionsToPlaceholderVersions.clear();
+ }
+ sRoot = root;
+ }
/**
* Save the image with default JPEG MIME type and add it to the MediaStore.
@@ -329,7 +337,23 @@ public class Storage {
}
private static String generateFilepath(String title) {
- return DIRECTORY + '/' + title + ".jpg";
+ return generateDirectory() + '/' + title + ".jpg";
+ }
+
+ private static String generateDCIM() {
+ return new File(sRoot, Environment.DIRECTORY_DCIM).toString();
+ }
+
+ public static String generateDirectory() {
+ return generateDCIM() + "/Camera";
+ }
+
+ public static String generateBucketId() {
+ return String.valueOf(generateBucketIdInt());
+ }
+
+ public static int generateBucketIdInt() {
+ return generateDirectory().toLowerCase().hashCode();
}
/**
@@ -394,7 +418,8 @@ public class Storage {
}
public static long getAvailableSpace() {
- String state = Environment.getExternalStorageState();
+ File dir = new File(generateDirectory());
+ String state = Environment.getStorageState(dir);
Log.d(TAG, "External storage state=" + state);
if (Environment.MEDIA_CHECKING.equals(state)) {
return PREPARING;
@@ -403,14 +428,13 @@ public class Storage {
return UNAVAILABLE;
}
- File dir = new File(DIRECTORY);
dir.mkdirs();
if (!dir.isDirectory() || !dir.canWrite()) {
return UNAVAILABLE;
}
try {
- StatFs stat = new StatFs(DIRECTORY);
+ StatFs stat = new StatFs(generateDirectory());
return stat.getAvailableBlocks() * (long) stat.getBlockSize();
} catch (Exception e) {
Log.i(TAG, "Fail to access external storage", e);
@@ -423,7 +447,7 @@ public class Storage {
* imported. This is a temporary fix for bug#1655552.
*/
public static void ensureOSXCompatible() {
- File nnnAAAAA = new File(DCIM, "100ANDRO");
+ File nnnAAAAA = new File(generateDCIM(), "100ANDRO");
if (!(nnnAAAAA.exists() || nnnAAAAA.mkdirs())) {
Log.e(TAG, "Failed to create " + nnnAAAAA.getPath());
}
diff --git a/src/com/android/camera/VideoModule.java b/src/com/android/camera/VideoModule.java
index a034a1c76..7ba630f81 100644
--- a/src/com/android/camera/VideoModule.java
+++ b/src/com/android/camera/VideoModule.java
@@ -1240,7 +1240,7 @@ public class VideoModule extends CameraModule
// Used when emailing.
String filename = title + convertOutputFormatToFileExt(outputFileFormat);
String mime = convertOutputFormatToMimeType(outputFileFormat);
- String path = Storage.DIRECTORY + '/' + filename;
+ String path = Storage.generateDirectory() + '/' + filename;
String tmpPath = path + ".tmp";
mCurrentVideoValues = new ContentValues(9);
mCurrentVideoValues.put(Video.Media.TITLE, title);
diff --git a/src/com/android/camera/data/LocalMediaData.java b/src/com/android/camera/data/LocalMediaData.java
index 83399e695..873f9c95c 100644
--- a/src/com/android/camera/data/LocalMediaData.java
+++ b/src/com/android/camera/data/LocalMediaData.java
@@ -52,7 +52,6 @@ import java.util.Locale;
public abstract class LocalMediaData implements LocalData {
/** The minimum id to use to query for all media at a given media store uri */
static final int QUERY_ALL_MEDIA_ID = -1;
- private static final String CAMERA_PATH = Storage.DIRECTORY + "%";
private static final String SELECT_BY_PATH = MediaStore.MediaColumns.DATA + " LIKE ?";
private static final int MEDIASTORE_THUMB_WIDTH = 512;
private static final int MEDIASTORE_THUMB_HEIGHT = 384;
@@ -107,7 +106,8 @@ public abstract class LocalMediaData implements LocalData {
Uri contentUri, String[] projection, long minimumId, String orderBy,
CursorToLocalData builder) {
String selection = SELECT_BY_PATH + " AND " + MediaStore.MediaColumns._ID + " > ?";
- String[] selectionArgs = new String[] { CAMERA_PATH, Long.toString(minimumId) };
+ String cameraPath = Storage.generateDirectory() + "%";
+ String[] selectionArgs = new String[] { cameraPath, Long.toString(minimumId) };
Cursor cursor = contentResolver.query(contentUri, projection,
selection, selectionArgs, orderBy);
diff --git a/src/com/android/camera/settings/CameraSettingsActivity.java b/src/com/android/camera/settings/CameraSettingsActivity.java
index bb30b1122..9380fcdc8 100644
--- a/src/com/android/camera/settings/CameraSettingsActivity.java
+++ b/src/com/android/camera/settings/CameraSettingsActivity.java
@@ -23,6 +23,7 @@ import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.os.Bundle;
+import android.os.storage.StorageVolume;
import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.Preference.OnPreferenceClickListener;
@@ -105,6 +106,8 @@ public class CameraSettingsActivity extends FragmentActivity {
private SelectedVideoQualities mVideoQualitiesBack;
private SelectedVideoQualities mVideoQualitiesFront;
+ private List<StorageVolume> mStorageVolumes;
+
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -135,6 +138,9 @@ public class CameraSettingsActivity extends FragmentActivity {
// Load the camera sizes.
loadSizes();
+ // Load storage volumes
+ loadStorageVolumeList();
+
// Make sure to hide settings for cameras that don't exist on this
// device.
setVisibilities();
@@ -149,6 +155,15 @@ public class CameraSettingsActivity extends FragmentActivity {
(PreferenceScreen) findPreference(PREF_CATEGORY_ADVANCED);
setPreferenceScreenIntent(advancedScreen);
+ // Fill Storage preference
+ final Preference storagePreference = findPreference(Keys.KEY_STORAGE);
+ if (mStorageVolumes == null) {
+ getPreferenceScreen().removePreference(storagePreference);
+ } else {
+ setEntries(storagePreference);
+ setSummary(storagePreference);
+ }
+
getPreferenceScreen().getSharedPreferences()
.registerOnSharedPreferenceChangeListener(this);
}
@@ -299,6 +314,8 @@ public class CameraSettingsActivity extends FragmentActivity {
setEntriesForSelection(mVideoQualitiesBack, listPreference);
} else if (listPreference.getKey().equals(Keys.KEY_VIDEO_QUALITY_FRONT)) {
setEntriesForSelection(mVideoQualitiesFront, listPreference);
+ } else if (listPreference.getKey().equals(Keys.KEY_STORAGE)) {
+ setStorageEntriesForSelection(mStorageVolumes, listPreference);
}
}
@@ -376,6 +393,28 @@ public class CameraSettingsActivity extends FragmentActivity {
}
/**
+ * Sets the entries for the storage list preference.
+ *
+ * @param storageVolumes The storage volumes.
+ * @param preference The preference to set the entries for.
+ */
+ private void setStorageEntriesForSelection(List<StorageVolume> storageVolumes,
+ ListPreference preference) {
+ if (storageVolumes == null) {
+ return;
+ }
+ String[] entries = new String[storageVolumes.size()];
+ String[] entryValues = new String[storageVolumes.size()];
+ for (int i = 0; i < storageVolumes.size(); i++) {
+ StorageVolume v = storageVolumes.get(i);
+ entries[i] = v.getDescription(getActivity());
+ entryValues[i] = v.getPath();
+ }
+ preference.setEntries(entries);
+ preference.setEntryValues(entryValues);
+ }
+
+ /**
* Sets the summary for the given list preference.
*
* @param oldPictureSizes The old selected picture sizes for small medium and large
@@ -456,6 +495,14 @@ public class CameraSettingsActivity extends FragmentActivity {
}
}
+ private void loadStorageVolumeList() {
+ mStorageVolumes = SettingsUtil.getMountedStorageVolumes();
+ if (mStorageVolumes.size() < 2) {
+ // Remove storage preference
+ mStorageVolumes = null;
+ }
+ }
+
/**
* @param size The photo resolution.
* @return A human readable and translated string for labeling the
diff --git a/src/com/android/camera/settings/Keys.java b/src/com/android/camera/settings/Keys.java
index 8c1f2765a..ea15d6551 100644
--- a/src/com/android/camera/settings/Keys.java
+++ b/src/com/android/camera/settings/Keys.java
@@ -18,6 +18,8 @@ package com.android.camera.settings;
import android.content.Context;
+import android.os.Environment;
+
import com.android.camera.app.LocationManager;
import com.android.camera.util.ApiHelper;
import com.android.camera2.R;
@@ -76,6 +78,7 @@ public class Keys {
"pref_should_show_settings_button_cling";
public static final String KEY_POWER_SHUTTER = "pref_power_shutter";
public static final String KEY_MAX_BRIGHTNESS = "pref_max_brightness";
+ public static final String KEY_STORAGE = "pref_camera_storage_key";
/**
* Set some number of defaults for the defined keys.
@@ -171,6 +174,11 @@ public class Keys {
settingsManager.setDefaults(KEY_SHOULD_SHOW_SETTINGS_BUTTON_CLING, true);
+ settingsManager.setDefaults(KEY_STORAGE,
+ Environment.getExternalStorageDirectory().toString(), null);
+ if (!settingsManager.isSet(SettingsManager.SCOPE_GLOBAL, KEY_STORAGE)) {
+ settingsManager.setToDefault(SettingsManager.SCOPE_GLOBAL, KEY_STORAGE);
+ }
}
/** Helper functions for some defined keys. */
diff --git a/src/com/android/camera/settings/SettingsUtil.java b/src/com/android/camera/settings/SettingsUtil.java
index acf892116..a5de91abe 100644
--- a/src/com/android/camera/settings/SettingsUtil.java
+++ b/src/com/android/camera/settings/SettingsUtil.java
@@ -21,6 +21,7 @@ import android.content.Context;
import android.content.DialogInterface;
import android.content.res.Resources;
import android.media.CamcorderProfile;
+import android.os.storage.StorageVolume;
import android.util.SparseArray;
import com.android.camera.debug.Log;
@@ -497,6 +498,16 @@ public class SettingsUtil {
return -1;
}
+ private static List<StorageVolume> sMountedStorageVolumes;
+
+ public static void setMountedStorageVolumes(List<StorageVolume> volumes) {
+ sMountedStorageVolumes = volumes;
+ }
+
+ public static List<StorageVolume> getMountedStorageVolumes() {
+ return sMountedStorageVolumes;
+ }
+
public static interface CameraDeviceSelector {
/**
* Given the static characteristics of a specific camera device, decide whether it is the