87be8496bae1a77ee9b41d78c2feee20c03b314a
[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.ActivityNotFoundException;
27 import android.content.Intent;
28 import android.net.Uri;
29 import android.os.Bundle;
30 import android.webkit.MimeTypeMap;
31 import android.widget.Toast;
32
33 import com.actionbarsherlock.app.SherlockFragmentActivity;
34 import com.owncloud.android.AccountUtils;
35 import com.owncloud.android.Log_OC;
36 import com.owncloud.android.authentication.AccountAuthenticator;
37 import com.owncloud.android.datamodel.OCFile;
38 import com.owncloud.android.files.FileHandler;
39
40 import eu.alefzero.webdav.WebdavUtils;
41
42 /**
43 * Activity with common behaviour for activities handling {@link OCFile}s in ownCloud {@link Account}s .
44 *
45 * @author David A. Velasco
46 */
47 public abstract class FileActivity extends SherlockFragmentActivity implements FileHandler {
48
49 public static final String EXTRA_FILE = "com.owncloud.android.ui.activity.FILE";
50 public static final String EXTRA_ACCOUNT = "com.owncloud.android.ui.activity.ACCOUNT";
51
52 public static final String TAG = FileActivity.class.getSimpleName();
53
54
55 /** OwnCloud {@link Account} where the main {@link OCFile} handled by the activity is located. */
56 private Account mAccount;
57
58 /** Main {@link OCFile} handled by the activity.*/
59 private OCFile mFile;
60
61 /** Flag to signal that the activity will is finishing to enforce the creation of an ownCloud {@link Account} */
62 private boolean mRedirectingToSetupAccount = false;
63
64 private FileHandlerImpl mFileHandler;
65
66
67 @Override
68 protected void onCreate(Bundle savedInstanceState) {
69 super.onCreate(savedInstanceState);
70
71 /// Load of saved instance state: keep this always before initDataFromCurrentAccount()
72 if(savedInstanceState != null) {
73 mFile = savedInstanceState.getParcelable(FileActivity.EXTRA_FILE);
74 mAccount = savedInstanceState.getParcelable(FileActivity.EXTRA_ACCOUNT);
75 } else {
76 mAccount = getIntent().getParcelableExtra(FileActivity.EXTRA_ACCOUNT);
77 mFile = getIntent().getParcelableExtra(FileActivity.EXTRA_FILE);
78 }
79
80 if (mAccount != null && AccountUtils.setCurrentOwnCloudAccount(getApplicationContext(), mAccount.name)) {
81 onAccountChanged();
82 }
83
84 mFileHandler = new FileHandlerImpl();
85 }
86
87
88 /**
89 * Validate the ownCloud {@link Account} associated to the Activity any time it is
90 * started, and if not valid tries to move to a different Account.
91 */
92 @Override
93 protected void onStart() {
94 Log_OC.e(TAG, "onStart en FileActivity");
95 super.onStart();
96 /// Validate account, and try to fix if wrong
97 if (mAccount == null || !AccountUtils.setCurrentOwnCloudAccount(getApplicationContext(), mAccount.name)) {
98 if (!AccountUtils.accountsAreSetup(getApplicationContext())) {
99 /// no account available: force account creation
100 mAccount = null;
101 createFirstAccount();
102 mRedirectingToSetupAccount = true;
103
104 } else {
105 /// get 'last current account' as default account
106 mAccount = AccountUtils.getCurrentOwnCloudAccount(getApplicationContext());
107 onAccountChanged();
108 }
109 }
110 }
111
112
113 /**
114 * Launches the account creation activity. To use when no ownCloud account is available
115 */
116 private void createFirstAccount() {
117 AccountManager am = AccountManager.get(getApplicationContext());
118 am.addAccount(AccountAuthenticator.ACCOUNT_TYPE,
119 AccountAuthenticator.AUTH_TOKEN_TYPE_PASSWORD,
120 null,
121 null,
122 this,
123 new AccountCreationCallback(),
124 null);
125 }
126
127
128 /**
129 * {@inheritDoc}
130 */
131 @Override
132 protected void onSaveInstanceState(Bundle outState) {
133 super.onSaveInstanceState(outState);
134 outState.putParcelable(FileActivity.EXTRA_FILE, mFile);
135 outState.putParcelable(FileActivity.EXTRA_ACCOUNT, mAccount);
136 }
137
138
139 /**
140 * Getter for the main {@link OCFile} handled by the activity.
141 *
142 * @return Main {@link OCFile} handled by the activity.
143 */
144 public OCFile getFile() {
145 return mFile;
146 }
147
148
149 /**
150 * Setter for the main {@link OCFile} handled by the activity.
151 *
152 * @param file Main {@link OCFile} to be handled by the activity.
153 */
154 public void setFile(OCFile file) {
155 mFile = file;
156 }
157
158
159 /**
160 * Getter for the ownCloud {@link Account} where the main {@link OCFile} handled by the activity is located.
161 *
162 * @return OwnCloud {@link Account} where the main {@link OCFile} handled by the activity is located.
163 */
164 public Account getAccount() {
165 return mAccount;
166 }
167
168
169 /**
170 * @return 'True' when the Activity is finishing to enforce the setup of a new account.
171 */
172 protected boolean isRedirectingToSetupAccount() {
173 return mRedirectingToSetupAccount;
174 }
175
176
177 /**
178 * Helper class handling a callback from the {@link AccountManager} after the creation of
179 * a new ownCloud {@link Account} finished, successfully or not.
180 *
181 * At this moment, only called after the creation of the first account.
182 *
183 * @author David A. Velasco
184 */
185 public class AccountCreationCallback implements AccountManagerCallback<Bundle> {
186
187 @Override
188 public void run(AccountManagerFuture<Bundle> future) {
189 FileActivity.this.mRedirectingToSetupAccount = false;
190 if (future != null) {
191 try {
192 Bundle result;
193 result = future.getResult();
194 String name = result.getString(AccountManager.KEY_ACCOUNT_NAME);
195 String type = result.getString(AccountManager.KEY_ACCOUNT_TYPE);
196 if (AccountUtils.setCurrentOwnCloudAccount(getApplicationContext(), name)) {
197 FileActivity.this.mAccount = new Account(name, type);
198 FileActivity.this.onAccountChanged();
199 }
200 } catch (OperationCanceledException e) {
201 Log_OC.e(TAG, "Account creation canceled");
202
203 } catch (Exception e) {
204 Log_OC.e(TAG, "Account creation finished in exception: ", e);
205 }
206
207 } else {
208 Log_OC.e(TAG, "Account creation callback with null bundle");
209 }
210 if (mAccount == null) {
211 finish();
212 }
213 }
214
215 }
216
217
218 public void openFile(OCFile file) {
219 mFileHandler.openFile(file);
220 }
221
222
223 /**
224 * Called when the ownCloud {@link Account} associated to the Activity was just updated.
225 *
226 * Child classes must grant that state depending on the {@link Account} is updated.
227 */
228 protected abstract void onAccountChanged();
229
230
231 public class FileHandlerImpl implements FileHandler {
232
233 public void openFile(OCFile file) {
234 if (file != null) {
235 String storagePath = file.getStoragePath();
236 String encodedStoragePath = WebdavUtils.encodePath(storagePath);
237 try {
238 Intent i = new Intent(Intent.ACTION_VIEW);
239 i.setDataAndType(Uri.parse("file://"+ encodedStoragePath), file.getMimetype());
240 i.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
241 startActivity(i);
242
243 } catch (Throwable t) {
244 Log_OC.e(TAG, "Fail when trying to open with the mimeType provided from the ownCloud server: " + file.getMimetype());
245 boolean toastIt = true;
246 String mimeType = "";
247 try {
248 Intent i = new Intent(Intent.ACTION_VIEW);
249 mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(storagePath.substring(storagePath.lastIndexOf('.') + 1));
250 if (mimeType == null || !mimeType.equals(file.getMimetype())) {
251 if (mimeType != null) {
252 i.setDataAndType(Uri.parse("file://"+ encodedStoragePath), mimeType);
253 } else {
254 // desperate try
255 i.setDataAndType(Uri.parse("file://"+ encodedStoragePath), "*/*");
256 }
257 i.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
258 startActivity(i);
259 toastIt = false;
260 }
261
262 } catch (IndexOutOfBoundsException e) {
263 Log_OC.e(TAG, "Trying to find out MIME type of a file without extension: " + storagePath);
264
265 } catch (ActivityNotFoundException e) {
266 Log_OC.e(TAG, "No activity found to handle: " + storagePath + " with MIME type " + mimeType + " obtained from extension");
267
268 } catch (Throwable th) {
269 Log_OC.e(TAG, "Unexpected problem when opening: " + storagePath, th);
270
271 } finally {
272 if (toastIt) {
273 Toast.makeText(FileActivity.this, "There is no application to handle file " + file.getFileName(), Toast.LENGTH_SHORT).show();
274 }
275 }
276 }
277 } else {
278 Log_OC.wtf(TAG, "Trying to open a NULL OCFile");
279 }
280 }
281 }
282 }