1a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberling/* 2a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberling * Copyright (C) 2014 The Android Open Source Project 3a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberling * 4a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberling * Licensed under the Apache License, Version 2.0 (the "License"); 5a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberling * you may not use this file except in compliance with the License. 6a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberling * You may obtain a copy of the License at 7a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberling * 8a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberling * http://www.apache.org/licenses/LICENSE-2.0 9a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberling * 10a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberling * Unless required by applicable law or agreed to in writing, software 11a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberling * distributed under the License is distributed on an "AS IS" BASIS, 12a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberling * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberling * See the License for the specific language governing permissions and 14a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberling * limitations under the License. 15a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberling */ 16a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberling 17a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberlingpackage com.android.camera.session; 18a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberling 19a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberlingimport android.content.Context; 20a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberling 212bca210e5fc8a77685775ffb403096167b017dceAngus Kongimport com.android.camera.debug.Log; 22a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberlingimport com.android.camera.util.FileUtil; 23a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberling 24a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberlingimport java.io.File; 25a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberlingimport java.io.FileFilter; 26a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberlingimport java.io.IOException; 27a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberling 28a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberling/** 29a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberling * Default implementation of {@link SessionStorageManager}. 30a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberling */ 31a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberlingpublic class SessionStorageManagerImpl implements SessionStorageManager { 322bca210e5fc8a77685775ffb403096167b017dceAngus Kong private static final Log.Tag TAG = new Log.Tag("SesnStorageMgrImpl"); 33a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberling 34a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberling /** Delete temporary session directory remnants after ONE day. */ 35a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberling private static final int MAX_SESSION_AGE_MILLIS = 24 * 60 * 60 * 1000; 36a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberling 37a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberling /** The base directory for all temporary data. */ 38a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberling private final File mBaseDirectory; 39a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberling 40a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberling /** 417868361295f07205fb49d3d03e886f1c7d2eb08bSascha Haeberling * This is where we used to store temp session data, but it was the wrong 427868361295f07205fb49d3d03e886f1c7d2eb08bSascha Haeberling * place. But we want to make sure it's cleaned up for users that upgraded. 437868361295f07205fb49d3d03e886f1c7d2eb08bSascha Haeberling */ 447868361295f07205fb49d3d03e886f1c7d2eb08bSascha Haeberling private final File mDeprecatedBaseDirectory; 457868361295f07205fb49d3d03e886f1c7d2eb08bSascha Haeberling 467868361295f07205fb49d3d03e886f1c7d2eb08bSascha Haeberling /** 47a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberling * Creates a new {@link SessionStorageManager} instance. 48a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberling * 49a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberling * @param context A valid Android context to be used for determining the 50a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberling * base directory. 51a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberling * @return A session storage manager. 52a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberling */ 53a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberling public static SessionStorageManager create(Context context) { 547868361295f07205fb49d3d03e886f1c7d2eb08bSascha Haeberling return new SessionStorageManagerImpl(context.getExternalCacheDir(), 557868361295f07205fb49d3d03e886f1c7d2eb08bSascha Haeberling context.getExternalFilesDir(null)); 56a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberling } 57a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberling 587868361295f07205fb49d3d03e886f1c7d2eb08bSascha Haeberling SessionStorageManagerImpl(File baseDirectory, File deprecatedBaseDirectory) { 59a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberling mBaseDirectory = baseDirectory; 607868361295f07205fb49d3d03e886f1c7d2eb08bSascha Haeberling mDeprecatedBaseDirectory = deprecatedBaseDirectory; 61a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberling } 62a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberling 63a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberling @Override 64a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberling public File getSessionDirectory(String subDirectory) throws IOException { 65a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberling File sessionDirectory = new File(mBaseDirectory, subDirectory); 66a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberling if (!sessionDirectory.exists() && !sessionDirectory.mkdirs()) { 67a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberling throw new IOException("Could not create session directory: " + sessionDirectory); 68a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberling } 69a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberling 70a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberling if (!sessionDirectory.isDirectory()) { 71a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberling throw new IOException("Session directory is not a directory: " + sessionDirectory); 72a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberling } 73a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberling 74a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberling // Make sure there are no expired sessions in this directory. 75a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberling cleanUpExpiredSessions(sessionDirectory); 767868361295f07205fb49d3d03e886f1c7d2eb08bSascha Haeberling 777868361295f07205fb49d3d03e886f1c7d2eb08bSascha Haeberling // For upgraded users, make sure we also clean up the old location. 787868361295f07205fb49d3d03e886f1c7d2eb08bSascha Haeberling File deprecatedSessionDirectory = new File(mDeprecatedBaseDirectory, subDirectory); 797868361295f07205fb49d3d03e886f1c7d2eb08bSascha Haeberling cleanUpExpiredSessions(deprecatedSessionDirectory); 807868361295f07205fb49d3d03e886f1c7d2eb08bSascha Haeberling 81a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberling return sessionDirectory; 82a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberling } 83a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberling 84abf1e994d236a65180eecfcb6997003ab12795dfSascha Haeberling @Override 8563a8c9467824ef8aa2039b7e27831b0533d8e5d9Sascha Haeberling public File createTemporaryOutputPath(String subDirectory, String title) throws IOException { 86abf1e994d236a65180eecfcb6997003ab12795dfSascha Haeberling File tempDirectory = null; 87abf1e994d236a65180eecfcb6997003ab12795dfSascha Haeberling try { 88abf1e994d236a65180eecfcb6997003ab12795dfSascha Haeberling tempDirectory = new File( 89abf1e994d236a65180eecfcb6997003ab12795dfSascha Haeberling getSessionDirectory(subDirectory), title); 90abf1e994d236a65180eecfcb6997003ab12795dfSascha Haeberling } catch (IOException e) { 91abf1e994d236a65180eecfcb6997003ab12795dfSascha Haeberling Log.e(TAG, "Could not get temp session directory", e); 92abf1e994d236a65180eecfcb6997003ab12795dfSascha Haeberling throw new IOException("Could not get temp session directory", e); 93abf1e994d236a65180eecfcb6997003ab12795dfSascha Haeberling } 94abf1e994d236a65180eecfcb6997003ab12795dfSascha Haeberling if (!tempDirectory.mkdirs()) { 95abf1e994d236a65180eecfcb6997003ab12795dfSascha Haeberling throw new IOException("Could not create output data directory."); 96abf1e994d236a65180eecfcb6997003ab12795dfSascha Haeberling } 97abf1e994d236a65180eecfcb6997003ab12795dfSascha Haeberling File tempFile = new File(tempDirectory, title + ".jpg"); 98abf1e994d236a65180eecfcb6997003ab12795dfSascha Haeberling try { 99abf1e994d236a65180eecfcb6997003ab12795dfSascha Haeberling if (!tempFile.exists()) { 100abf1e994d236a65180eecfcb6997003ab12795dfSascha Haeberling if (!tempFile.createNewFile()) { 101abf1e994d236a65180eecfcb6997003ab12795dfSascha Haeberling throw new IOException("Could not create output data file."); 102abf1e994d236a65180eecfcb6997003ab12795dfSascha Haeberling } 103abf1e994d236a65180eecfcb6997003ab12795dfSascha Haeberling } 104abf1e994d236a65180eecfcb6997003ab12795dfSascha Haeberling } catch (IOException e) { 105abf1e994d236a65180eecfcb6997003ab12795dfSascha Haeberling Log.e(TAG, "Could not create temp session file", e); 106abf1e994d236a65180eecfcb6997003ab12795dfSascha Haeberling throw new IOException("Could not create temp session file", e); 107abf1e994d236a65180eecfcb6997003ab12795dfSascha Haeberling } 108abf1e994d236a65180eecfcb6997003ab12795dfSascha Haeberling 109abf1e994d236a65180eecfcb6997003ab12795dfSascha Haeberling if (!tempFile.canWrite()) { 110abf1e994d236a65180eecfcb6997003ab12795dfSascha Haeberling throw new IOException("Temporary output file is not writeable."); 111abf1e994d236a65180eecfcb6997003ab12795dfSascha Haeberling } 11263a8c9467824ef8aa2039b7e27831b0533d8e5d9Sascha Haeberling return tempFile; 113abf1e994d236a65180eecfcb6997003ab12795dfSascha Haeberling } 114abf1e994d236a65180eecfcb6997003ab12795dfSascha Haeberling 115a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberling /** 116a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberling * Goes through all temporary sessions and deletes the ones that are older 117a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberling * than a certain age. 118a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberling */ 119a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberling private void cleanUpExpiredSessions(File baseDirectory) { 120a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberling File[] sessionDirs = baseDirectory.listFiles(new FileFilter() { 121a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberling @Override 122a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberling public boolean accept(File file) { 123a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberling return file.isDirectory(); 124a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberling } 125a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberling }); 1267868361295f07205fb49d3d03e886f1c7d2eb08bSascha Haeberling if (sessionDirs == null) { 1277868361295f07205fb49d3d03e886f1c7d2eb08bSascha Haeberling return; 1287868361295f07205fb49d3d03e886f1c7d2eb08bSascha Haeberling } 129a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberling 130a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberling final long nowInMillis = System.currentTimeMillis(); 131a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberling for (File sessionDir : sessionDirs) { 1328111aa0a298688da560dcac6bc4c3f92b878dbc7Sascha Haeberling Log.v(TAG, "Check for potential clean-up: " + sessionDir.getAbsolutePath()); 133a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberling if (sessionDir.lastModified() < (nowInMillis - MAX_SESSION_AGE_MILLIS)) { 134a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberling if (!FileUtil.deleteDirectoryRecursively(sessionDir)) { 135a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberling Log.w(TAG, "Could not clean up " + sessionDir.getAbsolutePath()); 136a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberling } 137a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberling } 138a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberling } 139a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberling } 140a86b048709342fc53cee92aa047a15a22462c71cSascha Haeberling} 141