/* * 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.activities; 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; import android.content.DialogInterface.OnDismissListener; import android.content.Intent; import android.content.IntentFilter; import android.content.res.Configuration; import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.os.storage.StorageVolume; import android.util.DisplayMetrics; import android.util.Log; import android.view.View; import android.view.ViewGroup.LayoutParams; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.FrameLayout; import android.widget.ListPopupWindow; import android.widget.Toast; import com.cyanogenmod.filemanager.R; import com.cyanogenmod.filemanager.adapters.CheckableListAdapter; 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.OnFilePickedListener; 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.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 { private static final String TAG = "PickerActivity"; //$NON-NLS-1$ private static boolean DEBUG = false; 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.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; /** * @hide */ NavigationView mNavigationView; private View mRootView; /** * {@inheritDoc} */ @Override protected void onCreate(Bundle state) { if (DEBUG) { Log.d(TAG, "PickerActivity.onCreate"); //$NON-NLS-1$ } // Register the broadcast receiver IntentFilter filter = new IntentFilter(); filter.addAction(FileManagerSettings.INTENT_THEME_CHANGED); registerReceiver(this.mNotificationReceiver, filter); // Initialize the activity init(); //Save state super.onCreate(state); } /** * {@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(); Log.d(TAG, "PickerActivity. action: " + String.valueOf(action)); //$NON-NLS-1$ if (action.compareTo(Intent.ACTION_GET_CONTENT.toString()) != 0) { setResult(Activity.RESULT_CANCELED); finish(); return; } // Display restrictions 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, "Mime type " + mimeType + " unknown, falling back to wildcard."); 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)); } } // Create or use the console if (!initializeConsole()) { // Something when wrong. Display a message and exit DialogHelper.showToast(this, R.string.msgs_cant_create_console, Toast.LENGTH_SHORT); cancel(); return; } // Create the root file this.mRootView = getLayoutInflater().inflate(R.layout.picker, null, false); this.mRootView.post(new Runnable() { @Override public void run() { measureHeight(); } }); // Breadcrumb 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(), (String)FileManagerSettings.SETTINGS_DISK_USAGE_WARNING_LEVEL.getDefaultValue()); breadcrumb.setFreeDiskSpaceWarningLevel(Integer.parseInt(fds)); // Navigation view this.mNavigationView = (NavigationView)this.mRootView.findViewById(R.id.navigation_view); this.mNavigationView.setRestrictions(restrictions); this.mNavigationView.setOnFilePickedListener(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, this.mRootView); this.mDialog.setButton( DialogInterface.BUTTON_NEUTRAL, getString(R.string.cancel), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dlg, int which) { dlg.cancel(); } }); this.mDialog.setCancelable(true); this.mDialog.setOnCancelListener(this); this.mDialog.setOnDismissListener(this); DialogHelper.delegateDialogShow(this, this.mDialog); // Set content description of storage volume button ButtonItem fs = (ButtonItem)this.mRootView.findViewById(R.id.ab_filesystem_info); fs.setContentDescription(getString(R.string.actionbar_button_storage_cd)); 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); } }); } /** * 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); } // There is a console allocated. Use it. return true; } catch (Throwable _throw) { // Capture the exception ExceptionUtil.translateException(this, _throw, true, false); } 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(src)); setResult(Activity.RESULT_OK, result); finish(); } else { cancel(); } } /** * {@inheritDoc} */ @Override public void onCancel(DialogInterface dialog) { cancel(); } /** * {@inheritDoc} */ @Override public void onFilePicked(FileSystemObject item) { this.mFso = item; this.mDialog.dismiss(); } /** * Method invoked when an action item is clicked. * * @param view The button pushed */ public void onActionBarItemClick(View view) { switch (view.getId()) { //###################### //Breadcrumb Actions //###################### case R.id.ab_filesystem_info: //Show a popup with the storage volumes to select showStorageVolumesPopUp(view); break; default: break; } } /** * Method that cancels the activity */ private void cancel() { setResult(Activity.RESULT_CANCELED); finish(); } /** * Method that shows a popup with the storage volumes * * @param anchor The view on which anchor the popup */ private void showStorageVolumesPopUp(View anchor) { // Create a list (but not checkable) final StorageVolume[] volumes = StorageHelper.getStorageVolumes(PickerActivity.this); List<CheckableItem> descriptions = new ArrayList<CheckableItem>(); if (volumes != null) { int cc = volumes.length; for (int i = 0; i < cc; i++) { String desc = StorageHelper.getStorageVolumeDescription(this, volumes[i]); CheckableItem item = new CheckableItem(desc, false, false); descriptions.add(item); } } CheckableListAdapter adapter = new CheckableListAdapter(getApplicationContext(), descriptions); //Create a show the popup menu final ListPopupWindow popup = DialogHelper.createListPopupWindow(this, adapter, anchor); popup.setOnItemClickListener(new OnItemClickListener() { @Override 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(); } }