OSDN Git Service

Some optimizations spotted during profiling.
[android-x86/packages-apps-CMFileManager.git] / src / com / cyanogenmod / filemanager / activities / BookmarksActivity.java
1 /*
2  * Copyright (C) 2012 The CyanogenMod Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package com.cyanogenmod.filemanager.activities;
18
19 import android.app.ActionBar;
20 import android.app.Activity;
21 import android.content.BroadcastReceiver;
22 import android.content.Context;
23 import android.content.Intent;
24 import android.content.IntentFilter;
25 import android.content.res.Configuration;
26 import android.content.res.XmlResourceParser;
27 import android.database.Cursor;
28 import android.os.AsyncTask;
29 import android.os.Bundle;
30 import android.os.storage.StorageVolume;
31 import android.util.Log;
32 import android.view.KeyEvent;
33 import android.view.MenuItem;
34 import android.view.View;
35 import android.view.View.OnClickListener;
36 import android.widget.AdapterView;
37 import android.widget.AdapterView.OnItemClickListener;
38 import android.widget.ListView;
39 import android.widget.TextView;
40 import android.widget.Toast;
41
42 import com.android.internal.util.XmlUtils;
43 import com.cyanogenmod.filemanager.FileManagerApplication;
44 import com.cyanogenmod.filemanager.R;
45 import com.cyanogenmod.filemanager.adapters.BookmarksAdapter;
46 import com.cyanogenmod.filemanager.console.NoSuchFileOrDirectory;
47 import com.cyanogenmod.filemanager.model.Bookmark;
48 import com.cyanogenmod.filemanager.model.Bookmark.BOOKMARK_TYPE;
49 import com.cyanogenmod.filemanager.model.FileSystemObject;
50 import com.cyanogenmod.filemanager.preferences.AccessMode;
51 import com.cyanogenmod.filemanager.preferences.Bookmarks;
52 import com.cyanogenmod.filemanager.preferences.FileManagerSettings;
53 import com.cyanogenmod.filemanager.preferences.Preferences;
54 import com.cyanogenmod.filemanager.ui.ThemeManager;
55 import com.cyanogenmod.filemanager.ui.ThemeManager.Theme;
56 import com.cyanogenmod.filemanager.ui.dialogs.InitialDirectoryDialog;
57 import com.cyanogenmod.filemanager.ui.widgets.FlingerListView;
58 import com.cyanogenmod.filemanager.ui.widgets.FlingerListView.OnItemFlingerListener;
59 import com.cyanogenmod.filemanager.ui.widgets.FlingerListView.OnItemFlingerResponder;
60 import com.cyanogenmod.filemanager.util.CommandHelper;
61 import com.cyanogenmod.filemanager.util.DialogHelper;
62 import com.cyanogenmod.filemanager.util.ExceptionUtil;
63 import com.cyanogenmod.filemanager.util.StorageHelper;
64
65 import java.io.FileNotFoundException;
66 import java.util.ArrayList;
67 import java.util.List;
68
69 /**
70  * An activity for show bookmarks and links.
71  */
72 public class BookmarksActivity extends Activity implements OnItemClickListener, OnClickListener {
73
74     private static final String TAG = "BookmarksActivity"; //$NON-NLS-1$
75
76     private static boolean DEBUG = false;
77
78     /**
79      * A listener for flinging events from {@link FlingerListView}
80      */
81     private final OnItemFlingerListener mOnItemFlingerListener = new OnItemFlingerListener() {
82
83         @Override
84         public boolean onItemFlingerStart(
85                 AdapterView<?> parent, View view, int position, long id) {
86             try {
87                 // Response if the item can be removed
88                 BookmarksAdapter adapter = (BookmarksAdapter)parent.getAdapter();
89                 Bookmark bookmark = adapter.getItem(position);
90                 if (bookmark != null &&
91                     bookmark.mType.compareTo(BOOKMARK_TYPE.USER_DEFINED) == 0) {
92                     return true;
93                 }
94             } catch (Exception e) {
95                 ExceptionUtil.translateException(BookmarksActivity.this, e, true, false);
96             }
97             return false;
98         }
99
100         @Override
101         public void onItemFlingerEnd(OnItemFlingerResponder responder,
102                 AdapterView<?> parent, View view, int position, long id) {
103
104             try {
105                 // Response if the item can be removed
106                 BookmarksAdapter adapter = (BookmarksAdapter)parent.getAdapter();
107                 Bookmark bookmark = adapter.getItem(position);
108                 if (bookmark != null &&
109                         bookmark.mType.compareTo(BOOKMARK_TYPE.USER_DEFINED) == 0) {
110                     boolean result = Bookmarks.removeBookmark(BookmarksActivity.this, bookmark);
111                     if (!result) {
112                         //Show warning
113                         DialogHelper.showToast(BookmarksActivity.this,
114                                 R.string.msgs_operation_failure, Toast.LENGTH_SHORT);
115                         responder.cancel();
116                         return;
117                     }
118                     responder.accept();
119                     adapter.remove(bookmark);
120                     return;
121                 }
122
123                 // Cancels the flinger operation
124                 responder.cancel();
125
126             } catch (Exception e) {
127                 ExceptionUtil.translateException(BookmarksActivity.this, e, true, false);
128                 responder.cancel();
129             }
130         }
131     };
132
133     private final BroadcastReceiver mNotificationReceiver = new BroadcastReceiver() {
134         @Override
135         public void onReceive(Context context, Intent intent) {
136             if (intent != null) {
137                 if (intent.getAction().compareTo(FileManagerSettings.INTENT_THEME_CHANGED) == 0) {
138                     applyTheme();
139                 }
140             }
141         }
142     };
143
144     // Bookmark list XML tags
145     private static final String TAG_BOOKMARKS = "Bookmarks"; //$NON-NLS-1$
146     private static final String TAG_BOOKMARK = "bookmark"; //$NON-NLS-1$
147
148     /**
149      * @hide
150      */
151     ListView mBookmarksListView;
152
153     private boolean mChRooted;
154
155     /**
156      * {@inheritDoc}
157      */
158     @Override
159     protected void onCreate(Bundle state) {
160         if (DEBUG) {
161             Log.d(TAG, "BookmarksActivity.onCreate"); //$NON-NLS-1$
162         }
163
164         // Register the broadcast receiver
165         IntentFilter filter = new IntentFilter();
166         filter.addAction(FileManagerSettings.INTENT_THEME_CHANGED);
167         registerReceiver(this.mNotificationReceiver, filter);
168
169         // Is ChRooted?
170         this.mChRooted = FileManagerApplication.getAccessMode().compareTo(AccessMode.SAFE) == 0;
171
172         //Set in transition
173         overridePendingTransition(R.anim.translate_to_right_in, R.anim.hold_out);
174
175         //Set the main layout of the activity
176         setContentView(R.layout.bookmarks);
177
178         //Initialize action bars and data
179         initTitleActionBar();
180         initBookmarks();
181
182         // Apply the theme
183         applyTheme();
184
185         //Save state
186         super.onCreate(state);
187     }
188
189     /**
190      * {@inheritDoc}
191      */
192     @Override
193     protected void onDestroy() {
194         if (DEBUG) {
195             Log.d(TAG, "BookmarksActivity.onDestroy"); //$NON-NLS-1$
196         }
197
198         // Unregister the receiver
199         try {
200             unregisterReceiver(this.mNotificationReceiver);
201         } catch (Throwable ex) {
202             /**NON BLOCK**/
203         }
204
205         //All destroy. Continue
206         super.onDestroy();
207     }
208
209     /**
210      * {@inheritDoc}
211      */
212     @Override
213     protected void onPause() {
214         //Set out transition
215         overridePendingTransition(R.anim.hold_in, R.anim.translate_to_left_out);
216         super.onPause();
217     }
218
219     /**
220      * {@inheritDoc}
221      */
222     @Override
223     public void onConfigurationChanged(Configuration newConfig) {
224         super.onConfigurationChanged(newConfig);
225     }
226
227     /**
228      * Method that initializes the titlebar of the activity.
229      */
230     private void initTitleActionBar() {
231         //Configure the action bar options
232         getActionBar().setBackgroundDrawable(
233                 getResources().getDrawable(R.drawable.bg_holo_titlebar));
234         getActionBar().setDisplayOptions(
235                 ActionBar.DISPLAY_SHOW_CUSTOM | ActionBar.DISPLAY_SHOW_HOME);
236         getActionBar().setDisplayHomeAsUpEnabled(true);
237         View customTitle = getLayoutInflater().inflate(R.layout.simple_customtitle, null, false);
238         TextView title = (TextView)customTitle.findViewById(R.id.customtitle_title);
239         title.setText(R.string.bookmarks);
240         title.setContentDescription(getString(R.string.bookmarks));
241         getActionBar().setCustomView(customTitle);
242     }
243
244     /**
245      * Method that initializes the titlebar of the activity.
246      */
247     private void initBookmarks() {
248         this.mBookmarksListView = (ListView)findViewById(R.id.bookmarks_listview);
249         List<Bookmark> bookmarks = new ArrayList<Bookmark>();
250         BookmarksAdapter adapter = new BookmarksAdapter(this, bookmarks, this);
251         this.mBookmarksListView.setAdapter(adapter);
252         this.mBookmarksListView.setOnItemClickListener(this);
253
254         // If we should set the listview to response to flinger gesture detection
255         boolean useFlinger =
256                 Preferences.getSharedPreferences().getBoolean(
257                         FileManagerSettings.SETTINGS_USE_FLINGER.getId(),
258                             ((Boolean)FileManagerSettings.
259                                     SETTINGS_USE_FLINGER.
260                                         getDefaultValue()).booleanValue());
261         if (useFlinger) {
262             ((FlingerListView)this.mBookmarksListView).
263                 setOnItemFlingerListener(this.mOnItemFlingerListener);
264         }
265
266         // Reload the data
267         refresh();
268     }
269
270     /**
271      * Method that makes the refresh of the data.
272      */
273     void refresh() {
274         // Retrieve the loading view
275         final View waiting = findViewById(R.id.bookmarks_waiting);
276         final BookmarksAdapter adapter = (BookmarksAdapter)this.mBookmarksListView.getAdapter();
277
278         // Load the history in background
279         AsyncTask<Void, Void, Boolean> task = new AsyncTask<Void, Void, Boolean>() {
280             Exception mCause;
281             List<Bookmark> mBookmarks;
282
283             @Override
284             protected Boolean doInBackground(Void... params) {
285                 try {
286                     this.mBookmarks = loadBookmarks();
287                     return Boolean.TRUE;
288
289                 } catch (Exception e) {
290                     this.mCause = e;
291                     return Boolean.FALSE;
292                 }
293             }
294
295             @Override
296             protected void onPreExecute() {
297                 waiting.setVisibility(View.VISIBLE);
298                 adapter.clear();
299             }
300
301             @Override
302             protected void onPostExecute(Boolean result) {
303                 waiting.setVisibility(View.GONE);
304                 if (result.booleanValue()) {
305                     adapter.addAll(this.mBookmarks);
306                     BookmarksActivity.this.mBookmarksListView.setSelection(0);
307
308                 } else {
309                     if (this.mCause != null) {
310                         ExceptionUtil.translateException(BookmarksActivity.this, this.mCause);
311                     }
312                 }
313             }
314
315             @Override
316             protected void onCancelled() {
317                 waiting.setVisibility(View.GONE);
318             }
319         };
320         task.execute();
321     }
322
323     /**
324      * {@inheritDoc}
325      */
326     @Override
327     public boolean onKeyUp(int keyCode, KeyEvent event) {
328         switch (keyCode) {
329             case KeyEvent.KEYCODE_BACK:
330                 back(true, null);
331                 return true;
332             default:
333                 return super.onKeyUp(keyCode, event);
334         }
335     }
336
337     /**
338      * {@inheritDoc}
339      */
340     @Override
341     public boolean onOptionsItemSelected(MenuItem item) {
342        switch (item.getItemId()) {
343           case android.R.id.home:
344               back(true, null);
345               return true;
346           default:
347              return super.onOptionsItemSelected(item);
348        }
349     }
350
351     /**
352      * {@inheritDoc}
353      */
354     @Override
355     public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
356         Bookmark bookmark = ((BookmarksAdapter)parent.getAdapter()).getItem(position);
357         back(false, bookmark.mPath);
358     }
359
360     /**
361      * {@inheritDoc}
362      */
363     @Override
364     public void onClick(View v) {
365       //Retrieve the position
366       final int position = ((Integer)v.getTag()).intValue();
367       final BookmarksAdapter adapter = (BookmarksAdapter)this.mBookmarksListView.getAdapter();
368       final Bookmark bookmark = adapter.getItem(position);
369
370       //Configure home
371       if (bookmark.mType.compareTo(BOOKMARK_TYPE.HOME) == 0) {
372           //Show a dialog for configure initial directory
373           InitialDirectoryDialog dialog = new InitialDirectoryDialog(this);
374           dialog.setOnValueChangedListener(new InitialDirectoryDialog.OnValueChangedListener() {
375               @Override
376               public void onValueChanged(String newInitialDir) {
377                   adapter.getItem(position).mPath = newInitialDir;
378                   adapter.notifyDataSetChanged();
379               }
380           });
381           dialog.show();
382           return;
383       }
384
385       //Remove bookmark
386       if (bookmark.mType.compareTo(BOOKMARK_TYPE.USER_DEFINED) == 0) {
387           boolean result = Bookmarks.removeBookmark(this, bookmark);
388           if (!result) {
389               //Show warning
390               DialogHelper.showToast(this, R.string.msgs_operation_failure, Toast.LENGTH_SHORT);
391               return;
392           }
393           adapter.remove(bookmark);
394           return;
395       }
396     }
397
398     /**
399      * Method that returns to previous activity and.
400      *
401      * @param cancelled Indicates if the activity was cancelled
402      * @param path The path of the selected bookmark
403      */
404     private void back(final boolean cancelled, final String path) {
405         Intent intent =  new Intent();
406         if (cancelled) {
407             setResult(RESULT_CANCELED, intent);
408         } else {
409             // Check that the bookmark exists
410             try {
411                 FileSystemObject fso = CommandHelper.getFileInfo(this, path, null);
412                 if (fso != null) {
413                     intent.putExtra(NavigationActivity.EXTRA_BOOKMARK_SELECTION, fso);
414                     setResult(RESULT_OK, intent);
415                 } else {
416                     // The bookmark not exists, delete the user-defined bookmark
417                     try {
418                         Bookmark b = Bookmarks.getBookmark(getContentResolver(), path);
419                         Bookmarks.removeBookmark(this, b);
420                         refresh();
421                     } catch (Exception ex) {/**NON BLOCK**/}
422                 }
423             } catch (Exception e) {
424                 // Capture the exception
425                 ExceptionUtil.translateException(this, e);
426                 if (e instanceof NoSuchFileOrDirectory || e instanceof FileNotFoundException) {
427                     // The bookmark not exists, delete the user-defined bookmark
428                     try {
429                         Bookmark b = Bookmarks.getBookmark(getContentResolver(), path);
430                         Bookmarks.removeBookmark(this, b);
431                         refresh();
432                     } catch (Exception ex) {/**NON BLOCK**/}
433                 }
434                 return;
435             }
436         }
437         finish();
438     }
439
440     /**
441      * Method that loads all kind of bookmarks and join in
442      * an array to be used in the listview adapter.
443      *
444      * @return List<Bookmark>
445      * @hide
446      */
447     List<Bookmark> loadBookmarks() {
448         // Bookmarks = HOME + FILESYSTEM + SD STORAGES + USER DEFINED
449         // In ChRooted mode = SD STORAGES + USER DEFINED (from SD STORAGES)
450         List<Bookmark> bookmarks = new ArrayList<Bookmark>();
451         if (!this.mChRooted) {
452             bookmarks.add(loadHomeBookmarks());
453             bookmarks.addAll(loadFilesystemBookmarks());
454         }
455         bookmarks.addAll(loadSdStorageBookmarks());
456         bookmarks.addAll(loadUserBookmarks());
457         return bookmarks;
458     }
459
460     /**
461      * Method that loads the home bookmark from the user preference.
462      *
463      * @return Bookmark The bookmark loaded
464      */
465     private Bookmark loadHomeBookmarks() {
466         String initialDir = Preferences.getSharedPreferences().getString(
467                                 FileManagerSettings.SETTINGS_INITIAL_DIR.getId(),
468                                 (String)FileManagerSettings.SETTINGS_INITIAL_DIR.getDefaultValue());
469         return new Bookmark(BOOKMARK_TYPE.HOME, getString(R.string.bookmarks_home), initialDir);
470     }
471
472     /**
473      * Method that loads the filesystem bookmarks from the internal xml file.
474      * (defined by this application)
475      *
476      * @return List<Bookmark> The bookmarks loaded
477      */
478     private List<Bookmark> loadFilesystemBookmarks() {
479         try {
480             //Initialize the bookmarks
481             List<Bookmark> bookmarks = new ArrayList<Bookmark>();
482
483             //Read the command list xml file
484             XmlResourceParser parser = getResources().getXml(R.xml.filesystem_bookmarks);
485
486             try {
487                 //Find the root element
488                 XmlUtils.beginDocument(parser, TAG_BOOKMARKS);
489                 while (true) {
490                     XmlUtils.nextElement(parser);
491                     String element = parser.getName();
492                     if (element == null) {
493                         break;
494                     }
495
496                     if (TAG_BOOKMARK.equals(element)) {
497                         CharSequence name = null;
498                         CharSequence directory = null;
499
500                         try {
501                             name =
502                                     getString(parser.getAttributeResourceValue(
503                                             R.styleable.Bookmark_name, 0));
504                         } catch (Exception e) {/**NON BLOCK**/}
505                         try {
506                             directory =
507                                     getString(parser.getAttributeResourceValue(
508                                             R.styleable.Bookmark_directory, 0));
509                         } catch (Exception e) {/**NON BLOCK**/}
510                         if (directory == null) {
511                             directory =
512                                     parser.getAttributeValue(R.styleable.Bookmark_directory);
513                         }
514                         if (name != null && directory != null) {
515                             bookmarks.add(
516                                     new Bookmark(
517                                             BOOKMARK_TYPE.FILESYSTEM,
518                                             name.toString(),
519                                             directory.toString()));
520                         }
521                     }
522                 }
523
524                 //Return the bookmarks
525                 return bookmarks;
526
527             } finally {
528                 parser.close();
529             }
530         } catch (Throwable ex) {
531             Log.e(TAG, "Load filesystem bookmarks failed", ex); //$NON-NLS-1$
532         }
533
534         //No data
535         return new ArrayList<Bookmark>();
536     }
537
538     /**
539      * Method that loads the secure digital card storage bookmarks from the system.
540      *
541      * @return List<Bookmark> The bookmarks loaded
542      */
543     private List<Bookmark> loadSdStorageBookmarks() {
544         //Initialize the bookmarks
545         List<Bookmark> bookmarks = new ArrayList<Bookmark>();
546
547         try {
548             //Recovery sdcards from storage manager
549             StorageVolume[] volumes = StorageHelper.getStorageVolumes(getApplication());
550             int cc = volumes.length;
551             for (int i = 0; i < cc ; i++) {
552                 if (volumes[i].getPath().toLowerCase().indexOf("usb") != -1) { //$NON-NLS-1$
553                     bookmarks.add(
554                             new Bookmark(
555                                     BOOKMARK_TYPE.USB,
556                                     StorageHelper.getStorageVolumeDescription(
557                                             getApplication(), volumes[i]),
558                                     volumes[i].getPath()));
559                 } else {
560                     bookmarks.add(
561                             new Bookmark(
562                                     BOOKMARK_TYPE.SDCARD,
563                                     StorageHelper.getStorageVolumeDescription(
564                                             getApplication(), volumes[i]),
565                                     volumes[i].getPath()));
566                 }
567             }
568
569             //Return the bookmarks
570             return bookmarks;
571         } catch (Throwable ex) {
572             Log.e(TAG, "Load filesystem bookmarks failed", ex); //$NON-NLS-1$
573         }
574
575         //No data
576         return new ArrayList<Bookmark>();
577     }
578
579     /**
580      * Method that loads the user bookmarks (added by the user).
581      *
582      * @return List<Bookmark> The bookmarks loaded
583      */
584     private List<Bookmark> loadUserBookmarks() {
585         List<Bookmark> bookmarks = new ArrayList<Bookmark>();
586         Cursor cursor = Bookmarks.getAllBookmarks(this.getContentResolver());
587         try {
588             if (cursor != null && cursor.moveToFirst()) {
589                 do {
590                     Bookmark bm = new Bookmark(cursor);
591                     if (this.mChRooted && !StorageHelper.isPathInStorageVolume(bm.mPath)) {
592                         continue;
593                     }
594                     bookmarks.add(bm);
595                 } while (cursor.moveToNext());
596             }
597         } finally {
598             try {
599                 if (cursor != null) {
600                     cursor.close();
601                 }
602             } catch (Exception e) {/**NON BLOCK**/}
603         }
604         return bookmarks;
605     }
606
607     /**
608      * Method that applies the current theme to the activity
609      * @hide
610      */
611     void applyTheme() {
612         Theme theme = ThemeManager.getCurrentTheme(this);
613         theme.setBaseTheme(this, false);
614
615         //- ActionBar
616         theme.setTitlebarDrawable(this, getActionBar(), "titlebar_drawable"); //$NON-NLS-1$
617         View v = getActionBar().getCustomView().findViewById(R.id.customtitle_title);
618         theme.setTextColor(this, (TextView)v, "text_color"); //$NON-NLS-1$
619         // -View
620         theme.setBackgroundDrawable(
621                 this, this.mBookmarksListView, "background_drawable"); //$NON-NLS-1$
622         if (((BookmarksAdapter)this.mBookmarksListView.getAdapter()) != null) {
623             ((BookmarksAdapter)this.mBookmarksListView.getAdapter()).notifyThemeChanged();
624             ((BookmarksAdapter)this.mBookmarksListView.getAdapter()).notifyDataSetChanged();
625         }
626         this.mBookmarksListView.setDivider(
627                 theme.getDrawable(this, "horizontal_divider_drawable")); //$NON-NLS-1$
628         this.mBookmarksListView.invalidate();
629     }
630 }