2e47ce0b28a2306ff181c71d834e5108d4b43af3
[pub/Android/ownCloud.git] / src / com / owncloud / android / ui / activity / FileActivity.java
1 /* ownCloud Android client application
2 * Copyright (C) 2011 Bartek Przybylski
3 * Copyright (C) 2012-2013 ownCloud Inc.
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2,
7 * as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 *
17 */
18
19 package com.owncloud.android.ui.activity;
20
21 import android.accounts.Account;
22 import android.accounts.AccountManager;
23 import android.accounts.AccountManagerCallback;
24 import android.accounts.AccountManagerFuture;
25 import android.accounts.OperationCanceledException;
26 import android.content.Intent;
27 import android.net.Uri;
28 import android.os.Bundle;
29 import android.webkit.MimeTypeMap;
30
31 import com.actionbarsherlock.app.SherlockFragmentActivity;
32 import com.owncloud.android.Log_OC;
33 import com.owncloud.android.R;
34 import com.owncloud.android.authentication.AccountAuthenticator;
35 import com.owncloud.android.authentication.AccountUtils;
36 import com.owncloud.android.datamodel.OCFile;
37
38 import eu.alefzero.webdav.WebdavUtils;
39
40 /**
41 * Activity with common behaviour for activities handling {@link OCFile}s in ownCloud {@link Account}s .
42 *
43 * @author David A. Velasco
44 */
45 public abstract class FileActivity extends SherlockFragmentActivity {
46
47 public static final String EXTRA_FILE = "com.owncloud.android.ui.activity.FILE";
48 public static final String EXTRA_ACCOUNT = "com.owncloud.android.ui.activity.ACCOUNT";
49 public static final String EXTRA_WAITING_TO_PREVIEW = "com.owncloud.android.ui.activity.WAITING_TO_PREVIEW";
50
51 public static final String TAG = FileActivity.class.getSimpleName();
52
53
54 /** OwnCloud {@link Account} where the main {@link OCFile} handled by the activity is located. */
55 private Account mAccount;
56
57 /** Main {@link OCFile} handled by the activity.*/
58 private OCFile mFile;
59
60 /** Flag to signal that the activity will is finishing to enforce the creation of an ownCloud {@link Account} */
61 private boolean mRedirectingToSetupAccount = false;
62
63 /** Flag to signal when the value of mAccount was set */
64 private boolean mAccountWasSet;
65
66 /** Flag to signal when the value of mAccount was restored from a saved state */
67 private boolean mAccountWasRestored;
68
69
70 /**
71 * Loads the ownCloud {@link Account} and main {@link OCFile} to be handled by the instance of
72 * the {@link FileActivity}.
73 *
74 * Grants that a valid ownCloud {@link Account} is associated to the instance, or that the user
75 * is requested to create a new one.
76 */
77 @Override
78 protected void onCreate(Bundle savedInstanceState) {
79 super.onCreate(savedInstanceState);
80
81 Account account;
82 if(savedInstanceState != null) {
83 account = savedInstanceState.getParcelable(FileActivity.EXTRA_ACCOUNT);
84 mFile = savedInstanceState.getParcelable(FileActivity.EXTRA_FILE);
85 } else {
86 account = getIntent().getParcelableExtra(FileActivity.EXTRA_ACCOUNT);
87 mFile = getIntent().getParcelableExtra(FileActivity.EXTRA_FILE);
88 }
89
90 setAccount(account, savedInstanceState != null);
91 }
92
93
94 /**
95 * Since ownCloud {@link Account}s can be managed from the system setting menu,
96 * the existence of the {@link Account} associated to the instance must be checked
97 * every time it is restarted.
98 */
99 @Override
100 protected void onRestart() {
101 super.onRestart();
102 boolean validAccount = (mAccount != null && AccountUtils.setCurrentOwnCloudAccount(getApplicationContext(), mAccount.name));
103 if (!validAccount) {
104 swapToDefaultAccount();
105 }
106
107 }
108
109
110 @Override
111 protected void onStart() {
112 super.onStart();
113 if (mAccountWasSet) {
114 onAccountSet(mAccountWasRestored);
115 }
116 }
117
118
119 /**
120 * Sets and validates the ownCloud {@link Account} associated to the Activity.
121 *
122 * If not valid, tries to swap it for other valid and existing ownCloud {@link Account}.
123 *
124 * POSTCONDITION: updates {@link #mAccountWasSet} and {@link #mAccountWasRestored}.
125 *
126 * @param account New {@link Account} to set.
127 * @param savedAccount When 'true', account was retrieved from a saved instance state.
128 */
129 private void setAccount(Account account, boolean savedAccount) {
130 Account oldAccount = mAccount;
131 boolean validAccount = (account != null && AccountUtils.setCurrentOwnCloudAccount(getApplicationContext(), account.name));
132 if (validAccount) {
133 mAccount = account;
134 mAccountWasSet = true;
135 mAccountWasRestored = (savedAccount || mAccount.equals(oldAccount));
136
137 } else {
138 swapToDefaultAccount();
139 }
140 }
141
142
143 /**
144 * Tries to swap the current ownCloud {@link Account} for other valid and existing.
145 *
146 * If no valid ownCloud {@link Account} exists, the the user is requested
147 * to create a new ownCloud {@link Account}.
148 *
149 * POSTCONDITION: updates {@link #mAccountWasSet} and {@link #mAccountWasRestored}.
150 *
151 * @return 'True' if the checked {@link Account} was valid.
152 */
153 private void swapToDefaultAccount() {
154 // default to the most recently used account
155 Account newAccount = AccountUtils.getCurrentOwnCloudAccount(getApplicationContext());
156 if (newAccount == null) {
157 /// no account available: force account creation
158 createFirstAccount();
159 mRedirectingToSetupAccount = true;
160 mAccountWasSet = false;
161 mAccountWasRestored = false;
162
163 } else {
164 mAccountWasSet = true;
165 mAccountWasRestored = (newAccount.equals(mAccount));
166 mAccount = newAccount;
167 }
168 }
169
170
171 /**
172 * Launches the account creation activity. To use when no ownCloud account is available
173 */
174 private void createFirstAccount() {
175 AccountManager am = AccountManager.get(getApplicationContext());
176 am.addAccount(AccountAuthenticator.ACCOUNT_TYPE,
177 null,
178 null,
179 null,
180 this,
181 new AccountCreationCallback(),
182 null);
183 }
184
185
186 /**
187 * {@inheritDoc}
188 */
189 @Override
190 protected void onSaveInstanceState(Bundle outState) {
191 super.onSaveInstanceState(outState);
192 outState.putParcelable(FileActivity.EXTRA_FILE, mFile);
193 outState.putParcelable(FileActivity.EXTRA_ACCOUNT, mAccount);
194 }
195
196
197 /**
198 * Getter for the main {@link OCFile} handled by the activity.
199 *
200 * @return Main {@link OCFile} handled by the activity.
201 */
202 public OCFile getFile() {
203 return mFile;
204 }
205
206
207 /**
208 * Setter for the main {@link OCFile} handled by the activity.
209 *
210 * @param file Main {@link OCFile} to be handled by the activity.
211 */
212 public void setFile(OCFile file) {
213 mFile = file;
214 }
215
216
217 /**
218 * Getter for the ownCloud {@link Account} where the main {@link OCFile} handled by the activity is located.
219 *
220 * @return OwnCloud {@link Account} where the main {@link OCFile} handled by the activity is located.
221 */
222 public Account getAccount() {
223 return mAccount;
224 }
225
226
227 /**
228 * @return 'True' when the Activity is finishing to enforce the setup of a new account.
229 */
230 protected boolean isRedirectingToSetupAccount() {
231 return mRedirectingToSetupAccount;
232 }
233
234
235 /**
236 * Helper class handling a callback from the {@link AccountManager} after the creation of
237 * a new ownCloud {@link Account} finished, successfully or not.
238 *
239 * At this moment, only called after the creation of the first account.
240 *
241 * @author David A. Velasco
242 */
243 public class AccountCreationCallback implements AccountManagerCallback<Bundle> {
244
245 @Override
246 public void run(AccountManagerFuture<Bundle> future) {
247 FileActivity.this.mRedirectingToSetupAccount = false;
248 boolean accountWasSet = false;
249 if (future != null) {
250 try {
251 Bundle result;
252 result = future.getResult();
253 String name = result.getString(AccountManager.KEY_ACCOUNT_NAME);
254 String type = result.getString(AccountManager.KEY_ACCOUNT_TYPE);
255 if (AccountUtils.setCurrentOwnCloudAccount(getApplicationContext(), name)) {
256 setAccount(new Account(name, type), false);
257 accountWasSet = true;
258 }
259 } catch (OperationCanceledException e) {
260 Log_OC.d(TAG, "Account creation canceled");
261
262 } catch (Exception e) {
263 Log_OC.e(TAG, "Account creation finished in exception: ", e);
264 }
265
266 } else {
267 Log_OC.e(TAG, "Account creation callback with null bundle");
268 }
269 if (!accountWasSet) {
270 moveTaskToBack(true);
271 }
272 }
273
274 }
275
276
277 /**
278 * Called when the ownCloud {@link Account} associated to the Activity was just updated.
279 *
280 * Child classes must grant that state depending on the {@link Account} is updated.
281 */
282 protected abstract void onAccountSet(boolean stateWasRecovered);
283
284
285
286 public void openFile(OCFile file) {
287 if (file != null) {
288 String storagePath = file.getStoragePath();
289 String encodedStoragePath = WebdavUtils.encodePath(storagePath);
290
291 Intent intentForSavedMimeType = new Intent(Intent.ACTION_VIEW);
292 intentForSavedMimeType.setDataAndType(Uri.parse("file://"+ encodedStoragePath), file.getMimetype());
293 intentForSavedMimeType.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
294
295 Intent intentForGuessedMimeType = null;
296 if (storagePath.lastIndexOf('.') >= 0) {
297 String guessedMimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(storagePath.substring(storagePath.lastIndexOf('.') + 1));
298 if (guessedMimeType != null && !guessedMimeType.equals(file.getMimetype())) {
299 intentForGuessedMimeType = new Intent(Intent.ACTION_VIEW);
300 intentForGuessedMimeType.setDataAndType(Uri.parse("file://"+ encodedStoragePath), guessedMimeType);
301 intentForGuessedMimeType.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
302 }
303 }
304
305 Intent chooserIntent = null;
306 if (intentForGuessedMimeType != null) {
307 chooserIntent = Intent.createChooser(intentForGuessedMimeType, getString(R.string.actionbar_open_with));
308 } else {
309 chooserIntent = Intent.createChooser(intentForSavedMimeType, getString(R.string.actionbar_open_with));
310 }
311
312 startActivity(chooserIntent);
313
314 } else {
315 Log_OC.wtf(TAG, "Trying to open a NULL OCFile");
316 }
317 }
318
319 }