diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 2d8380258..57aad5da4 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -154,10 +154,26 @@
android:name=".activities.EditorActivity"
android:label="@string/editor"
android:configChanges="orientation|keyboardHidden|screenSize"
- android:icon="@drawable/ic_launcher_editor"
- android:exported="false">
+ android:icon="@drawable/ic_launcher_editor">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml
new file mode 100644
index 000000000..074984395
--- /dev/null
+++ b/res/values-el/strings.xml
@@ -0,0 +1,690 @@
+
+
+
+
+
+
+ Διαχείριση αρχείων
+
+ Διαχείριση αρχείων του CyanogenMod
+
+
+ Ναι
+ Όχι
+ Όλα
+ Αντικατάσταση
+
+
+ ]]>
+
+ Αναζήτηση: %1$s
+
+
+ Φόρτωση\u2026
+
+ Ακυρώθηκε.
+
+ Σφάλμα.
+
+
+ Προσοχή
+
+ Εντοπίστηκε σφάλμα
+
+ Επιβεβαίωση δραστηριότητας
+
+ Επιβεβαίωση αντικατάστασης
+
+ Επιβεβαίωση διαγραφής
+
+
+ Επιβεβαίωση αλλαγής
+
+
+ Δεν είναι δυνατή η πρόσβαση Root. Αλλαγή σε κατάσταση Ασφαλούς Λειτουργίας. \n\nΕφαρμoγή αλλαγής;
+
+
+ Δεν είναι δυνατή η απόκτήση των απαιτούμενων δικαιωμάτων για να λειτουργήσει η εφαρμογή.
+
+ Δεν είναι δυνατή η πρόσβαση Root.
+ Αλλαγή σε κατάσταση Ασφαλούς Λειτουργίας.
+
+ Η ρύθμιση δεν μπορεί να εφαρμοστεί ή να αποθηκευθεί.
+
+ Ο αρχικός φάκελος
+ "%1$s" δεν είναι έγκυρος. Αλλαγή στο ριζικό φάκελο.
+
+
+ Η λειτουργία ολοκληρώθηκε με επιτυχία.
+
+ Ένα σφάλμα εντοπίστηκε. Η λειτουργία ήταν ανεπιτυχής.
+
+ Αυτή η λειτουργία απαιτεί αυξημένα δικαιώματα. Προσπαθήστε
+ να αλλάξετε σε λειτουργία πρόσβασης Root.
+
+ Το αρχείο ή ο φάκελος δεν βρέθηκε.
+
+ Η εντολή δεν βρέθηκε ή δεν έχει οριστεί σωστά.
+
+ Αποτυχία ανάγνωσης/εγγραφής.
+
+ Λήξη χρονικού ορίου λειτουργίας.
+
+ Αποτυχία λειτουργίας.
+
+ Παρουσιάστηκε ένα εσωτερικό σφάλμα.
+
+ Η λειτουργία δεν μπορεί να ακυρωθεί.
+
+ Το σύστημα αρχείων είναι μόνο για ανάγνωση. Προσπαθήστε να προσαρτήσετε το
+ σύστημα αρχείων για ανάγνωση/εγγραφή πριν εκτελέσετε τη λειτουργία.
+
+ Μη έγκυρο επιχείρημα. Αποτυχία επίκλησης λειτουργίας.
+
+
+ Η λειτουργία δεν επιτρέπεται, διότι θα δημιουργούσε προβλήματα ασυνέπειας.
+
+
+ Η λειτουργία δεν επιτρέπεται στον τρέχοντα φάκελο.
+
+
+ Πιέστε ξανά για έξοδο.
+
+
+ Δεν υπάρχει καμία εφαρμογή για να χειριστεί
+ τον τύπο του αρχείου που έχετε επιλέξει.
+
+
+
+ Μερικά από τα αρχεία υπάρχουν ήδη στο φάκελο προορισμού.\n\nΑντικατάσταση;
+
+
+ Η συσχέτιση της ενέργειας με την
+ εφαρμογή απέτυχε.
+
+
+ Αυτή η λειτουργία απαιτεί αυξημένα δικαιώματα.\n\n
+ Αλλαγή σε λειτουργία πρόσβασης Root;
+
+
+
+ Γονικός φάκελος
+
+ Εξωτερικός αποθ. χώρος
+
+ Αποθ. χώρος USB
+
+
+ Πληροφορίες συστήματος αρχείων
+
+ Επιλογές ταξινόμησης
+
+ Επιλογές διάταξης
+
+ Άλλες επιλογές εμφάνισης
+
+ Έγινε
+
+ Ενέργειες
+
+ Ιστορικό
+
+ Σελιδοδείκτες
+
+ Αναζήτηση
+
+ Περισσότερες επιλογές
+
+ Μονάδες αποθήκευσης
+
+ Αποθήκευση
+
+
+ Κατά όνομα ▲
+
+ Κατά όνομα ▼
+
+ Κατά ημερομηνία ▲
+
+ Κατά ημερομηνία ▼
+
+
+ Εικονίδια
+
+ Απλή
+
+ Λεπτομέρειες
+
+
+ Εμφάνιση φακέλων πρώτα
+
+ Εμφάνιση κρυφών αρχείων
+
+ Εμφάνιση αρχείων συστήματος
+
+ Εμφάνιση symlink
+
+
+ Καμία πληροφορία
+
+ Δεν υπάρχουν διαθέσιμες πληροφορίες για το σύστημα αρχείων.
+
+
+ Το σύστημα αρχείων δεν μπορεί να προσαρτηθεί/αποπροσαρτηθεί.
+
+ Η προσάρτηση του συστήματος αρχείων δεν επιτρέπεται
+ στην Ασφαλή Λειτουργία. Πιέστε για αλλαγή σε λειτουργία πρόσβασης Root.
+
+ Η προσάρτηση του συστήματος αρχείων απέτυχε.
+ Μερικά συστήματα αρχείων, όπως οι κάρτες SD, δεν μπορούν να προσαρτηθούν/αποπροσαρτηθούν επειδή
+ έχουν ενσωματωθεί ως συστήματα αρχείων μόνο για ανάγνωση.
+
+ Πληροφορίες συστήματος αρχείων
+
+ Πληροφορίες
+
+ Χρήση δίσκου
+
+ Κατάσταση:
+
+ Σημ. προσάρτησης:
+
+ Συσκευή:
+
+ Τύπος:
+
+ Επιλογές:
+
+ Dump / Pass:
+
+ Συνολικά:
+
+ Σε χρήση:
+
+ Ελεύθερα:
+
+
+
+ Η αλλαγή δικαιωμάτων δεν επιτρέπεται
+ στην Ασφαλή Λειτουργία. Πιέστε για αλλαγή σε λειτουργία πρόσβασης Root.
+
+ Η αλλαγή ιδιοκτήτη απέτυχε.\n\n
+ Για λόγους ασφαλείας, μερικά συστήματα αρχείων, όπως οι κάρτες SD, δεν επιτρέπουν την αλλαγή ιδιοκτήτη.
+
+ Η αλλαγή γκρουπ απέτυχε.\n\n
+ Για λόγους ασφαλείας, μερικά συστήματα αρχείων, όπως οι κάρτες SD, δεν επιτρέπουν την αλλαγή γκρουπ.
+
+ Η αλλαγή δικαιωμάτων απέτυχε.\n\n
+ Για λόγους ασφαλείας, μερικά συστήματα αρχείων, όπως οι κάρτες SD, δεν επιτρέπουν την αλλαγή δικαιωμάτων.
+
+ Ιδιότητες
+
+ Πληροφορίες
+
+ Δικαιώματα
+
+ Όνομα:
+
+ Γονικός:
+
+ Τύπος:
+
+ Κατηγορία:
+
+ Link:
+
+ Μέγεθος:
+
+ Περιέχει:
+
+ Τελ. προσπέλαση:
+
+ Ιδιοκτήτης:
+
+ Γκρουπ:
+
+ Άλλοι:
+
+
+ - 0 φάκελοι
+ - 1 φάκελος
+ - %1$d φάκελοι
+
+
+
+ - 0 αρχεία
+ - 1 αρχείο
+ - %1$d αρχεία
+
+
+
+ Ιστορικό
+
+ Το ιστορικό είναι άδειο.
+
+ Άγνωστο στοιχείο ιστορικού.
+
+
+ Αποτελέσματα αναζήτησης
+
+ Πληκτρολογήστε για αναζήτηση
+
+ Μιλήστε για αναζήτηση
+
+ Ένα σφάλμα προέκυψε κατά την αναζήτηση. Δεν βρέθηκαν αποτέλεσματα.
+
+ Δέν βρέθηκαν αποτελέσματα.
+
+
+ - Δέν βρέθηκαν αντικείμενα
+ - Βρέθηκε 1 αντικείμενο
+ - Βρέθηκαν %d αντικείμενα
+
+
+ %1$s in
+ %2$s
+
+ Όροι:]]> %1$s
+
+ Επιβεβαίωση αναζήτησης
+
+ Μερικοί από τους όρους αναζήτησης έχουν μικρό αριθμό χαρακτήρων. Η
+ λειτουργία μπορεί να είναι πολύ δαπανηρή σε χρόνο και σε πόρους του συστήματος. \n\nΘέλετε να συνεχίσετε;
+
+ Παρακαλώ περιμένετε...
+
+ Αναζήτηση σε εξέλιξη
+
+
+ Επιλέξτε ένα αρχείο
+
+
+ Επεξεργασία
+
+ Μη έγκυρο αρχείο.
+
+ Το αρχείο δεν βρέθηκε.
+
+ Το αρχείο είναι πολύ μεγάλο για να ανοιχθεί.
+
+ Επιβεβαίωση εξόδου
+
+ Υπάρχουν μη αποθηκευμένες αλλαγές.\n\nΈξοδος χωρίς αποθήκευση;
+
+ Το αρχείο αποθηκεύτηκε επιτυχώς.
+
+ Το αρχείο ανοίχθηκε σε λειτουργία μόνο για ανάγνωση.
+
+
+ Σελιδοδείκτες
+
+ Αρχική
+
+ Ριζικός φάκελος
+
+ Φάκελος συστήματος
+
+ Ρυθμίστε το αρχικό φάκελο.
+
+ Αφαίρεση σελιδοδείκτη.
+
+ Ο σελιδοδείκτης προστέθηκε με επιτυχία.
+
+
+ Αρχικός φάκελος
+
+ Επιλέξτε τον αρχικό φάκελο:
+
+ Δεν επιτρέπονται σχετικές διαδρομές.
+
+ Προέκυψε σφάλμα κατά την αποθήκευση του αρχικού φακέλου.
+
+
+ Ιστορικό
+
+ Σελιδοδείκτες
+
+ Αναζήτηση
+
+ Ρυθμίσεις
+
+ Καθαρισμός ιστορικού
+
+
+
+ %1$s - copy%2$s
+
+
+ %1$s - new%2$s
+
+
+ Εκτέλεση λειτουργίας\u2026
+
+ Αντιγραφή\u2026
+
+
+ Από]]> %1$s]]>
+ Σε]]> %2$s
+
+ Μετακίνηση\u2026
+
+
+ Από]]> %1$s]]>
+ Σε]]> %2$s
+
+ Διαγραφή\u2026
+
+
+ Αρχείο]]> %1$s
+
+ Αποσυμπίεση\u2026
+
+
+ Αρχείο]]> %1$s
+
+ Συμπίεση\u2026
+
+
+ Αρχείο]]> %1$s
+
+
+ Ανάλυση\u2026]]>
+
+
+ Η αποσυμπίεση ολοκληρώθκε με επιτυχία. Τα αποσυμπιεσμένα αρχεία βρίσκονται στο
+ %1$s.
+
+
+ Η συμπίεση ολοκληρώθηκε με επιτυχία. Τα αρχεία συμπιέστηκαν στο
+ %1$s.
+
+
+ Ενέργειες
+
+ Ιδιότητες
+
+ Ανανέωση
+
+ Νέος φάκελος
+
+ Νέο αρχείο
+
+ Επιλογή όλων
+
+ Αποεπιλογή όλων
+
+ Επιλογή
+
+ Αποεπιλογή
+
+ Επικόλληση επιλογής
+
+ Μετακίνηση επιλογής
+
+ Διαγραφή επιλογής
+
+ Συμπίεση επιλογής
+
+ Δημιουργία συνδέσμου
+
+ Άνοιγμα
+
+ Άνοιγμα με
+
+ Εκτέλεση
+
+ Αποστολή
+
+ Συμπίεση
+
+ Αποσυμπίεση
+
+ Διαγραφή
+
+ Μετονομασία
+
+ Δημ. αντίγραφου
+
+ Ιδιότητες
+
+ Προσθ. στους σελιδοδείκτες
+
+ Προσθήκη συντόμευσης
+
+ Άνοιγμα γονικού
+
+
+
+ Αυτή η ενέργεια δεν μπορεί να αναιρεθεί. Θέλετε να συνεχίσετε;
+
+
+ Όνομα:
+
+ Το όνομα δεν μπορεί να είναι κενό.
+
+ Μη έγκυρο όνομα. Οι χαρακτήρες
+ \'%1$s\' δεν επιτρέπονται.
+
+ Μη έγκυρο όνομα. Τα ονόματα \'.\' και
+ \'..\' δεν επιτρέπονται.
+
+ Το όνομα υπάρχει ήδη.
+
+
+ Συσχετισμοί
+
+ Αποθήκευση επιλογής
+
+ Άνοιγμα με
+
+ Άνοιγμα
+
+ Αποστολή με
+
+ Αποστολή
+
+
+ Τίποτα για συμπλήρωση.
+
+
+ Κονσόλα
+
+ Script:
+
+ Ώρα:
+
+ Exit code:
+
+
+ %1$s δευτ.
+
+
+ Φάκελος
+
+ Symlink
+
+ Άγνωστο
+
+
+ Επιλέχθηκε %1$s φάκελος.
+ Επιλέχθηκαν %1$s φάκελοι.
+ Επιλέχθηκε %1$s αρχείο.
+ Επιλέχθηκαν %1$s αρχεία.
+ Επιλέχθηκαν %1$s φάκελοι και
+ %2$s αρχείο.
+ Επιλέχθηκαν %1$s φάκελος και
+ %2$s αρχεία.
+ Επιλέχθηκαν %1$s φάκελοι
+ και %2$s αρχεία.
+
+
+ SYSTEM
+ APP
+ BINARY
+ TEXT
+ DOCUMENT
+ EBOOK
+ MAIL
+ COMPRESS
+ EXECUTABLE
+ DATABASE
+ FONT
+ IMAGE
+ AUDIO
+ VIDEO
+ SECURITY
+
+
+ Λειτουργία συμπίεσης
+
+
+ Αποτυχία χειρισμού της συντόμευσης.
+
+ Επιτυχής δημιουργία συντόμευσης.
+
+ Αποτυχία δημιουργίας συντόμευσης.
+
+
+ Ρυθμίσεις
+
+ Γενικές ρυθμίσεις
+
+ Επιλογές αναζήτησης
+
+ Θέματα
+
+ Σχετικά
+
+ Διαχείριση αρχείων v%1$s
+ \nCopyright \u00A9 2012 The CyanogenMod Project
+
+
+ Γενικά
+
+ Χρήση ταξινόμησης πεζών-κεφαλαίων
+
+ Προειδοποίηση χρήσης δίσκου
+
+
+ Εμφάνιση διαφορετικού
+ χρώματος στα widget χρήσης δίσκου όταν καταληφθεί το %1$s τοις εκατό
+ του ελεύθερου χώρου
+
+ Υπολογισμός στατιστικών φακέλου
+
+ Προσοχή! Ο υπολογισμός των στατιστικών φακέλου είναι δαπανηρός σε χρόνο και
+ πόρους του συστήματος
+
+ Χρήση χειρονομιών swipe
+
+ Κάντε swipe από αριστερά προς δεξιά για διαγραφή αρχείων ή φακέλων.
+
+ Για προχωρημένους
+
+ Λειτουργία πρόσβασης
+
+ Ασφαλής Λειτουργία
+
+ Ασφαλής Λειτουργία\n\nΗ εφαρμογή τρέχει χωρίς
+ δικαιώματα και τα μόνα προσπελάσιμα συστήματα αρχείων είναι οι κάρτες SD και οι αποθηκευτικοί χώροι USB
+
+ Λειτουργία ερώτησης χρήστη
+
+ Λειτουργία ερώτησης χρήστη\n\nΗ εφαρμογή τρέχει
+ με πλήρη πρόσβαση στο σύστημα αρχείων, αλλά θα ζητήσει άδεια πριν από την εκτέλεση
+ οποιασδήποτε ενέργειας που απαιτεί δικαιώματα
+
+ Λειτουργία πρόσβασης Root
+
+ Λειτουργία πρόσβασης Root\n\nΠροσοχή! Αυτή η λειτουργία επιτρέπει ενέργειες που θα μπορούσαν να χαλάσουν
+ τη συσκευή σας. Είναι δική σας ευθύνη να διασφαλίσετε ότι μία ενέργεια είναι ασφαλής
+
+ Αποτελέσματα
+
+ Εμφάνιση widget συνάφειας
+
+ Επισήμανση όρων αναζήτησης
+
+ Ταξινόμηση αποτελεσμάτων
+
+ Χωρίς ταξινόμηση
+
+ Κατά όνομα
+
+ Κατά συνάφεια
+
+ Απόρρητο
+
+ Αποθήκευση όρων αναζήτησης
+
+ Οι όροι θα αποθηκεύνται και θα χρησιμοποιούνται ως προτάσεις
+ σε μελλοντικές αναζητήσεις
+
+ Οι όροι δεν θα αποθηκεύονται
+
+ Διαγραφή αποθηκευμένων όρων
+
+ Πιέστε για διαγραφή όλων των αποθηκευμένων όρων αναζήτησης
+
+ Όλοι οι αποθηκευμένοι όροι αναζήτησης έχουν διαγραφεί.
+
+ Θέματα
+
+ Ορισμός θέματος
+
+ Δεν υπάρχει\nδιαθέσιμη προεπισκόπηση
+
+ Το θέμα εφαρμόστηκε με επιτυχία.
+
+ Το θέμα δεν βρέθηκε.
+
+
+ Καταγραφή πληροφοριών αποσφαλμάτωσης
+
+
+ Ανοιχτόχρωμο θέμα
+
+ Ένα ανοιχτόχρωμο θέμα για την Διαχείριση αρχείων του CyanogenMod.
+
+ CyanogenMod
+
+
+ Προσοχή!\n\n
+ Η εξαγωγή ενός αρχείου με σχετικά ή απόλυτα μονοπάτια μπορεί να προκαλέσει
+ βλάβη στη συσκευή σας αντικαταστώντας αρχεία συστήματος.\n\n
+ Θέλετε να συνεχίσετε;
+
+
+ Changelog
+
+
+ Καλώς ήλθατε
+
+
+ Καλώς ήλθατε στη Διαχείριση αρχείων του CyanogenMod.
+ \n\nΗ εφαρμογή αυτή σας επιτρέπει να εξερευνήσετε το σύστημα αρχείων και να εκτελέσετε ενέργειες που
+ ενδέχεται να χαλάσουν τη συσκευή σας. Για την αποφυγή πρόκλησης βλάβης, η εφαρμογή θα ξεκινήσει σε
+ Ασφαλή Λειτουργία.\n\nΜπορείτε να αποκτήσετε πρόσβαση στην προηγμένη λειτουργία πρόσβασης Root μέσω
+ των ρυθμίσεων. Είναι δική σας ευθύνη να διασφαλίσετε ότι μία ενέργεια είναι ασφαλής για την συσκευή σας.
+ \n\nCyanogenMod Team.\n
+
+
diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml
index aa2838c92..ff1c00e53 100644
--- a/res/values-hu/strings.xml
+++ b/res/values-hu/strings.xml
@@ -403,13 +403,13 @@
Elvet
- Kijelölés beillesztése
+ Kijelöltek beillesztése
- Kijelölés mozgatása
+ Kijelöltek mozgatása
- Kijelölés törlése
+ Kijelöltek törlése
- Kijelölés tömörítése
+ Kijelöltek tömörítése
Link létrehozása
@@ -555,7 +555,7 @@
Kézmozdulatok használata
- A balról jobbra elhúzott mozdulat használata a fájl vagy mappa törléshez.
+ Fájlok és mappák törlése jobbra történő elhúzással.
Speciális
@@ -575,7 +575,7 @@
Találatok
- Vonatkozási modul megjelenítése
+ Relevancia modul megjelenítése
Keresési feltételek kiemelése
diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml
index b168bca17..f2d174fae 100644
--- a/res/values-ro/strings.xml
+++ b/res/values-ro/strings.xml
@@ -285,6 +285,7 @@
Eliminaţi termenii de căutare salvaţi
Apăsaţi pentru eliminarea tuturor termenilor de căutare salvaţi
Toţi termenii de căutare salvaţi au fost eliminaţi.
+ Teme
Teme
Aplicaţi tema
Nici o previzualizare\ndisponibilă
diff --git a/src/com/cyanogenmod/filemanager/activities/EditorActivity.java b/src/com/cyanogenmod/filemanager/activities/EditorActivity.java
index 912c0befb..6b682ad2c 100644
--- a/src/com/cyanogenmod/filemanager/activities/EditorActivity.java
+++ b/src/com/cyanogenmod/filemanager/activities/EditorActivity.java
@@ -459,7 +459,10 @@ private void readFile() {
this, R.string.editor_invalid_file_msg, Toast.LENGTH_SHORT);
return;
}
- this.mReadOnly = (action.compareTo(Intent.ACTION_VIEW) == 0);
+ // This var should be set depending on ACTION_VIEW or ACTION_EDIT action, but for
+ // better compatibility, IntentsActionPolicy use always ACTION_VIEW, so we have
+ // to ignore this check here
+ this.mReadOnly = false;
// Read the intent and check that is has a valid request
String path = getIntent().getData().getPath();
diff --git a/src/com/cyanogenmod/filemanager/activities/PickerActivity.java b/src/com/cyanogenmod/filemanager/activities/PickerActivity.java
index e40106411..5d3c03365 100644
--- a/src/com/cyanogenmod/filemanager/activities/PickerActivity.java
+++ b/src/com/cyanogenmod/filemanager/activities/PickerActivity.java
@@ -19,6 +19,7 @@
import android.app.Activity;
import android.app.AlertDialog;
import android.content.BroadcastReceiver;
+import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnCancelListener;
@@ -45,6 +46,7 @@
import com.cyanogenmod.filemanager.adapters.CheckableListAdapter.CheckableItem;
import com.cyanogenmod.filemanager.console.ConsoleBuilder;
import com.cyanogenmod.filemanager.model.FileSystemObject;
+import com.cyanogenmod.filemanager.preferences.DisplayRestrictions;
import com.cyanogenmod.filemanager.preferences.FileManagerSettings;
import com.cyanogenmod.filemanager.preferences.Preferences;
import com.cyanogenmod.filemanager.ui.ThemeManager;
@@ -60,7 +62,9 @@
import java.io.File;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
/**
* The activity for allow to use a {@link NavigationView} like, to pick a file from other
@@ -84,7 +88,22 @@ public void onReceive(Context context, Intent intent) {
}
};
- private String mMimeType;
+ // The result code
+ private static final int RESULT_CROP_IMAGE = 1;
+
+ // The component that holds the crop operation. We use Gallery3d because we are confidence
+ // of his input parameters
+ private static final ComponentName CROP_COMPONENT =
+ new ComponentName(
+ "com.android.gallery3d", //$NON-NLS-1$
+ "com.android.gallery3d.app.CropImage"); //$NON-NLS-1$
+
+ // Gallery crop editor action
+ private static final String ACTION_CROP = "com.android.camera.action.CROP"; //$NON-NLS-1$
+
+ // Extra data for Gallery CROP action
+ private static final String EXTRA_CROP = "crop"; //$NON-NLS-1$
+
private FileSystemObject mFso; // The picked item
private AlertDialog mDialog;
private Handler mHandler;
@@ -151,14 +170,38 @@ public void onConfigurationChanged(Configuration newConfig) {
private void init() {
// Check that call has a valid request (GET_CONTENT a and mime type)
String action = getIntent().getAction();
- this.mMimeType = getIntent().getType();
- if (action.compareTo(Intent.ACTION_GET_CONTENT.toString()) != 0 ||
- this.mMimeType == null) {
+
+ if (action.compareTo(Intent.ACTION_GET_CONTENT.toString()) != 0) {
setResult(Activity.RESULT_CANCELED);
finish();
return;
}
+ // Display restrictions
+ Map restrictions = new HashMap();
+ //- Mime/Type restriction
+ String mimeType = getIntent().getType();
+ if (mimeType != null) {
+ restrictions.put(DisplayRestrictions.MIME_TYPE_RESTRICTION, mimeType);
+ }
+ // Other restrictions
+ Bundle extras = getIntent().getExtras();
+ if (extras != null) {
+ //-- File size
+ if (extras.containsKey(android.provider.MediaStore.Audio.Media.EXTRA_MAX_BYTES)) {
+ long size =
+ extras.getLong(android.provider.MediaStore.Audio.Media.EXTRA_MAX_BYTES);
+ restrictions.put(DisplayRestrictions.SIZE_RESTRICTION, Long.valueOf(size));
+ }
+ //-- Local filesystems only
+ if (extras.containsKey(Intent.EXTRA_LOCAL_ONLY)) {
+ boolean localOnly = extras.getBoolean(Intent.EXTRA_LOCAL_ONLY);
+ restrictions.put(
+ DisplayRestrictions.LOCAL_FILESYSTEM_ONLY_RESTRICTION,
+ Boolean.valueOf(localOnly));
+ }
+ }
+
// Create or use the console
if (!initializeConsole()) {
// Something when wrong. Display a message and exit
@@ -187,7 +230,7 @@ public void run() {
// Navigation view
this.mNavigationView =
(NavigationView)this.mRootView.findViewById(R.id.navigation_view);
- this.mNavigationView.setMimeType(this.mMimeType);
+ this.mNavigationView.setRestrictions(restrictions);
this.mNavigationView.setOnFilePickedListener(this);
this.mNavigationView.setBreadcrumb(breadcrumb);
@@ -265,16 +308,68 @@ private boolean initializeConsole() {
return false;
}
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ switch (requestCode) {
+ case RESULT_CROP_IMAGE:
+ // Return what the callee activity returns
+ setResult(resultCode, data);
+ finish();
+ return;
+
+ default:
+ break;
+ }
+
+ // The response is not understood
+ Log.w(TAG,
+ String.format(
+ "Ignore response. requestCode: %s, resultCode: %s, data: %s", //$NON-NLS-1$
+ Integer.valueOf(requestCode),
+ Integer.valueOf(resultCode),
+ data));
+ DialogHelper.showToast(this, R.string.msgs_operation_failure, Toast.LENGTH_SHORT);
+ }
+
/**
* {@inheritDoc}
*/
@Override
public void onDismiss(DialogInterface dialog) {
if (this.mFso != null) {
+ File src = new File(this.mFso.getFullPath());
+ if (getIntent().getExtras() != null) {
+ // Some AOSP applications use the gallery to edit and crop the selected image
+ // with the Gallery crop editor. In this case pass the picked file to the
+ // CropActivity with the requested parameters
+ // Expected result is on onActivityResult
+ Bundle extras = getIntent().getExtras();
+ String crop = extras.getString(EXTRA_CROP);
+ if (Boolean.parseBoolean(crop)) {
+ // We want to use the Gallery3d activity because we know about it, and his
+ // parameters. At least we have a compatible one.
+ Intent intent = new Intent(ACTION_CROP);
+ if (getIntent().getType() != null) {
+ intent.setType(getIntent().getType());
+ }
+ intent.setData(Uri.fromFile(src));
+ intent.putExtras(extras);
+ intent.setComponent(CROP_COMPONENT);
+ startActivityForResult(intent, RESULT_CROP_IMAGE);
+ return;
+ }
+ }
+
+ // Return the picked file, as expected (this activity should fill the intent data
+ // and return RESULT_OK result)
Intent result = new Intent();
- result.setData(Uri.fromFile(new File(this.mFso.getFullPath())));
+ result.setData(Uri.fromFile(src));
setResult(Activity.RESULT_OK, result);
finish();
+
} else {
cancel();
}
diff --git a/src/com/cyanogenmod/filemanager/commands/java/ReadCommand.java b/src/com/cyanogenmod/filemanager/commands/java/ReadCommand.java
index 5aa4b96a9..3a7490a4b 100644
--- a/src/com/cyanogenmod/filemanager/commands/java/ReadCommand.java
+++ b/src/com/cyanogenmod/filemanager/commands/java/ReadCommand.java
@@ -24,9 +24,9 @@
import com.cyanogenmod.filemanager.console.InsufficientPermissionsException;
import com.cyanogenmod.filemanager.console.NoSuchFileOrDirectory;
-import java.io.BufferedReader;
+import java.io.BufferedInputStream;
import java.io.File;
-import java.io.FileReader;
+import java.io.FileInputStream;
/**
* A class for read a file.
@@ -121,12 +121,12 @@ public void execute()
*/
private void read(File file) {
// Read the file
- BufferedReader br = null;
+ BufferedInputStream bis = null;
try {
- br = new BufferedReader(new FileReader(file), getBufferSize());
+ bis = new BufferedInputStream(new FileInputStream(file), getBufferSize());
int read = 0;
- char[] data = new char[getBufferSize()];
- while ((read = br.read(data, 0, getBufferSize())) != -1) {
+ byte[] data = new byte[getBufferSize()];
+ while ((read = bis.read(data, 0, getBufferSize())) != -1) {
if (this.mAsyncResultListener != null) {
byte[] readData = new byte[read];
System.arraycopy(data, 0, readData, 0, read);
@@ -154,8 +154,8 @@ private void read(File file) {
} finally {
try {
- if (br != null) {
- br.close();
+ if (bis != null) {
+ bis.close();
}
} catch (Throwable _throw) {/**NON BLOCK**/}
}
diff --git a/src/com/cyanogenmod/filemanager/preferences/DisplayRestrictions.java b/src/com/cyanogenmod/filemanager/preferences/DisplayRestrictions.java
new file mode 100644
index 000000000..2525ade4e
--- /dev/null
+++ b/src/com/cyanogenmod/filemanager/preferences/DisplayRestrictions.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2012 The CyanogenMod Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.cyanogenmod.filemanager.preferences;
+
+/**
+ * An enumeration of the restrictions that can be applied when displaying list of files.
+ */
+public enum DisplayRestrictions {
+ /**
+ * Restriction for display only files with the category.
+ */
+ CATEGORY_TYPE_RESTRICTION,
+ /**
+ * Restriction for display only files with the mime/type.
+ */
+ MIME_TYPE_RESTRICTION,
+ /**
+ * Restriction for display only files with a size lower than the specified
+ */
+ SIZE_RESTRICTION,
+ /**
+ * Restriction for display only files from the local file system. Avoid remote files.
+ */
+ LOCAL_FILESYSTEM_ONLY_RESTRICTION
+}
diff --git a/src/com/cyanogenmod/filemanager/tasks/SearchResultDrawingAsyncTask.java b/src/com/cyanogenmod/filemanager/tasks/SearchResultDrawingAsyncTask.java
index df91b8778..c53d59c61 100644
--- a/src/com/cyanogenmod/filemanager/tasks/SearchResultDrawingAsyncTask.java
+++ b/src/com/cyanogenmod/filemanager/tasks/SearchResultDrawingAsyncTask.java
@@ -28,6 +28,7 @@
import com.cyanogenmod.filemanager.model.Query;
import com.cyanogenmod.filemanager.model.SearchResult;
import com.cyanogenmod.filemanager.preferences.AccessMode;
+import com.cyanogenmod.filemanager.preferences.DisplayRestrictions;
import com.cyanogenmod.filemanager.preferences.FileManagerSettings;
import com.cyanogenmod.filemanager.preferences.NavigationSortMode;
import com.cyanogenmod.filemanager.preferences.ObjectStringIdentifier;
@@ -40,7 +41,9 @@
import java.util.Collections;
import java.util.Comparator;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
/**
* A class for paint the resulting file system object of a search.
@@ -112,11 +115,17 @@ protected Boolean doInBackground(Object... params) {
boolean chRooted =
FileManagerApplication.getAccessMode().compareTo(AccessMode.SAFE) == 0;
+ // Create display restrictions
+ Map restrictions =
+ new HashMap();
+ restrictions.put(
+ DisplayRestrictions.MIME_TYPE_RESTRICTION, MimeTypeHelper.ALL_MIME_TYPES);
+
//Process all the data
final List result =
SearchHelper.convertToResults(
FileHelper.applyUserPreferences(
- this.mFiles, MimeTypeHelper.ALL_MIME_TYPES, true, chRooted),
+ this.mFiles, restrictions, true, chRooted),
this.mQueries);
if (mode.compareTo(SearchSortResultMode.NAME) == 0) {
Collections.sort(result, new Comparator() {
diff --git a/src/com/cyanogenmod/filemanager/ui/dialogs/AssociationsDialog.java b/src/com/cyanogenmod/filemanager/ui/dialogs/AssociationsDialog.java
index 370043319..096bacdbd 100644
--- a/src/com/cyanogenmod/filemanager/ui/dialogs/AssociationsDialog.java
+++ b/src/com/cyanogenmod/filemanager/ui/dialogs/AssociationsDialog.java
@@ -127,8 +127,7 @@ public AssociationsDialog(
*/
private void init(int icon, String title, String action,
OnCancelListener onCancelListener, OnDismissListener onDismissListener) {
- boolean isPlatformSigned =
- AndroidHelper.isAppPlatformSignature(this.mContext);
+ boolean isPlatformSigned = AndroidHelper.isAppPlatformSignature(this.mContext);
//Create the layout, and retrieve the views
LayoutInflater li =
@@ -138,7 +137,9 @@ private void init(int icon, String title, String action,
this.mRemember.setVisibility(
isPlatformSigned && this.mAllowPreferred ? View.VISIBLE : View.GONE);
this.mGrid = (GridView)v.findViewById(R.id.associations_gridview);
- this.mGrid.setAdapter(new AssociationsAdapter(this.mContext, this.mIntents, this));
+ AssociationsAdapter adapter =
+ new AssociationsAdapter(this.mContext, this.mIntents, this);
+ this.mGrid.setAdapter(adapter);
// Ensure a default title dialog
String dialogTitle = title;
@@ -164,27 +165,9 @@ private void init(int icon, String title, String action,
@Override
public void onClick(DialogInterface dialog, int which) {
ResolveInfo ri = getSelected();
- Intent intent = new Intent(AssociationsDialog.this.mRequestIntent);
- if (isInternalEditor(ri)) {
- // The action for internal editors (for default VIEW)
- String a = Intent.ACTION_VIEW;
- if (ri.activityInfo.metaData != null) {
- a = ri.activityInfo.metaData.getString(
- IntentsActionPolicy.EXTRA_INTERNAL_ACTION,
- Intent.ACTION_VIEW);
- }
- intent.setAction(a);
- }
- intent.setFlags(
- intent.getFlags() &~
- Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
- intent.addFlags(
- Intent.FLAG_ACTIVITY_FORWARD_RESULT |
- Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP);
- intent.setComponent(
- new ComponentName(
- ri.activityInfo.applicationInfo.packageName,
- ri.activityInfo.name));
+ Intent intent =
+ IntentsActionPolicy.getIntentFromResolveInfo(
+ ri, AssociationsDialog.this.mRequestIntent);
// Open the intent (and remember the action is the check is marked)
onIntentSelected(
@@ -228,6 +211,16 @@ public void onItemClick(AdapterView> parent, View view, int position, long id)
deselectAll();
((ViewGroup)view).setSelected(true);
+ // Internal editors can be associated
+ boolean isPlatformSigned = AndroidHelper.isAppPlatformSignature(this.mContext);
+ if (isPlatformSigned && this.mAllowPreferred) {
+ ResolveInfo ri = getSelected();
+ this.mRemember.setVisibility(
+ IntentsActionPolicy.isInternalEditor(ri) ?
+ View.INVISIBLE :
+ View.VISIBLE);
+ }
+
// Enable action button
this.mDialog.getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(true);
}
@@ -255,10 +248,7 @@ boolean checkUserPreferences() {
if (item != null) {
if (!item.isSelected()) {
onItemClick(null, item, i, item.getId());
-
- // Not allow to revert remember status
this.mRemember.setChecked(true);
- this.mRemember.setEnabled(false);
ret = false;
} else {
this.mLoaded = true;
@@ -348,82 +338,103 @@ ResolveInfo getSelected() {
*/
@SuppressWarnings({"deprecation"})
void onIntentSelected(ResolveInfo ri, Intent intent, boolean remember) {
- if (remember && !isInternalEditor(ri) && ri.filter != null) {
- // Build a reasonable intent filter, based on what matched.
- IntentFilter filter = new IntentFilter();
- if (intent.getAction() != null) {
- filter.addAction(intent.getAction());
- }
- Set categories = intent.getCategories();
- if (categories != null) {
- for (String cat : categories) {
- filter.addCategory(cat);
- }
+ boolean isPlatformSigned = AndroidHelper.isAppPlatformSignature(this.mContext);
+
+ // Register preferred association is only allowed by platform signature
+ // The app will be signed with this signature, but when is launch from
+ // inside ADT, the app is signed with testkey.
+ if (isPlatformSigned && this.mAllowPreferred) {
+
+ PackageManager pm = this.mContext.getPackageManager();
+
+ // Remove preferred application if user don't want to remember it
+ if (this.mPreferred != null && !remember) {
+ pm.clearPackagePreferredActivities(
+ this.mPreferred.activityInfo.packageName);
}
- filter.addCategory(Intent.CATEGORY_DEFAULT);
- int cat = ri.match & IntentFilter.MATCH_CATEGORY_MASK;
- Uri data = intent.getData();
- if (cat == IntentFilter.MATCH_CATEGORY_TYPE) {
- String mimeType = intent.resolveType(this.mContext);
- if (mimeType != null) {
- try {
- filter.addDataType(mimeType);
- } catch (IntentFilter.MalformedMimeTypeException e) {
- Log.w(TAG, e);
- filter = null;
+ // Associate the activity under these circumstances:
+ // - The user has selected the remember option
+ // - The selected intent is not an internal editor (internal editors are private and
+ // can be associated)
+ // - The selected intent is not the current preferred selection
+ if (remember && !IntentsActionPolicy.isInternalEditor(ri) && !isPreferredSelected()) {
+
+ // Build a reasonable intent filter, based on what matched.
+ IntentFilter filter = new IntentFilter();
+
+ if (intent.getAction() != null) {
+ filter.addAction(intent.getAction());
+ }
+ Set categories = intent.getCategories();
+ if (categories != null) {
+ for (String cat : categories) {
+ filter.addCategory(cat);
}
}
- }
- if (data != null && data.getScheme() != null && filter != null) {
- // We need the data specification if there was no type,
- // OR if the scheme is not one of our magical "file:"
- // or "content:" schemes (see IntentFilter for the reason).
- if (cat != IntentFilter.MATCH_CATEGORY_TYPE
- || (!"file".equals(data.getScheme()) //$NON-NLS-1$
- && !"content".equals(data.getScheme()))) { //$NON-NLS-1$
- filter.addDataScheme(data.getScheme());
-
- // Look through the resolved filter to determine which part
- // of it matched the original Intent.
- Iterator aIt = ri.filter.authoritiesIterator();
- if (aIt != null) {
- while (aIt.hasNext()) {
- IntentFilter.AuthorityEntry a = aIt.next();
- if (a.match(data) >= 0) {
- int port = a.getPort();
- filter.addDataAuthority(a.getHost(),
- port >= 0 ? Integer.toString(port) : null);
- break;
- }
+ filter.addCategory(Intent.CATEGORY_DEFAULT);
+
+ int cat = ri.match & IntentFilter.MATCH_CATEGORY_MASK;
+ Uri data = intent.getData();
+ if (cat == IntentFilter.MATCH_CATEGORY_TYPE) {
+ String mimeType = intent.resolveType(this.mContext);
+ if (mimeType != null) {
+ try {
+ filter.addDataType(mimeType);
+ } catch (IntentFilter.MalformedMimeTypeException e) {
+ Log.w(TAG, e);
+ filter = null;
}
}
- Iterator pIt = ri.filter.pathsIterator();
- if (pIt != null) {
- String path = data.getPath();
- while (path != null && pIt.hasNext()) {
- PatternMatcher p = pIt.next();
- if (p.match(path)) {
- filter.addDataPath(p.getPath(), p.getType());
- break;
+ }
+ if (data != null && data.getScheme() != null && filter != null) {
+ // We need the data specification if there was no type,
+ // OR if the scheme is not one of our magical "file:"
+ // or "content:" schemes (see IntentFilter for the reason).
+ if (cat != IntentFilter.MATCH_CATEGORY_TYPE
+ || (!"file".equals(data.getScheme()) //$NON-NLS-1$
+ && !"content".equals(data.getScheme()))) { //$NON-NLS-1$
+ filter.addDataScheme(data.getScheme());
+
+ // Look through the resolved filter to determine which part
+ // of it matched the original Intent.
+ // ri.filter should not be null here because the activity matches a filter
+ // Anyway protect the access
+ if (ri.filter != null) {
+ Iterator aIt =
+ ri.filter.authoritiesIterator();
+ if (aIt != null) {
+ while (aIt.hasNext()) {
+ IntentFilter.AuthorityEntry a = aIt.next();
+ if (a.match(data) >= 0) {
+ int port = a.getPort();
+ filter.addDataAuthority(a.getHost(),
+ port >= 0 ? Integer.toString(port) : null);
+ break;
+ }
+ }
+ }
+ Iterator pIt = ri.filter.pathsIterator();
+ if (pIt != null) {
+ String path = data.getPath();
+ while (path != null && pIt.hasNext()) {
+ PatternMatcher p = pIt.next();
+ if (p.match(path)) {
+ filter.addDataPath(p.getPath(), p.getType());
+ break;
+ }
+ }
}
}
}
}
- }
- // Register preferred association is only allowed by platform signature
- // The app will be signed with this signature, but when is launch from
- // inside ADT, the app is signed with testkey.
- // Ignore it if the preferred can be saved. Only notify the user and open the
- // intent
- boolean isPlatformSigned =
- AndroidHelper.isAppPlatformSignature(this.mContext);
- if (isPlatformSigned && this.mAllowPreferred) {
- if (filter != null && !isPreferredSelected()) {
+ // If we don't have a filter then don't try to associate
+ if (filter != null) {
try {
- AssociationsAdapter adapter = (AssociationsAdapter)this.mGrid.getAdapter();
+ AssociationsAdapter adapter =
+ (AssociationsAdapter)this.mGrid.getAdapter();
final int cc = adapter.getCount();
ComponentName[] set = new ComponentName[cc];
int bestMatch = 0;
@@ -437,13 +448,12 @@ void onIntentSelected(ResolveInfo ri, Intent intent, boolean remember) {
}
}
- PackageManager pm = this.mContext.getPackageManager();
-
// The only way i found to ensure of the use of the preferred activity
// selected is to clear preferred activity associations
- // Maybe it's necessary also remove the rest of activities?
- pm.clearPackagePreferredActivities(
- this.mPreferred.activityInfo.packageName);
+ if (this.mPreferred != null) {
+ pm.clearPackagePreferredActivities(
+ this.mPreferred.activityInfo.packageName);
+ }
// This is allowed for now in AOSP, but probably in the future this will
// not work at all
@@ -465,18 +475,4 @@ void onIntentSelected(ResolveInfo ri, Intent intent, boolean remember) {
this.mContext.startActivity(intent);
}
}
-
- /**
- * Method that returns if the selected resolve info is about an internal viewer
- *
- * @param ri The resolve info
- * @return boolean If the selected resolve info is about an internal viewer
- * @hide
- */
- @SuppressWarnings("static-method")
- boolean isInternalEditor(ResolveInfo ri) {
- return ri.activityInfo.metaData != null &&
- ri.activityInfo.metaData.getBoolean(
- IntentsActionPolicy.CATEGORY_INTERNAL_VIEWER, false);
- }
}
diff --git a/src/com/cyanogenmod/filemanager/ui/policy/IntentsActionPolicy.java b/src/com/cyanogenmod/filemanager/ui/policy/IntentsActionPolicy.java
index 004719b0e..774509957 100644
--- a/src/com/cyanogenmod/filemanager/ui/policy/IntentsActionPolicy.java
+++ b/src/com/cyanogenmod/filemanager/ui/policy/IntentsActionPolicy.java
@@ -16,7 +16,9 @@
package com.cyanogenmod.filemanager.ui.policy;
+import android.content.ComponentName;
import android.content.Context;
+import android.content.IntentFilter;
import android.content.DialogInterface.OnCancelListener;
import android.content.DialogInterface.OnDismissListener;
import android.content.Intent;
@@ -41,6 +43,8 @@
import java.io.File;
import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
import java.util.List;
/**
@@ -52,6 +56,9 @@ public final class IntentsActionPolicy extends ActionsPolicy {
private static boolean DEBUG = false;
+ // The preferred package when sorting intents
+ private static final String PREFERRED_PACKAGE = "com.cyanogenmod.filemanager"; //$NON-NLS-1$
+
/**
* Extra field for the internal action
*/
@@ -84,7 +91,7 @@ public static void openFileSystemObject(
final Context ctx, final FileSystemObject fso, final boolean choose,
OnCancelListener onCancelListener, OnDismissListener onDismissListener) {
try {
- // Create the intent to
+ // Create the intent to open the file
Intent intent = new Intent();
intent.setAction(android.content.Intent.ACTION_VIEW);
@@ -177,6 +184,22 @@ private static void resolveIntent(
List info =
packageManager.
queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
+ Collections.sort(info, new Comparator() {
+ @Override
+ public int compare(ResolveInfo lhs, ResolveInfo rhs) {
+ boolean isLshCMFM =
+ lhs.activityInfo.packageName.compareTo(PREFERRED_PACKAGE) == 0;
+ boolean isRshCMFM =
+ rhs.activityInfo.packageName.compareTo(PREFERRED_PACKAGE) == 0;
+ if (isLshCMFM && !isRshCMFM) {
+ return -1;
+ }
+ if (!isLshCMFM && isRshCMFM) {
+ return 1;
+ }
+ return lhs.activityInfo.name.compareTo(rhs.activityInfo.name);
+ }
+ });
// Add the internal editors
int count = 0;
@@ -184,47 +207,70 @@ private static void resolveIntent(
int cc = internals.size();
for (int i = 0; i < cc; i++) {
Intent ii = internals.get(i);
- List ris =
+ List ie =
packageManager.
queryIntentActivities(ii, 0);
- if (ris.size() > 0) {
- ResolveInfo ri = ris.get(0);
+ if (ie.size() > 0) {
+ ResolveInfo rie = ie.get(0);
+
+ // Only if the internal is not in the query list
+ boolean exists = false;
+ int ccc = info.size();
+ for (int j = 0; j < ccc; j++) {
+ ResolveInfo ri = info.get(j);
+ if (ri.activityInfo.packageName.compareTo(
+ rie.activityInfo.packageName) == 0 &&
+ ri.activityInfo.name.compareTo(
+ rie.activityInfo.name) == 0) {
+ exists = true;
+ break;
+ }
+ }
+ if (exists) {
+ continue;
+ }
+
// Mark as internal
- if (ri.activityInfo.metaData == null) {
- ri.activityInfo.metaData = new Bundle();
- ri.activityInfo.metaData.putString(EXTRA_INTERNAL_ACTION, ii.getAction());
- ri.activityInfo.metaData.putBoolean(CATEGORY_INTERNAL_VIEWER, true);
+ if (rie.activityInfo.metaData == null) {
+ rie.activityInfo.metaData = new Bundle();
+ rie.activityInfo.metaData.putString(EXTRA_INTERNAL_ACTION, ii.getAction());
+ rie.activityInfo.metaData.putBoolean(CATEGORY_INTERNAL_VIEWER, true);
}
// Only one result must be matched
- info.add(count, ri);
+ info.add(count, rie);
count++;
}
}
}
- // Retrieve the preferred activity that can handle the file
- final ResolveInfo mPreferredInfo = packageManager.resolveActivity(intent, 0);
-
// No registered application
if (info.size() == 0) {
DialogHelper.showToast(ctx, R.string.msgs_not_registered_app, Toast.LENGTH_SHORT);
return;
}
+ // Retrieve the preferred activity that can handle the file. We only want the
+ // resolved activity if the activity is a preferred activity. Other case, the
+ // resolved activity was never added by addPreferredActivity
+ ResolveInfo mPreferredInfo = findPreferredActivity(ctx, intent, info);
+
// Is a simple open and we have an application that can handle the file?
- if (!choose &&
- ((mPreferredInfo != null && mPreferredInfo.match != 0) || info.size() == 1)) {
- // But not if the only match is the an internal editor
+ //---
+ // If we have a preferred application, then use it
+ if (!choose && (mPreferredInfo != null && mPreferredInfo.match != 0)) {
+ ctx.startActivity(getIntentFromResolveInfo(mPreferredInfo, intent));
+ return;
+ }
+ // If there are only one activity (app or internal editor), then use it
+ if (!choose && info.size() == 1) {
ResolveInfo ri = info.get(0);
- if (ri.activityInfo.metaData == null ||
- !ri.activityInfo.metaData.getBoolean(CATEGORY_INTERNAL_VIEWER, false)) {
- ctx.startActivity(intent);
- return;
- }
+ ctx.startActivity(getIntentFromResolveInfo(ri, intent));
+ return;
}
- // Otherwise, we have to show the open with dialog
+ // If we have multiples apps and there is not a preferred application then show
+ // open with dialog
AssociationsDialog dialog =
new AssociationsDialog(
ctx,
@@ -316,7 +362,7 @@ private static List createEditorIntent(Context ctx, FileSystemObject fso
category.compareTo(MimeTypeCategory.EXEC) == 0 ||
category.compareTo(MimeTypeCategory.TEXT) == 0)) {
Intent editorIntent = new Intent();
- editorIntent.setAction(Intent.ACTION_EDIT);
+ editorIntent.setAction(Intent.ACTION_VIEW);
editorIntent.addCategory(CATEGORY_INTERNAL_VIEWER);
editorIntent.addCategory(CATEGORY_EDITOR);
intents.add(editorIntent);
@@ -324,4 +370,138 @@ private static List createEditorIntent(Context ctx, FileSystemObject fso
return intents;
}
+
+ /**
+ * Method that returns an {@link Intent} from his {@link ResolveInfo}
+ *
+ * @param ri The ResolveInfo
+ * @param request The requested intent
+ * @return Intent The intent
+ */
+ public static final Intent getIntentFromResolveInfo(ResolveInfo ri, Intent request) {
+ Intent intent =
+ getIntentFromComponentName(
+ new ComponentName(
+ ri.activityInfo.applicationInfo.packageName,
+ ri.activityInfo.name),
+ request);
+ if (isInternalEditor(ri)) {
+ String a = Intent.ACTION_VIEW;
+ if (ri.activityInfo.metaData != null) {
+ a = ri.activityInfo.metaData.getString(
+ IntentsActionPolicy.EXTRA_INTERNAL_ACTION,
+ Intent.ACTION_VIEW);
+ }
+ intent.setAction(a);
+ }
+ return intent;
+ }
+
+ /**
+ * Method that returns an {@link Intent} from his {@link ComponentName}
+ *
+ * @param cn The ComponentName
+ * @param request The requested intent
+ * @return Intent The intent
+ */
+ public static final Intent getIntentFromComponentName(ComponentName cn, Intent request) {
+ Intent intent = new Intent(request);
+ intent.setFlags(
+ intent.getFlags() &~
+ Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+ intent.addFlags(
+ Intent.FLAG_ACTIVITY_FORWARD_RESULT |
+ Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP);
+ intent.setComponent(
+ new ComponentName(
+ cn.getPackageName(),
+ cn.getClassName()));
+ return intent;
+ }
+
+ /**
+ * Method that returns if the selected resolve info is about an internal viewer
+ *
+ * @param ri The resolve info
+ * @return boolean If the selected resolve info is about an internal viewer
+ * @hide
+ */
+ public static final boolean isInternalEditor(ResolveInfo ri) {
+ return ri.activityInfo.metaData != null &&
+ ri.activityInfo.metaData.getBoolean(
+ IntentsActionPolicy.CATEGORY_INTERNAL_VIEWER, false);
+ }
+
+ /**
+ * Method that retrieve the finds the preferred activity, if one exists. In case
+ * of multiple preferred activity exists the try to choose the better
+ *
+ * @param ctx The current context
+ * @param intent The query intent
+ * @param info The initial info list
+ * @return ResolveInfo The resolved info
+ */
+ private static final ResolveInfo findPreferredActivity(
+ Context ctx, Intent intent, List info) {
+
+ final PackageManager packageManager = ctx.getPackageManager();
+
+ // Retrieve the preferred activity that can handle the file. We only want the
+ // resolved activity if the activity is a preferred activity. Other case, the
+ // resolved activity was never added by addPreferredActivity
+ List pref = new ArrayList();
+ int cc = info.size();
+ for (int i = 0; i < cc; i++) {
+ ResolveInfo ri = info.get(i);
+ if (isInternalEditor(ri)) continue;
+ if (ri.activityInfo == null || ri.activityInfo.packageName == null) continue;
+ List prefActList = new ArrayList();
+ List intentList = new ArrayList();
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(intent.getAction());
+ try {
+ filter.addDataType(intent.getType());
+ } catch (Exception ex) {/**NON BLOCK**/}
+ intentList.add(filter);
+ packageManager.getPreferredActivities(
+ intentList, prefActList, ri.activityInfo.packageName);
+ if (prefActList.size() > 0) {
+ pref.add(ri);
+ }
+ }
+
+ // No preferred activity is selected
+ if (pref.size() == 0) {
+ return null;
+ }
+
+ // Sort and return the first activity
+ Collections.sort(pref, new Comparator() {
+ @Override
+ public int compare(ResolveInfo lhs, ResolveInfo rhs) {
+ if (lhs.priority > rhs.priority) {
+ return -1;
+ } else if (lhs.priority < rhs.priority) {
+ return 1;
+ }
+ if (lhs.preferredOrder > rhs.preferredOrder) {
+ return -1;
+ } else if (lhs.preferredOrder < rhs.preferredOrder) {
+ return 1;
+ }
+ if (lhs.isDefault && !rhs.isDefault) {
+ return -1;
+ } else if (!lhs.isDefault && rhs.isDefault) {
+ return 1;
+ }
+ if (lhs.match > rhs.match) {
+ return -1;
+ } else if (lhs.match > rhs.match) {
+ return 1;
+ }
+ return 0;
+ }
+ });
+ return pref.get(0);
+ }
}
diff --git a/src/com/cyanogenmod/filemanager/ui/widgets/NavigationView.java b/src/com/cyanogenmod/filemanager/ui/widgets/NavigationView.java
index 24b1af59f..dd15c7efc 100644
--- a/src/com/cyanogenmod/filemanager/ui/widgets/NavigationView.java
+++ b/src/com/cyanogenmod/filemanager/ui/widgets/NavigationView.java
@@ -46,6 +46,7 @@
import com.cyanogenmod.filemanager.parcelables.NavigationViewInfoParcelable;
import com.cyanogenmod.filemanager.parcelables.SearchInfoParcelable;
import com.cyanogenmod.filemanager.preferences.AccessMode;
+import com.cyanogenmod.filemanager.preferences.DisplayRestrictions;
import com.cyanogenmod.filemanager.preferences.FileManagerSettings;
import com.cyanogenmod.filemanager.preferences.NavigationLayoutMode;
import com.cyanogenmod.filemanager.preferences.ObjectIdentifier;
@@ -60,11 +61,12 @@
import com.cyanogenmod.filemanager.util.DialogHelper;
import com.cyanogenmod.filemanager.util.ExceptionUtil;
import com.cyanogenmod.filemanager.util.FileHelper;
-import com.cyanogenmod.filemanager.util.MimeTypeHelper;
import com.cyanogenmod.filemanager.util.StorageHelper;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
/**
* The file manager implementation view (contains the graphical representation and the input
@@ -204,7 +206,8 @@ public void onItemFlingerEnd(OnItemFlingerResponder responder,
private NAVIGATION_MODE mNavigationMode;
- private String mMimeType = MimeTypeHelper.ALL_MIME_TYPES;
+ // Restrictions
+ private Map mRestrictions;
/**
* @hide
@@ -318,6 +321,9 @@ private void init(TypedArray tarray) {
this.mNavigationMode = NAVIGATION_MODE.values()[mode];
}
+ // Initialize default restrictions (no restrictions)
+ this.mRestrictions = new HashMap();
+
//Initialize variables
this.mFiles = new ArrayList();
@@ -345,23 +351,21 @@ private void init(TypedArray tarray) {
}
/**
- * Method that returns the mime/type used by this class. Only the files with this mime/type
- * are shown.
+ * Method that returns the display restrictions to apply to this view.
*
- * @return String The mime/type
+ * @return Map The restrictions to apply
*/
- public String getMimeType() {
- return this.mMimeType;
+ public Map getRestrictions() {
+ return this.mRestrictions;
}
/**
- * Method that sets the mime/type used by this class. Only the files with this mime/type
- * are shown.
+ * Method that sets the display restrictions to apply to this view.
*
- * @param mimeType String The mime/type
+ * @param mRestrictions The restrictions to apply
*/
- public void setMimeType(String mimeType) {
- this.mMimeType = mimeType;
+ public void setRestrictions(Map mRestrictions) {
+ this.mRestrictions = mRestrictions;
}
/**
@@ -888,7 +892,7 @@ void onPostExecuteTask(
//Apply user preferences
List sortedFiles =
- FileHelper.applyUserPreferences(files, this.mMimeType, this.mChRooted);
+ FileHelper.applyUserPreferences(files, this.mRestrictions, this.mChRooted);
//Remove parent directory if we are in the root of a chrooted environment
if (this.mChRooted && StorageHelper.isStorageVolume(newDir)) {
diff --git a/src/com/cyanogenmod/filemanager/util/FileHelper.java b/src/com/cyanogenmod/filemanager/util/FileHelper.java
index bd9049799..f4f3612eb 100644
--- a/src/com/cyanogenmod/filemanager/util/FileHelper.java
+++ b/src/com/cyanogenmod/filemanager/util/FileHelper.java
@@ -16,6 +16,7 @@
package com.cyanogenmod.filemanager.util;
+import android.annotation.SuppressLint;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Resources;
@@ -39,10 +40,12 @@
import com.cyanogenmod.filemanager.model.Symlink;
import com.cyanogenmod.filemanager.model.SystemFile;
import com.cyanogenmod.filemanager.model.User;
+import com.cyanogenmod.filemanager.preferences.DisplayRestrictions;
import com.cyanogenmod.filemanager.preferences.FileManagerSettings;
import com.cyanogenmod.filemanager.preferences.NavigationSortMode;
import com.cyanogenmod.filemanager.preferences.ObjectIdentifier;
import com.cyanogenmod.filemanager.preferences.Preferences;
+import com.cyanogenmod.filemanager.util.MimeTypeHelper.MimeTypeCategory;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
@@ -53,7 +56,9 @@
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
+import java.util.Iterator;
import java.util.List;
+import java.util.Map;
/**
* A helper class with useful methods for deal with files.
@@ -156,6 +161,7 @@ public static String getHumanReadableSize(FileSystemObject fso) {
* @param size The size in bytes
* @return String The human readable size
*/
+ @SuppressLint("DefaultLocale")
public static String getHumanReadableSize(long size) {
Resources res = FileManagerApplication.getInstance().getResources();
final String format = "%d %s"; //$NON-NLS-1$
@@ -458,13 +464,14 @@ public static FileSystemObject getReference(FileSystemObject fso) {
* (sort mode, hidden files, ...).
*
* @param files The listed files
- * @param mimeType The mime-type to apply. if null returns all.
+ * @param restrictions The restrictions to apply when displaying files
* @param chRooted If app run with no privileges
* @return List The applied mode listed files
*/
public static List applyUserPreferences(
- List files, String mimeType, boolean chRooted) {
- return applyUserPreferences(files, mimeType, false, chRooted);
+ List files, Map restrictions, boolean chRooted) {
+ return applyUserPreferences(files, restrictions, false, chRooted);
}
/**
@@ -472,13 +479,14 @@ public static List applyUserPreferences(
* (sort mode, hidden files, ...).
*
* @param files The listed files
- * @param mimeType The mime-type to apply. if null returns all.
+ * @param restrictions The restrictions to apply when displaying files
* @param noSort If sort must be applied
* @param chRooted If app run with no privileges
* @return List The applied mode listed files
*/
public static List applyUserPreferences(
- List files, String mimeType, boolean noSort, boolean chRooted) {
+ List files, Map restrictions,
+ boolean noSort, boolean chRooted) {
//Retrieve user preferences
SharedPreferences prefs = Preferences.getSharedPreferences();
FileManagerSettings sortModePref = FileManagerSettings.SETTINGS_SORT_MODE;
@@ -522,12 +530,10 @@ public static List applyUserPreferences(
}
}
- //Mime/Type
- if (chRooted && !isDirectory(file)) {
- if (mimeType != null && mimeType.compareTo(MimeTypeHelper.ALL_MIME_TYPES) != 0) {
- // NOTE: We don't need the context here, because mime-type database should
- // be loaded prior to this call
- if (!MimeTypeHelper.matchesMimeType(null, file, mimeType)) {
+ // Restrictions (only apply to files)
+ if (restrictions != null) {
+ if (!isDirectory(file)) {
+ if (!isDisplayAllowed(file, restrictions)) {
files.remove(i);
continue;
}
@@ -582,6 +588,73 @@ public int compare(FileSystemObject lhs, FileSystemObject rhs) {
return files;
}
+ /**
+ * Method that check if a file should be displayed according to the restrictions
+ *
+ * @param fso The file system object to check
+ * @param restrictions The restrictions map
+ * @return boolean If the file should be displayed
+ */
+ private static boolean isDisplayAllowed(
+ FileSystemObject fso, Map restrictions) {
+ Iterator it = restrictions.keySet().iterator();
+ while (it.hasNext()) {
+ DisplayRestrictions restriction = it.next();
+ Object value = restrictions.get(restriction);
+ if (value == null) {
+ continue;
+ }
+ switch (restriction) {
+ case CATEGORY_TYPE_RESTRICTION:
+ if (value instanceof MimeTypeCategory) {
+ MimeTypeCategory cat1 = (MimeTypeCategory)value;
+ // NOTE: We don't need the context here, because mime-type
+ // database should be loaded prior to this call
+ MimeTypeCategory cat2 = MimeTypeHelper.getCategory(null, fso);
+ if (cat1.compareTo(cat2) != 0) {
+ return false;
+ }
+ }
+ break;
+
+ case MIME_TYPE_RESTRICTION:
+ if (value instanceof String) {
+ String mimeType = (String)value;
+ if (mimeType.compareTo(MimeTypeHelper.ALL_MIME_TYPES) != 0) {
+ // NOTE: We don't need the context here, because mime-type
+ // database should be loaded prior to this call
+ if (!MimeTypeHelper.matchesMimeType(null, fso, mimeType)) {
+ return false;
+ }
+ }
+ }
+ break;
+
+ case SIZE_RESTRICTION:
+ if (value instanceof Long) {
+ Long maxSize = (Long)value;
+ if (fso.getSize() > maxSize.longValue()) {
+ return false;
+ }
+ }
+ break;
+
+ case LOCAL_FILESYSTEM_ONLY_RESTRICTION:
+ if (value instanceof Boolean) {
+ Boolean localOnly = (Boolean)value;
+ if (localOnly.booleanValue()) {
+ /** TODO Needed when CMFM gets networking **/
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ return true;
+ }
+
/**
* Method that resolve the symbolic links of the list of files passed as argument.
* This method invokes the {@link ResolveLinkCommand} in those files that hasn't a valid
diff --git a/src/com/cyanogenmod/filemanager/util/ShellHelper.java b/src/com/cyanogenmod/filemanager/util/ShellHelper.java
index 4f1b92e25..e497bcf61 100644
--- a/src/com/cyanogenmod/filemanager/util/ShellHelper.java
+++ b/src/com/cyanogenmod/filemanager/util/ShellHelper.java
@@ -42,7 +42,9 @@ public static String prepareArgument(final String arg) {
if (arg == null) {
return null;
}
- return arg.replace("\"", "\\\""); //$NON-NLS-1$//$NON-NLS-2$
+ String preparedArgs = arg.replace("\"", "\\\""); //$NON-NLS-1$//$NON-NLS-2$
+ preparedArgs = preparedArgs.replace("$", "\\$"); //$NON-NLS-1$//$NON-NLS-2$
+ return preparedArgs;
}
/**
diff --git a/themes/res/values-el/strings.xml b/themes/res/values-el/strings.xml
new file mode 100644
index 000000000..add4778d8
--- /dev/null
+++ b/themes/res/values-el/strings.xml
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+ Θέματα Διαχείρισης αρχείων
+
+ Θέματα για την Διαχείριση αρχείων του CyanogenMod.
+
+
+ Σκούρο θέμα
+
+ Ένα σκούρο θέμα για την Διαχείριση αρχείων του CyanogenMod.
+
+