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. + +