import android.app.Activity;
import android.app.AlertDialog;
+import android.content.ActivityNotFoundException;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnCancelListener;
import android.content.DialogInterface.OnDismissListener;
import android.content.Intent;
-import android.content.pm.ActivityInfo;
+import android.content.IntentFilter;
+import android.content.res.Configuration;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
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;
+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;
import com.cyanogenmod.filemanager.util.FileHelper;
+import com.cyanogenmod.filemanager.util.MediaHelper;
+import com.cyanogenmod.filemanager.util.MimeTypeHelper;
import com.cyanogenmod.filemanager.util.StorageHelper;
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
* application.
*/
public class PickerActivity extends Activity
- implements OnCancelListener, OnDismissListener, OnFilePickedListener {
+ implements OnCancelListener, OnDismissListener, OnFilePickedListener, OnDirectoryChangedListener {
private static final String TAG = "PickerActivity"; //$NON-NLS-1$
private static boolean DEBUG = false;
- private String mMimeType;
- private FileSystemObject mFso; // The picked item
+ private final BroadcastReceiver mNotificationReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (intent != null) {
+ if (intent.getAction().compareTo(FileManagerSettings.INTENT_THEME_CHANGED) == 0) {
+ applyTheme();
+ }
+ }
+ }
+ };
+
+ // 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.filtershow.crop.CropActivity"); //$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$
+
+ // 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;
/**
* @hide
*/
NavigationView mNavigationView;
+ private View mRootView;
/**
* {@inheritDoc}
Log.d(TAG, "PickerActivity.onCreate"); //$NON-NLS-1$
}
- //Request features
- setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
+ // Register the broadcast receiver
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(FileManagerSettings.INTENT_THEME_CHANGED);
+ registerReceiver(this.mNotificationReceiver, filter);
+
+ // Set the theme before setContentView
+ Theme theme = ThemeManager.getCurrentTheme(this);
+ theme.setBaseTheme(this, true);
// Initialize the activity
init();
}
/**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void onDestroy() {
+ if (DEBUG) {
+ Log.d(TAG, "PickerActivity.onDestroy"); //$NON-NLS-1$
+ }
+
+ // Unregister the receiver
+ try {
+ unregisterReceiver(this.mNotificationReceiver);
+ } catch (Throwable ex) {
+ /**NON BLOCK**/
+ }
+
+ //All destroy. Continue
+ super.onDestroy();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ measureHeight();
+ }
+
+ /**
* Method that displays a dialog with a {@link NavigationView} to select the
* proposed file
*/
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) {
+ 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;
}
+ // Display restrictions
+ Map<DisplayRestrictions, Object> restrictions = new HashMap<DisplayRestrictions, Object>();
+ //- Mime/Type restriction
+ String mimeType = getIntent().getType();
+ if (mimeType != null) {
+ if (!MimeTypeHelper.isMimeTypeKnown(this, mimeType)) {
+ Log.i(TAG,
+ String.format(
+ "Mime type %s unknown, falling back to wildcard.", //$NON-NLS-1$
+ mimeType));
+ mimeType = MimeTypeHelper.ALL_MIME_TYPES;
+ }
+ restrictions.put(DisplayRestrictions.MIME_TYPE_RESTRICTION, mimeType);
+ }
+ // Other restrictions
+ Bundle extras = getIntent().getExtras();
+ Log.d(TAG, "PickerActivity. extras: " + String.valueOf(extras)); //$NON-NLS-1$
+ 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));
+ }
+ }
+ if (pickingDirectory) {
+ restrictions.put(DisplayRestrictions.DIRECTORY_ONLY_RESTRICTION, Boolean.TRUE);
+ }
+
// Create or use the console
if (!initializeConsole()) {
// Something when wrong. Display a message and exit
return;
}
- // Calculate the dialog size based on the window height
- DisplayMetrics displaymetrics = new DisplayMetrics();
- getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
- final int height = displaymetrics.heightPixels;
-
// Create the root file
- final View rootView = getLayoutInflater().inflate(R.layout.picker, null, false);
- rootView.post(new Runnable() {
+ this.mRootView = getLayoutInflater().inflate(R.layout.picker, null, false);
+ this.mRootView.post(new Runnable() {
@Override
public void run() {
- FrameLayout.LayoutParams params =
- new FrameLayout.LayoutParams(
- LayoutParams.WRAP_CONTENT, (height * 70) / 100);
- rootView.setLayoutParams(params);
+ measureHeight();
}
});
// Breadcrumb
- Breadcrumb breadcrumb = (Breadcrumb)rootView.findViewById(R.id.breadcrumb_view);
+ Breadcrumb breadcrumb = (Breadcrumb)this.mRootView.findViewById(R.id.breadcrumb_view);
// Set the free disk space warning level of the breadcrumb widget
String fds = Preferences.getSharedPreferences().getString(
FileManagerSettings.SETTINGS_DISK_USAGE_WARNING_LEVEL.getId(),
// Navigation view
this.mNavigationView =
- (NavigationView)rootView.findViewById(R.id.navigation_view);
- this.mNavigationView.setMimeType(this.mMimeType);
+ (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
+ applyTheme();
+
// Create the dialog
this.mDialog = DialogHelper.createDialog(
- this, R.drawable.ic_launcher, R.string.picker_title, rootView);
+ 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
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);
- this.mDialog.show();
+ DialogHelper.delegateDialogShow(this, this.mDialog);
// Set content description of storage volume button
- ButtonItem fs = (ButtonItem)rootView.findViewById(R.id.ab_filesystem_info);
+ 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);
}
});
}
/**
+ * Method that measure the height needed to avoid resizing when
+ * change to a new directory. This method fixed the height of the window
+ * @hide
+ */
+ void measureHeight() {
+ // Calculate the dialog size based on the window height
+ DisplayMetrics displaymetrics = new DisplayMetrics();
+ getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
+ final int height = displaymetrics.heightPixels;
+
+ Configuration config = getResources().getConfiguration();
+ int percent = config.orientation == Configuration.ORIENTATION_LANDSCAPE ? 55 : 70;
+
+ FrameLayout.LayoutParams params =
+ new FrameLayout.LayoutParams(
+ LayoutParams.WRAP_CONTENT, (height * percent) / 100);
+ this.mRootView.setLayoutParams(params);
+ }
+
+ /**
* Method that initializes a console
*/
private boolean initializeConsole() {
try {
- // Is there a console allocate
- if (!ConsoleBuilder.isAlloc()) {
- // Create a ChRooted console
- ConsoleBuilder.createDefaultConsole(this, false, false);
- }
+ // Create a ChRooted console
+ ConsoleBuilder.createDefaultConsole(this, false, false);
// There is a console allocated. Use it.
return true;
} catch (Throwable _throw) {
* {@inheritDoc}
*/
@Override
- protected void onDestroy() {
- if (DEBUG) {
- Log.d(TAG, "PickerActivity.onDestroy"); //$NON-NLS-1$
+ 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;
}
- //All destroy. Continue
- super.onDestroy();
+ // 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);
}
/**
@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);
+ try {
+ startActivityForResult(intent, RESULT_CROP_IMAGE);
+ return;
+ } catch (ActivityNotFoundException e) {
+ Log.w(TAG, "Failed to find crop activity!");
+ }
+ intent.setComponent(null);
+ try {
+ startActivityForResult(intent, RESULT_CROP_IMAGE);
+ return;
+ } catch (ActivityNotFoundException e) {
+ Log.w(TAG, "Failed to find any crop 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(new File(this.mFso.getFullPath())));
+ result.setData(getResultUriForFileFromIntent(this, src, getIntent()));
setResult(Activity.RESULT_OK, result);
finish();
+
} else {
cancel();
}
}
+ private static 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 static 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 static 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 static Uri getResultUriForFileFromIntent(Context context, File src, Intent intent) {
+ // Try to find the preferred uri scheme
+ Uri result = MediaHelper.fileToContentUri(context, src);
+ if (result == null) {
+ 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}
*/
}
/**
+ * {@inheritDoc}
+ */
+ @Override
+ public void onDirectoryChanged(FileSystemObject item) {
+ this.mCurrentDirectory = item;
+ }
+
+ /**
* Method invoked when an action item is clicked.
*
* @param view The button pushed
public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
popup.dismiss();
if (volumes != null) {
-
PickerActivity.this.
mNavigationView.changeCurrentDir(volumes[position].getPath());
}
});
popup.show();
}
+
+ /**
+ * Method that applies the current theme to the activity
+ * @hide
+ */
+ void applyTheme() {
+ Theme theme = ThemeManager.getCurrentTheme(this);
+ theme.setBaseTheme(this, true);
+
+ // View
+ theme.setBackgroundDrawable(this, this.mRootView, "background_drawable"); //$NON-NLS-1$
+ this.mNavigationView.applyTheme();
+ }
}