Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 39cea3fa authored by Danny Baumann's avatar Danny Baumann Committed by Jorge Ruesga
Browse files

Allow picking of directories.

This is used e.g. by k-9 to select an attachment storage path.

There are a number of intent filter conventions for picking directories.
In k-9's code I found the following:

- action org.openintents.action.PICK_DIRECTORY, scheme file
- action com.estrongs.action.PICK_DIRECTORY, scheme file
- action Intent.ACTION_PICK, scheme folder
- action com.androidworkz.action.PICK_DIRECTORY, scheme file

Implemented is the third variant, as it's the most generic way to
describe the intention.

Change-Id: I8752fe0db923a9ca169cc09eeee6a13bb5236626
parent 6a977307
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -115,6 +115,14 @@
        <category android:name="android.intent.category.DEFAULT" />
        <data android:mimeType="*/*" />
      </intent-filter>
      <intent-filter>
        <action android:name="android.intent.action.PICK" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <data android:scheme="file" />
        <data android:scheme="folder" />
        <data android:scheme="directory" />
      </intent-filter>
    </activity>

    <activity
+2 −0
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@
    <string name="no">Nein</string>
    <string name="all">Alle</string>
    <string name="overwrite">Überschreiben</string>
    <string name="select">Auswählen</string>

    <!-- Root directory name -->
    <string name="root_directory_name"><![CDATA[<Wurzelverzeichnis>]]></string>
@@ -209,6 +210,7 @@

    <!-- Picker activity -->
    <string name="picker_title">Datei wählen</string>
    <string name="directory_picker_title">Verzeichnis wählen</string>

    <!-- Editor -->
    <string name="editor">Editor</string>
+2 −0
Original line number Diff line number Diff line
@@ -44,6 +44,7 @@
  <string name="no">No</string>
  <string name="all">All</string>
  <string name="overwrite">Overwrite</string>
  <string name="select">Select</string>

  <!-- The root directory name -->
  <string name="root_directory_name"><![CDATA[<Root folder>]]></string>
@@ -362,6 +363,7 @@
  <string name="picker" translatable="false">@string/app_name</string>
  <!-- Picker Activity * Dialog title -->
  <string name="picker_title">Pick a file</string>
  <string name="directory_picker_title">Pick a directory</string>

  <!-- Editor * Editor activity title -->
  <string name="editor">Editor</string>
+128 −12
Original line number Diff line number Diff line
@@ -54,6 +54,7 @@ import com.cyanogenmod.filemanager.ui.ThemeManager.Theme;
import com.cyanogenmod.filemanager.ui.widgets.Breadcrumb;
import com.cyanogenmod.filemanager.ui.widgets.ButtonItem;
import com.cyanogenmod.filemanager.ui.widgets.NavigationView;
import com.cyanogenmod.filemanager.ui.widgets.NavigationView.OnDirectoryChangedListener;
import com.cyanogenmod.filemanager.ui.widgets.NavigationView.OnFilePickedListener;
import com.cyanogenmod.filemanager.util.DialogHelper;
import com.cyanogenmod.filemanager.util.ExceptionUtil;
@@ -72,7 +73,7 @@ import java.util.Map;
 * application.
 */
public class PickerActivity extends Activity
        implements OnCancelListener, OnDismissListener, OnFilePickedListener {
        implements OnCancelListener, OnDismissListener, OnFilePickedListener, OnDirectoryChangedListener {

    private static final String TAG = "PickerActivity"; //$NON-NLS-1$

@@ -105,7 +106,13 @@ public class PickerActivity extends Activity
    // Extra data for Gallery CROP action
    private static final String EXTRA_CROP = "crop"; //$NON-NLS-1$

    private FileSystemObject mFso;  // The picked item
    // Scheme for file and directory picking
    private static final String FILE_URI_SCHEME = "file"; //$NON-NLS-1$
    private static final String FOLDER_URI_SCHEME = "folder"; //$NON-NLS-1$
    private static final String DIRECTORY_URI_SCHEME = "directory"; //$NON-NLS-1$

    FileSystemObject mFso;  // The picked item
    FileSystemObject mCurrentDirectory;
    private AlertDialog mDialog;
    private Handler mHandler;
    /**
@@ -169,11 +176,19 @@ public class PickerActivity extends Activity
     * proposed file
     */
    private void init() {
        // Check that call has a valid request (GET_CONTENT a and mime type)
        String action = getIntent().getAction();

        Log.d(TAG, "PickerActivity. action: " + String.valueOf(action)); //$NON-NLS-1$
        if (action.compareTo(Intent.ACTION_GET_CONTENT.toString()) != 0) {
        final boolean pickingDirectory;
        final Intent intent = getIntent();

        if (isFilePickIntent(intent)) {
            // ok
            Log.d(TAG, "PickerActivity: got file pick intent: " + String.valueOf(intent)); //$NON-NLS-1$
            pickingDirectory = false;
        } else if (isDirectoryPickIntent(getIntent())) {
            // ok
            Log.d(TAG, "PickerActivity: got folder pick intent: " + String.valueOf(intent)); //$NON-NLS-1$
            pickingDirectory = true;
        } else {
            Log.d(TAG, "PickerActivity got unrecognized intent: " + String.valueOf(intent)); //$NON-NLS-1$
            setResult(Activity.RESULT_CANCELED);
            finish();
            return;
@@ -183,7 +198,6 @@ public class PickerActivity extends Activity
        Map<DisplayRestrictions, Object> restrictions = new HashMap<DisplayRestrictions, Object>();
        //- Mime/Type restriction
        String mimeType = getIntent().getType();
        Log.d(TAG, "PickerActivity. type: " + String.valueOf(mimeType)); //$NON-NLS-1$
        if (mimeType != null) {
            if (!MimeTypeHelper.isMimeTypeKnown(this, mimeType)) {
                Log.i(TAG,
@@ -212,6 +226,9 @@ public class PickerActivity extends Activity
                        Boolean.valueOf(localOnly));
            }
        }
        if (pickingDirectory) {
            restrictions.put(DisplayRestrictions.DIRECTORY_ONLY_RESTRICTION, Boolean.TRUE);
        }

        // Create or use the console
        if (!initializeConsole()) {
@@ -243,6 +260,7 @@ public class PickerActivity extends Activity
                (NavigationView)this.mRootView.findViewById(R.id.navigation_view);
        this.mNavigationView.setRestrictions(restrictions);
        this.mNavigationView.setOnFilePickedListener(this);
        this.mNavigationView.setOnDirectoryChangedListener(this);
        this.mNavigationView.setBreadcrumb(breadcrumb);

        // Apply the current theme
@@ -250,9 +268,12 @@ public class PickerActivity extends Activity

        // Create the dialog
        this.mDialog = DialogHelper.createDialog(
            this, R.drawable.ic_launcher, R.string.picker_title, this.mRootView);
            this, R.drawable.ic_launcher,
            pickingDirectory ? R.string.directory_picker_title : R.string.picker_title,
            this.mRootView);

        this.mDialog.setButton(
                DialogInterface.BUTTON_NEUTRAL,
                DialogInterface.BUTTON_NEGATIVE,
                getString(R.string.cancel),
                new DialogInterface.OnClickListener() {
            @Override
@@ -260,6 +281,18 @@ public class PickerActivity extends Activity
                dlg.cancel();
            }
        });
        if (pickingDirectory) {
            this.mDialog.setButton(
                    DialogInterface.BUTTON_POSITIVE,
                    getString(R.string.select),
                    new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dlg, int which) {
                    PickerActivity.this.mFso = PickerActivity.this.mCurrentDirectory;
                    dlg.dismiss();
                }
            });
        }
        this.mDialog.setCancelable(true);
        this.mDialog.setOnCancelListener(this);
        this.mDialog.setOnDismissListener(this);
@@ -269,12 +302,21 @@ public class PickerActivity extends Activity
        ButtonItem fs = (ButtonItem)this.mRootView.findViewById(R.id.ab_filesystem_info);
        fs.setContentDescription(getString(R.string.actionbar_button_storage_cd));

        final File initialDir = getInitialDirectoryFromIntent(getIntent());
        final String rootDirectory;

        if (initialDir != null) {
            rootDirectory = initialDir.getAbsolutePath();
        } else {
            rootDirectory = FileHelper.ROOT_DIRECTORY;
        }

        this.mHandler = new Handler();
        this.mHandler.post(new Runnable() {
            @Override
            public void run() {
                // Navigate to. The navigation view will redirect to the appropriate directory
                PickerActivity.this.mNavigationView.changeCurrentDir(FileHelper.ROOT_DIRECTORY);
                PickerActivity.this.mNavigationView.changeCurrentDir(rootDirectory);
            }
        });

@@ -374,7 +416,7 @@ public class PickerActivity extends Activity
            // 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(src));
            result.setData(getResultUriForFileFromIntent(src, getIntent()));
            setResult(Activity.RESULT_OK, result);
            finish();

@@ -383,6 +425,72 @@ public class PickerActivity extends Activity
        }
    }

    private boolean isFilePickIntent(Intent intent) {
        final String action = intent.getAction();

        if (Intent.ACTION_GET_CONTENT.equals(action)) {
            return true;
        }
        if (Intent.ACTION_PICK.equals(action)) {
            final Uri data = intent.getData();
            if (data != null && FILE_URI_SCHEME.equals(data.getScheme())) {
                return true;
            }
        }

        return false;
    }

    private boolean isDirectoryPickIntent(Intent intent) {
        if (Intent.ACTION_PICK.equals(intent.getAction()) && intent.getData() != null) {
            String scheme = intent.getData().getScheme();
            if (FOLDER_URI_SCHEME.equals(scheme) || DIRECTORY_URI_SCHEME.equals(scheme)) {
                return true;
            }
        }

        return false;
    }

    private File getInitialDirectoryFromIntent(Intent intent) {
        if (!Intent.ACTION_PICK.equals(intent.getAction())) {
            return null;
        }

        final Uri data = intent.getData();
        if (data == null) {
            return null;
        }

        final String path = data.getPath();
        if (path == null) {
            return null;
        }

        final File file = new File(path);
        if (!file.exists() || !file.isAbsolute()) {
            return null;
        }

        if (file.isDirectory()) {
            return file;
        }
        return file.getParentFile();
    }

    private Uri getResultUriForFileFromIntent(File src, Intent intent) {
        Uri result = Uri.fromFile(src);

        if (Intent.ACTION_PICK.equals(intent.getAction()) && intent.getData() != null) {
            String scheme = intent.getData().getScheme();
            if (scheme != null) {
                result = result.buildUpon().scheme(scheme).build();
            }
        }

        return result;
    }

    /**
     * {@inheritDoc}
     */
@@ -400,6 +508,14 @@ public class PickerActivity extends Activity
        this.mDialog.dismiss();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void onDirectoryChanged(FileSystemObject item) {
        this.mCurrentDirectory = item;
    }

    /**
     * Method invoked when an action item is clicked.
     *
+4 −0
Original line number Diff line number Diff line
@@ -32,6 +32,10 @@ public enum DisplayRestrictions {
     * Restriction for display only files with a size lower than the specified
     */
    SIZE_RESTRICTION,
    /**
     * Restriction for display only directories
     */
    DIRECTORY_ONLY_RESTRICTION,
    /**
     * Restriction for display only files from the local file system. Avoid remote files.
     */
Loading