diff options
| author | dcalandria <dcalandria@gmail.com> | 2015-04-25 18:09:25 +0200 |
|---|---|---|
| committer | Gerrit Code Review <gerrit@cyanogenmod.org> | 2015-05-31 00:47:56 +0000 |
| commit | d981627b4fe8b5d58cf6363768b6c4607f6e2683 (patch) | |
| tree | 02395f0f355ca57c8b90b4f82b6e9fef58d78fad | |
| parent | d4e6548e0ee391f841e28b7cd7056f0205f76d4d (diff) | |
| download | android_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.mk | 2 | ||||
| -rw-r--r-- | AndroidManifest.xml | 1 | ||||
| -rw-r--r-- | res/values/cm_strings.xml | 2 | ||||
| -rw-r--r-- | res/xml/camera_preferences.xml | 5 | ||||
| -rw-r--r-- | src/com/android/camera/CameraActivity.java | 103 | ||||
| -rw-r--r-- | src/com/android/camera/Storage.java | 46 | ||||
| -rw-r--r-- | src/com/android/camera/VideoModule.java | 2 | ||||
| -rw-r--r-- | src/com/android/camera/data/LocalMediaData.java | 4 | ||||
| -rw-r--r-- | src/com/android/camera/settings/CameraSettingsActivity.java | 47 | ||||
| -rw-r--r-- | src/com/android/camera/settings/Keys.java | 8 | ||||
| -rw-r--r-- | src/com/android/camera/settings/SettingsUtil.java | 11 |
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 |
