/*
* 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.ui.dialogs;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.res.Resources;
import android.os.AsyncTask;
import android.util.Log;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.Spinner;
import android.widget.TextView;
import com.cyanogenmod.filemanager.FileManagerApplication;
import com.cyanogenmod.filemanager.R;
import com.cyanogenmod.filemanager.commands.AsyncResultListener;
import com.cyanogenmod.filemanager.commands.FolderUsageExecutable;
import com.cyanogenmod.filemanager.console.ConsoleBuilder;
import com.cyanogenmod.filemanager.model.AID;
import com.cyanogenmod.filemanager.model.FileSystemObject;
import com.cyanogenmod.filemanager.model.FolderUsage;
import com.cyanogenmod.filemanager.model.Group;
import com.cyanogenmod.filemanager.model.GroupPermission;
import com.cyanogenmod.filemanager.model.OthersPermission;
import com.cyanogenmod.filemanager.model.Permission;
import com.cyanogenmod.filemanager.model.Permissions;
import com.cyanogenmod.filemanager.model.Symlink;
import com.cyanogenmod.filemanager.model.User;
import com.cyanogenmod.filemanager.model.UserPermission;
import com.cyanogenmod.filemanager.preferences.AccessMode;
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.util.AIDHelper;
import com.cyanogenmod.filemanager.util.CommandHelper;
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.MimeTypeHelper.MimeTypeCategory;
import com.cyanogenmod.filemanager.util.ResourcesHelper;
import java.text.DateFormat;
/**
* A class that wraps a dialog for showing information about a {@link FileSystemObject}
*/
public class FsoPropertiesDialog
implements OnClickListener, OnCheckedChangeListener, OnItemSelectedListener,
DialogInterface.OnCancelListener, DialogInterface.OnDismissListener, AsyncResultListener {
private static final String TAG = "FsoPropertiesDialog"; //$NON-NLS-1$
private static final String OWNER_TYPE = "owner"; //$NON-NLS-1$
private static final String GROUP_TYPE = "group"; //$NON-NLS-1$
private static final String OTHERS_TYPE = "others"; //$NON-NLS-1$
private static final String AID_FORMAT = "%05d - %s"; //$NON-NLS-1$
private static final String AID_SEPARATOR = " - "; //$NON-NLS-1$
/**
* @hide
*/
final FileSystemObject mFso;
private boolean mHasChanged;
/**
* @hide
*/
final Context mContext;
private final AlertDialog mDialog;
private final View mContentView;
private View mInfoViewTab;
private View mPermissionsViewTab;
private View mInfoView;
private View mPermissionsView;
/**
* @hide
*/
Spinner mSpnOwner;
/**
* @hide
*/
Spinner mSpnGroup;
/**
* @hide
*/
private CheckBox[] mChkUserPermission;
private CheckBox[] mChkGroupPermission;
private CheckBox[] mChkOthersPermission;
private TextView mInfoMsgView;
/**
* @hide
*/
TextView mTvSize;
/**
* @hide
*/
TextView mTvContains;
private boolean mIgnoreCheckEvents;
private boolean mHasPrivileged;
private final boolean mIsAdvancedMode;
private final boolean mComputeFolderStatistics;
private FolderUsageExecutable mFolderUsageExecutable;
private FolderUsage mFolderUsage;
/**
* @hide
*/
boolean mDrawingFolderUsage;
private DialogInterface.OnDismissListener mOnDismissListener;
/**
* Constructor of <code>FsoPropertiesDialog</code>.
*
* @param context The current context
* @param fso The file system object reference
*/
public FsoPropertiesDialog(Context context, FileSystemObject fso) {
super();
//Save the context
this.mContext = context;
//Save data
this.mFso = fso;
this.mHasChanged = false;
this.mIgnoreCheckEvents = true;
this.mHasPrivileged = false;
this.mIsAdvancedMode =
FileManagerApplication.getAccessMode().compareTo(AccessMode.SAFE) != 0;
//Inflate the content
LayoutInflater li =
(LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
this.mContentView = li.inflate(R.layout.fso_properties_dialog, null);
// Apply current theme
applyTheme();
//Create the dialog
this.mDialog = DialogHelper.createDialog(
context,
0,
R.string.fso_properties_dialog_title,
this.mContentView);
this.mDialog.setButton(
DialogInterface.BUTTON_NEGATIVE,
this.mContext.getString(android.R.string.ok),
(DialogInterface.OnClickListener)null);
this.mDialog.setOnCancelListener(this);
this.mDialog.setOnDismissListener(this);
// Retrieve the user settings about computing folder statistics
this.mComputeFolderStatistics =
Preferences.getSharedPreferences().
getBoolean(
FileManagerSettings.SETTINGS_COMPUTE_FOLDER_STATISTICS.getId(),
((Boolean)FileManagerSettings.SETTINGS_COMPUTE_FOLDER_STATISTICS.
getDefaultValue()).booleanValue());
//Fill the dialog
fillData(this.mContentView);
}
/**
* Set a listener to be invoked when the dialog is dismissed.
*
* @param onDismissListener The {@link "OnDismissListener"} to use.
*/
public void setOnDismissListener(DialogInterface.OnDismissListener onDismissListener) {
this.mOnDismissListener = onDismissListener;
}
/**
* Method that shows the dialog.
*/
public void show() {
DialogHelper.delegateDialogShow(this.mContext, this.mDialog);
}
/**
* Method that return the associated {@link FileSystemObject} reference
*
* @return FileSystemObject The fso
*/
public FileSystemObject getFso() {
return this.mFso;
}
/**
* Method that returns if the properties of the file was changed
*
* @return boolean If the properties of the file was changed
*/
public boolean isHasChanged() {
return this.mHasChanged;
}
/**
* Method that fill the dialog with the data of the mount point.
*
* @param contentView The content view
*/
private void fillData(View contentView) {
//Get the tab views
this.mInfoViewTab = contentView.findViewById(R.id.fso_properties_dialog_tab_info);
this.mPermissionsViewTab =
contentView.findViewById(R.id.fso_properties_dialog_tab_permissions);
this.mInfoView = contentView.findViewById(R.id.fso_tab_info);
this.mPermissionsView = contentView.findViewById(R.id.fso_tab_permissions);
//Register the listeners
this.mInfoViewTab.setOnClickListener(this);
this.mPermissionsViewTab.setOnClickListener(this);
//Gets text views
TextView tvName = (TextView)contentView.findViewById(R.id.fso_properties_name);
TextView tvParent = (TextView)contentView.findViewById(R.id.fso_properties_parent);
TextView tvType = (TextView)contentView.findViewById(R.id.fso_properties_type);
View vCategoryRow = contentView.findViewById(R.id.fso_properties_category_row);
TextView tvCategory = (TextView)contentView.findViewById(R.id.fso_properties_category);
View vLinkRow = contentView.findViewById(R.id.fso_properties_link_row);
TextView tvLink = (TextView)contentView.findViewById(R.id.fso_properties_link);
this.mTvSize = (TextView)contentView.findViewById(R.id.fso_properties_size);
View vContatinsRow = contentView.findViewById(R.id.fso_properties_contains_row);
this.mTvContains = (TextView)contentView.findViewById(R.id.fso_properties_contains);
TextView tvDate = (TextView)contentView.findViewById(R.id.fso_properties_date);
this.mSpnOwner = (Spinner)contentView.findViewById(R.id.fso_properties_owner);
this.mSpnGroup = (Spinner)contentView.findViewById(R.id.fso_properties_group);
this.mInfoMsgView = (TextView)contentView.findViewById(R.id.fso_info_msg);
//Fill the text views
//- Info
tvName.setText(this.mFso.getName());
if (FileHelper.isRootDirectory(this.mFso)) {
tvParent.setText("-"); //$NON-NLS-1$
} else {
tvParent.setText(this.mFso.getParent());
}
tvType.setText(MimeTypeHelper.getMimeTypeDescription(this.mContext, this.mFso));
if (this.mFso instanceof Symlink) {
Symlink link = (Symlink)this.mFso;
if (link.getLinkRef() != null) {
tvLink.setText(link.getLinkRef().getFullPath());
} else {
tvLink.setText("-"); //$NON-NLS-1$
}
}
MimeTypeCategory category = MimeTypeHelper.getCategory(this.mContext, this.mFso);
if (category.compareTo(MimeTypeCategory.NONE) == 0) {
vCategoryRow.setVisibility(View.GONE);
} else {
tvCategory.setText(
MimeTypeHelper.getCategoryDescription(
this.mContext, category));
}
vLinkRow.setVisibility(this.mFso instanceof Symlink ? View.VISIBLE : View.GONE);
String size = FileHelper.getHumanReadableSize(this.mFso);
if (size.length() == 0) {
size = "-"; //$NON-NLS-1$
}
this.mTvSize.setText(size);
this.mTvContains.setText("-"); //$NON-NLS-1$
DateFormat df = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT);
tvDate.setText(df.format(this.mFso.getLastModifiedTime()));
//- Permissions
String loadingMsg = this.mContext.getString(R.string.loading_message);
setSpinnerMsg(this.mContext, FsoPropertiesDialog.this.mSpnOwner, loadingMsg);
setSpinnerMsg(this.mContext, FsoPropertiesDialog.this.mSpnGroup, loadingMsg);
updatePermissions();
// Load owners and groups AIDs in background
loadAIDs();
// Load owners and groups AIDs in background
if (FileHelper.isDirectory(this.mFso)) {
vContatinsRow.setVisibility(View.VISIBLE);
if (this.mComputeFolderStatistics) {
computeFolderUsage();
}
}
// Check if permissions operations are allowed
try {
this.mHasPrivileged = ConsoleBuilder.getConsole(this.mContext).isPrivileged();
} catch (Throwable ex) {/**NON BLOCK**/}
this.mSpnOwner.setEnabled(this.mHasPrivileged);
this.mSpnGroup.setEnabled(this.mHasPrivileged);
// Not allowed for symlinks
if (!(this.mFso instanceof Symlink)) {
setCheckBoxesPermissionsEnable(this.mChkUserPermission, this.mHasPrivileged);
setCheckBoxesPermissionsEnable(this.mChkGroupPermission, this.mHasPrivileged);
setCheckBoxesPermissionsEnable(this.mChkOthersPermission, this.mHasPrivileged);
} else {
setCheckBoxesPermissionsEnable(this.mChkUserPermission, false);
setCheckBoxesPermissionsEnable(this.mChkGroupPermission, false);
setCheckBoxesPermissionsEnable(this.mChkOthersPermission, false);
}
if (!this.mHasPrivileged && this.mIsAdvancedMode) {
this.mInfoMsgView.setVisibility(View.VISIBLE);
this.mInfoMsgView.setOnClickListener(this);
}
// Add the listener after set the value to avoid raising triggers
this.mSpnOwner.setOnItemSelectedListener(this);
this.mSpnGroup.setOnItemSelectedListener(this);
setPermissionCheckBoxesListener(this.mChkUserPermission);
setPermissionCheckBoxesListener(this.mChkGroupPermission);
setPermissionCheckBoxesListener(this.mChkOthersPermission);
//Change the tab
onClick(this.mInfoViewTab);
this.mIgnoreCheckEvents = false;
}
/**
* Method that loads the AIDs in background
*/
private void loadAIDs() {
// Load owners and groups AIDs in background
AsyncTask<Void, Void, SparseArray<AID>> aidsTask =
new AsyncTask<Void, Void, SparseArray<AID>>() {
@Override
protected SparseArray<AID> doInBackground(Void...params) {
return AIDHelper.getAIDs(FsoPropertiesDialog.this.mContext, true);
}
@Override
protected void onPostExecute(SparseArray<AID> aids) {
if (!isCancelled()) {
// Ensure that at least one AID was loaded
if (aids == null) {
String errorMsg =
FsoPropertiesDialog.this.mContext.getString(R.string.error_message);
setSpinnerMsg(
FsoPropertiesDialog.this.mContext,
FsoPropertiesDialog.this.mSpnOwner, errorMsg);
setSpinnerMsg(
FsoPropertiesDialog.this.mContext,
FsoPropertiesDialog.this.mSpnGroup, errorMsg);
return;
}
// Position of the owner and group
int owner = FsoPropertiesDialog.this.mFso.getUser().getId();
int group = FsoPropertiesDialog.this.mFso.getGroup().getId();
int ownerPosition = 0;
int groupPosition = 0;
// Convert the SparseArray in an array of string of "uid - name"
int len = aids.size();
final String[] data = new String[len];
for (int i = 0; i < len; i++) {
AID aid = aids.valueAt(i);
data[i] = String.format(AID_FORMAT,
Integer.valueOf(aid.getId()), aid.getName());
if (owner == aid.getId()) ownerPosition = i;
if (group == aid.getId()) groupPosition = i;
}
// Change the adapter of the spinners
setSpinnerData(
FsoPropertiesDialog.this.mContext,
FsoPropertiesDialog.this.mSpnOwner, data, ownerPosition);
setSpinnerData(
FsoPropertiesDialog.this.mContext,
FsoPropertiesDialog.this.mSpnGroup, data, groupPosition);
}
}
};
aidsTask.execute();
}
/**
* Method that computes the disk usage of the folder in background
*/
private void computeFolderUsage() {
try {
if (this.mFso instanceof Symlink && ((Symlink) this.mFso).getLinkRef() != null) {
this.mFolderUsageExecutable =
CommandHelper.getFolderUsage(
this.mContext,
((Symlink) this.mFso).getLinkRef().getFullPath(), this, null);
} else {
this.mFolderUsageExecutable =
CommandHelper.getFolderUsage(
this.mContext, this.mFso.getFullPath(), this, null);
}
} catch (Exception cause) {
//Capture the exception
ExceptionUtil.translateException(this.mContext, cause, true, false);
this.mTvSize.setText(R.string.error_message);
this.mTvContains.setText(R.string.error_message);
}
}
/**
* {@inheritDoc}
*/
@Override
public void onDismiss(DialogInterface dialog) {
cancelFolderUsageCommand();
if (this.mOnDismissListener != null) {
this.mOnDismissListener.onDismiss(dialog);
}
}
/**
* {@inheritDoc}
*/
@Override
public void onCancel(DialogInterface dialog) {
cancelFolderUsageCommand();
if (this.mOnDismissListener != null) {
this.mOnDismissListener.onDismiss(dialog);
}
}
/**
* {@inheritDoc}
*/
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.fso_properties_dialog_tab_info:
if (!this.mInfoViewTab.isSelected()) {
this.mInfoViewTab.setSelected(true);
((TextView)this.mInfoViewTab).setTextAppearance(
this.mContext, R.style.primary_text_appearance);
this.mPermissionsViewTab.setSelected(false);
((TextView)this.mPermissionsViewTab).setTextAppearance(
this.mContext, R.style.secondary_text_appearance);
this.mInfoView.setVisibility(View.VISIBLE);
this.mPermissionsView.setVisibility(View.GONE);
// Apply the them
applyTabTheme();
}
break;
case R.id.fso_properties_dialog_tab_permissions:
if (!this.mPermissionsViewTab.isSelected()) {
this.mInfoViewTab.setSelected(false);
((TextView)this.mInfoViewTab).setTextAppearance(
this.mContext, R.style.secondary_text_appearance);
this.mPermissionsViewTab.setSelected(true);
((TextView)this.mPermissionsViewTab).setTextAppearance(
this.mContext, R.style.primary_text_appearance);
this.mInfoView.setVisibility(View.GONE);
this.mPermissionsView.setVisibility(View.VISIBLE);
// Apply the them
applyTabTheme();
// Adjust the size of the spinners
adjustSpinnerSize(this.mSpnOwner);
adjustSpinnerSize(this.mSpnGroup);
}
this.mInfoMsgView.setVisibility(
this.mHasPrivileged || !this.mIsAdvancedMode ? View.GONE : View.VISIBLE);
break;
case R.id.fso_info_msg:
//Change the console
boolean superuser = ConsoleBuilder.changeToPrivilegedConsole(this.mContext);
if (superuser) {
this.mInfoMsgView.setOnClickListener(null);
this.mInfoMsgView.setVisibility(View.GONE);
this.mInfoMsgView.setBackground(null);
// Enable controls
this.mSpnOwner.setEnabled(true);
this.mSpnGroup.setEnabled(true);
setCheckBoxesPermissionsEnable(this.mChkUserPermission, true);
setCheckBoxesPermissionsEnable(this.mChkGroupPermission, true);
setCheckBoxesPermissionsEnable(this.mChkOthersPermission, true);
// Not allowed for symlinks
if (!(this.mFso instanceof Symlink)) {
setCheckBoxesPermissionsEnable(this.mChkUserPermission, true);
setCheckBoxesPermissionsEnable(this.mChkGroupPermission, true);
setCheckBoxesPermissionsEnable(this.mChkOthersPermission, true);
}
this.mHasPrivileged = true;
}
break;
default:
break;
}
}
/**
* {@inheritDoc}
*/
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (this.mIgnoreCheckEvents) return;
try {
// Cancel the folder usage command
cancelFolderUsageCommand();
// Retrieve the permissions and send to operating system
Permissions permissions = getPermissions();
if (!CommandHelper.changePermissions(
this.mContext, this.mFso.getFullPath(), permissions, null)) {
// Show the warning message
setMsg(this.mContext.getString(
R.string.fso_properties_failed_to_change_permission_msg));
// Update the permissions with the previous information
updatePermissions();
return;
}
// Some filesystem, like sdcards, doesn't allow to change the permissions.
// But the system doesn't return the fail. Read again the fso and compare to
// ensure that the permission was changed
try {
FileSystemObject systemFso =
CommandHelper.getFileInfo(
this.mContext, this.mFso.getFullPath(), false, null);
if (systemFso == null || systemFso.getPermissions().compareTo(permissions) != 0) {
// Show the warning message
setMsg(FsoPropertiesDialog.this.mContext.getString(
R.string.fso_properties_failed_to_change_permission_msg));
// Update the permissions with the previous information
updatePermissions();
return;
}
} catch (Exception e) {
// Show the warning message
setMsg(FsoPropertiesDialog.this.mContext.getString(
R.string.fso_properties_failed_to_change_permission_msg));
// Update the permissions with the previous information
updatePermissions();
return;
}
// The permission was changed. Refresh the information
this.mFso.setPermissions(permissions);
this.mHasChanged = true;
setMsg(null);
} catch (Exception ex) {
// Capture the exception and show warning message
ExceptionUtil.translateException(
this.mContext, ex, true, true, new ExceptionUtil.OnRelaunchCommandResult() {
@Override
public void onSuccess() {
// Hide the message
setMsg(null);
}
@Override
public void onCancelled() {
// Update the permissions with the previous information
updatePermissions();
setMsg(null);
}
@Override
public void onFailed(Throwable cause) {
// Show the warning message
setMsg(FsoPropertiesDialog.this.mContext.getString(
R.string.fso_properties_failed_to_change_permission_msg));
// Update the permissions with the previous information
updatePermissions();
}
});
}
}
/**
* {@inheritDoc}
*/
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
User user = null;
Group group = null;
String msg = null;
try {
// Apply theme
Theme theme = ThemeManager.getCurrentTheme(this.mContext);
theme.setTextColor(
this.mContext, ((TextView) parent.getChildAt(0)), "text_color"); //$NON-NLS-1$
String row = parent.getItemAtPosition(position).toString();
int uid = Integer.parseInt(row.substring(0, row.indexOf(AID_SEPARATOR)));
String name = row.substring(row.indexOf(AID_SEPARATOR) + 3);
// Check which spinner was changed
switch (parent.getId()) {
case R.id.fso_properties_owner:
//Owner
user = new User(uid, name);
group = this.mFso.getGroup();
msg = this.mContext.getString(
R.string.fso_properties_failed_to_change_owner_msg);
break;
case R.id.fso_properties_group:
//Group
user = this.mFso.getUser();
group = new Group(uid, name);
msg = this.mContext.getString(
R.string.fso_properties_failed_to_change_group_msg);
break;
default:
break;
}
} catch (Exception ex) {
// Capture the exception
ExceptionUtil.translateException(this.mContext, ex);
// Exit from dialog. The dialog may have inconsistency
this.mDialog.dismiss();
return;
}
// Has changed?
if (this.mFso.getUser().compareTo(user) == 0 &&
this.mFso.getGroup().compareTo(group) == 0) {
return;
}
// Cancel the folder usage command
cancelFolderUsageCommand();
// Change the owner and group of the fso
try {
if (!CommandHelper.changeOwner(
this.mContext, this.mFso.getFullPath(), user, group, null)) {
// Show the warning message
setMsg(msg);
// Update the information of owner and group
updateSpinnerFromAid(this.mSpnOwner, this.mFso.getUser());
updateSpinnerFromAid(this.mSpnGroup, this.mFso.getGroup());
return;
}
//Change the fso reference
this.mFso.setUser(user);
this.mFso.setGroup(group);
this.mHasChanged = true;
setMsg(null);
} catch (Exception ex) {
// Capture the exception and show warning message
final String txtMsg = msg;
ExceptionUtil.translateException(
this.mContext, ex, true, true, new ExceptionUtil.OnRelaunchCommandResult() {
@Override
public void onSuccess() {
// Hide the message
setMsg(null);
}
@Override
public void onCancelled() {
// Update the information of owner and group
updateSpinnerFromAid(
FsoPropertiesDialog.this.mSpnOwner,
FsoPropertiesDialog.this.mFso.getUser());
updateSpinnerFromAid(
FsoPropertiesDialog.this.mSpnGroup,
FsoPropertiesDialog.this.mFso.getGroup());
setMsg(null);
}
@Override
public void onFailed(Throwable cause) {
setMsg(txtMsg);
// Update the information of owner and group
updateSpinnerFromAid(
FsoPropertiesDialog.this.mSpnOwner,
FsoPropertiesDialog.this.mFso.getUser());
updateSpinnerFromAid(
FsoPropertiesDialog.this.mSpnGroup,
FsoPropertiesDialog.this.mFso.getGroup());
return;
}
});
}
}
/**
* {@inheritDoc}
*/
@Override
public void onNothingSelected(AdapterView<?> parent) {/**NON BLOCK**/}
/**
* Method that shows a simple message on the spinner (loading, error, ...)
*
* @param ctx The current context
* @param spinner The spinner
* @param msg The message
* @hide
*/
static void setSpinnerMsg(Context ctx, Spinner spinner, String msg) {
ArrayAdapter<String> loadingAdapter =
new ArrayAdapter<String>(
ctx, R.layout.spinner_item, new String[]{msg});
loadingAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(loadingAdapter);
spinner.setEnabled(false);
}
/**
* Method that fills the spinner with the data
*
* @param ctx The current context
* @param spinner The spinner
* @param data The data
* @param selection The object to select
* @hide
*/
void setSpinnerData(
Context ctx, Spinner spinner, String[] data, int selection) {
ArrayAdapter<String> adapter =
new ArrayAdapter<String>(
ctx, R.layout.spinner_item, data);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(adapter);
spinner.setSelection(selection);
spinner.setEnabled(this.mHasPrivileged);
}
/**
* Method that update a spinner from an {@link AID} reference
*
* @param spinner The spinner to update
* @param aid The {@link AID} reference
*/
@SuppressWarnings({"unchecked", "boxing"})
public static void updateSpinnerFromAid(Spinner spinner, AID aid) {
ArrayAdapter<String> adapter = (ArrayAdapter<String>)spinner.getAdapter();
int position = adapter.getPosition(String.format(AID_FORMAT, aid.getId(), aid.getName()));
if (position != -1) {
spinner.setSelection(position);
}
}
/**
* Method that refresh the information of permissions
* @hide
*/
void updatePermissions() {
// Update the permissions with the previous information
FsoPropertiesDialog.this.mIgnoreCheckEvents = true;
try {
Permissions permissions = this.mFso.getPermissions();
this.mChkUserPermission =
loadCheckBoxUserPermission(
this.mContext, this.mContentView, permissions.getUser());
this.mChkGroupPermission =
loadCheckBoxGroupPermission(
this.mContext, this.mContentView, permissions.getGroup());
this.mChkOthersPermission =
loadCheckBoxOthersPermission(
this.mContext, this.mContentView, permissions.getOthers());
} finally {
FsoPropertiesDialog.this.mIgnoreCheckEvents = false;
}
}
/**
* Method that load the checkboxes for a user permission
*
* @param ctx The current context
* @param rootView The root view
* @return UserPermission The user permission
*/
private static CheckBox[] loadCheckBoxUserPermission (
Context ctx, View rootView, UserPermission permission) {
CheckBox[] chkPermissions = loadPermissionCheckBoxes(ctx, rootView, OWNER_TYPE);
chkPermissions[0].setChecked(permission.isSetUID());
setCheckBoxesPermissions(chkPermissions, permission);
return chkPermissions;
}
/**
* Method that load the checkboxes for a group permission
*
* @param ctx The current context
* @param rootView The root view
* @return UserPermission The user permission
*/
private static CheckBox[] loadCheckBoxGroupPermission (
Context ctx, View rootView, GroupPermission permission) {
CheckBox[] chkPermissions = loadPermissionCheckBoxes(ctx, rootView, GROUP_TYPE);
chkPermissions[0].setChecked(permission.isSetGID());
setCheckBoxesPermissions(chkPermissions, permission);
return chkPermissions;
}
/**
* Method that load the checkboxes for a group permission
*
* @param ctx The current context
* @param rootView The root view
* @return UserPermission The user permission
*/
private static CheckBox[] loadCheckBoxOthersPermission (
Context ctx, View rootView, OthersPermission permission) {
CheckBox[] chkPermissions = loadPermissionCheckBoxes(ctx, rootView, OTHERS_TYPE);
chkPermissions[0].setChecked(permission.isStickybit());
setCheckBoxesPermissions(chkPermissions, permission);
return chkPermissions;
}
/**
* Method that check/uncheck the common permission for a permission checkboxes
*
* @param chkPermissions The checkboxes
* @param permission The permission
*/
private static void setCheckBoxesPermissions (
CheckBox[] chkPermissions, Permission permission) {
chkPermissions[1].setChecked(permission.isRead());
chkPermissions[2].setChecked(permission.isWrite());
chkPermissions[3].setChecked(permission.isExecute());
}
/**
* Method that check/uncheck the common permission for a permission checkboxes
*
* @param chkPermissions The checkboxes
* @param enabled If the checkbox should be enabled
*/
private static void setCheckBoxesPermissionsEnable (
CheckBox[] chkPermissions, boolean enabled) {
int cc = chkPermissions.length;
for (int i = 0; i < cc; i++) {
chkPermissions[i].setEnabled(enabled);
}
}
/**
* Method that load the checkboxes associated with a type of permission
*
* @param ctx The current context
* @param rootView The root view
* @param type The type of permission [owner, group, others]
* @return CheckBox[] The checkboxes associated
*/
private static CheckBox[] loadPermissionCheckBoxes(Context ctx, View rootView, String type) {
Resources res = ctx.getResources();
CheckBox[] chkPermissions = new CheckBox[4];
chkPermissions[0] = (CheckBox)rootView.findViewById(
ResourcesHelper.getIdentifier(
res, "id", //$NON-NLS-1$
String.format("fso_permissions_%s_special", type))); //$NON-NLS-1$
chkPermissions[1] = (CheckBox)rootView.findViewById(
ResourcesHelper.getIdentifier(
res, "id", //$NON-NLS-1$
String.format("fso_permissions_%s_read", type))); //$NON-NLS-1$
chkPermissions[2] = (CheckBox)rootView.findViewById(
ResourcesHelper.getIdentifier(
res, "id", //$NON-NLS-1$
String.format("fso_permissions_%s_write", type))); //$NON-NLS-1$
chkPermissions[3] = (CheckBox)rootView.findViewById(
ResourcesHelper.getIdentifier(
res, "id", //$NON-NLS-1$
String.format("fso_permissions_%s_execute", type))); //$NON-NLS-1$
return chkPermissions;
}
/**
* Method that sets the listener for the permission checkboxes
*
* @param chkPermissions The checkboxes
*/
private void setPermissionCheckBoxesListener(CheckBox[] chkPermissions) {
int cc = chkPermissions.length;
for (int i = 0; i < cc; i++) {
chkPermissions[i].setOnCheckedChangeListener(this);
}
}
/**
* Method that retrieves the current permissions selected by the user
*
* @return Permissions The permissions selected by the user
*/
private Permissions getPermissions() {
UserPermission userPermission =
new UserPermission(
this.mChkUserPermission[1].isChecked(),
this.mChkUserPermission[2].isChecked(),
this.mChkUserPermission[3].isChecked(),
this.mChkUserPermission[0].isChecked());
GroupPermission groupPermission =
new GroupPermission(
this.mChkGroupPermission[1].isChecked(),
this.mChkGroupPermission[2].isChecked(),
this.mChkGroupPermission[3].isChecked(),
this.mChkGroupPermission[0].isChecked());
OthersPermission othersPermission =
new OthersPermission(
this.mChkOthersPermission[1].isChecked(),
this.mChkOthersPermission[2].isChecked(),
this.mChkOthersPermission[3].isChecked(),
this.mChkOthersPermission[0].isChecked());
Permissions permissions =
new Permissions(userPermission, groupPermission, othersPermission);
return permissions;
}
/**
* Method that set a message in the dialog. If the message is {@link null} then
* the view is hidden
*
* @param msg The message to show. {@link null} to hide the dialog
* @hide
*/
void setMsg(String msg) {
this.mInfoMsgView.setText(msg);
this.mInfoMsgView.setVisibility(
!this.mIsAdvancedMode || (this.mHasPrivileged && msg == null) ?
View.GONE :
View.VISIBLE);
}
/**
* {@inheritDoc}
*/
@Override
public void onAsyncStart() {
this.mDrawingFolderUsage = false;
this.mFolderUsage = new FolderUsage(this.mFso.getFullPath());
printFolderUsage(true, false);
}
/**
* {@inheritDoc}
*/
@Override
public void onAsyncEnd(final boolean cancelled) {
try {
// Clone the reference
FsoPropertiesDialog.this.mFolderUsage =
(FolderUsage)this.mFolderUsageExecutable.getFolderUsage().clone();
printFolderUsage(true, cancelled);
} catch (Exception ex) {/**NON BLOCK**/}
}
/**
* {@inheritDoc}
*/
@Override
public void onPartialResult(final Object partialResults) {
try {
// Do not saturate ui thread
if (this.mDrawingFolderUsage) {
return;
}
// Clone the reference
FsoPropertiesDialog.this.mFolderUsage =
(FolderUsage)(((FolderUsage)partialResults).clone());
printFolderUsage(true, false);
} catch (Exception ex) {/**NON BLOCK**/}
}
/**
* {@inheritDoc}
*/
@Override
public void onAsyncExitCode(int exitCode) {/**NON BLOCK**/}
/**
* {@inheritDoc}
*/
@Override
public void onException(Exception cause) {
//Capture the exception
ExceptionUtil.translateException(this.mContext, cause);
}
/**
* Method that cancels the folder usage command execution
*/
private void cancelFolderUsageCommand() {
if (this.mComputeFolderStatistics) {
// Cancel the folder usage command
try {
if (this.mFolderUsageExecutable != null &&
this.mFolderUsageExecutable.isCancellable() &&
!this.mFolderUsageExecutable.isCancelled()) {
this.mFolderUsageExecutable.cancel();
}
} catch (Exception ex) {
Log.e(TAG, "Failed to cancel the folder usage command", ex); //$NON-NLS-1$
}
}
}
/**
* Method that redraws the information about folder usage
*
* @param computing If the process if computing the data
* @param cancelled If the process was cancelled
*/
private void printFolderUsage(final boolean computing, final boolean cancelled) {
// Mark that a drawing is in progress
this.mDrawingFolderUsage = true;
final Resources res = this.mContext.getResources();
if (cancelled) {
try {
FsoPropertiesDialog.this.mTvSize.setText(R.string.cancelled_message);
FsoPropertiesDialog.this.mTvContains.setText(R.string.cancelled_message);
} catch (Throwable e) {/**NON BLOCK**/}
// End of drawing
this.mDrawingFolderUsage = false;
} else {
// Calculate size prior to use ui thread
final String size = FileHelper.getHumanReadableSize(this.mFolderUsage.getTotalSize());
// Compute folders and files string
String folders = res.getQuantityString(
R.plurals.fso_properties_dialog_folders,
this.mFolderUsage.getNumberOfFolders(),
Integer.valueOf(this.mFolderUsage.getNumberOfFolders()));
String files = res.getQuantityString(
R.plurals.fso_properties_dialog_files,
this.mFolderUsage.getNumberOfFiles(),
Integer.valueOf(this.mFolderUsage.getNumberOfFiles()));
final String contains = res.getString(
R.string.fso_properties_dialog_folder_items,
folders, files);
// Update the dialog
((Activity)this.mContext).runOnUiThread(new Runnable() {
@Override
public void run() {
if (computing) {
FsoPropertiesDialog.this.mTvSize.setText(
res.getString(R.string.computing_message, size));
FsoPropertiesDialog.this.mTvContains.setText(
res.getString(R.string.computing_message_ln, contains));
} else {
FsoPropertiesDialog.this.mTvSize.setText(size);
FsoPropertiesDialog.this.mTvContains.setText(contains);
}
// End of drawing
FsoPropertiesDialog.this.mDrawingFolderUsage = false;
}
});
}
}
/**
* Method that adjust the size of the spinner to fit the window
*
* @param spinner The spinner
*/
private void adjustSpinnerSize(final Spinner spinner) {
final View v = this.mContentView.findViewById(R.id.fso_properties_dialog_tabhost);
spinner.post(new Runnable() {
@Override
public void run() {
// Align with the last checkbox of the column
int vW = v.getMeasuredWidth();
int[] cbSpn = new int[2];
spinner.getLocationInWindow(cbSpn);
// Set the width
spinner.getLayoutParams().width = vW - cbSpn[0];
}
});
}
/**
* Method that applies the current theme to the activity
*/
private void applyTheme() {
Theme theme = ThemeManager.getCurrentTheme(this.mContext);
theme.setBackgroundDrawable(
this.mContext, this.mContentView, "background_drawable"); //$NON-NLS-1$
applyTabTheme();
View v = this.mContentView.findViewById(R.id.fso_properties_dialog_tab_divider1);
theme.setBackgroundColor(this.mContext, v, "horizontal_divider_color"); //$NON-NLS-1$
v = this.mContentView.findViewById(R.id.fso_properties_dialog_tab_divider2);
theme.setBackgroundColor(this.mContext, v, "vertical_divider_color"); //$NON-NLS-1$
v = this.mContentView.findViewById(R.id.fso_properties_dialog_tab_divider3);
theme.setBackgroundColor(this.mContext, v, "vertical_divider_color"); //$NON-NLS-1$
v = this.mContentView.findViewById(R.id.fso_properties_name_label);
theme.setTextColor(this.mContext, (TextView)v, "text_color"); //$NON-NLS-1$
v = this.mContentView.findViewById(R.id.fso_properties_name);
theme.setTextColor(this.mContext, (TextView)v, "text_color"); //$NON-NLS-1$
v = this.mContentView.findViewById(R.id.fso_properties_parent_label);
theme.setTextColor(this.mContext, (TextView)v, "text_color"); //$NON-NLS-1$
v = this.mContentView.findViewById(R.id.fso_properties_parent);
theme.setTextColor(this.mContext, (TextView)v, "text_color"); //$NON-NLS-1$
v = this.mContentView.findViewById(R.id.fso_properties_type_label);
theme.setTextColor(this.mContext, (TextView)v, "text_color"); //$NON-NLS-1$
v = this.mContentView.findViewById(R.id.fso_properties_type);
theme.setTextColor(this.mContext, (TextView)v, "text_color"); //$NON-NLS-1$
v = this.mContentView.findViewById(R.id.fso_properties_category_label);
theme.setTextColor(this.mContext, (TextView)v, "text_color"); //$NON-NLS-1$
v = this.mContentView.findViewById(R.id.fso_properties_category);
theme.setTextColor(this.mContext, (TextView)v, "text_color"); //$NON-NLS-1$
v = this.mContentView.findViewById(R.id.fso_properties_link_label);
theme.setTextColor(this.mContext, (TextView)v, "text_color"); //$NON-NLS-1$
v = this.mContentView.findViewById(R.id.fso_properties_link);
theme.setTextColor(this.mContext, (TextView)v, "text_color"); //$NON-NLS-1$
v = this.mContentView.findViewById(R.id.fso_properties_size_label);
theme.setTextColor(this.mContext, (TextView)v, "text_color"); //$NON-NLS-1$
v = this.mContentView.findViewById(R.id.fso_properties_size);
theme.setTextColor(this.mContext, (TextView)v, "text_color"); //$NON-NLS-1$
v = this.mContentView.findViewById(R.id.fso_properties_contains_label);
theme.setTextColor(this.mContext, (TextView)v, "text_color"); //$NON-NLS-1$
v = this.mContentView.findViewById(R.id.fso_properties_contains);
theme.setTextColor(this.mContext, (TextView)v, "text_color"); //$NON-NLS-1$
v = this.mContentView.findViewById(R.id.fso_properties_date_label);
theme.setTextColor(this.mContext, (TextView)v, "text_color"); //$NON-NLS-1$
v = this.mContentView.findViewById(R.id.fso_properties_date);
theme.setTextColor(this.mContext, (TextView)v, "text_color"); //$NON-NLS-1$
v = this.mContentView.findViewById(R.id.fso_properties_owner_label);
theme.setTextColor(this.mContext, (TextView)v, "text_color"); //$NON-NLS-1$
v = this.mContentView.findViewById(R.id.fso_properties_group_label);
theme.setTextColor(this.mContext, (TextView)v, "text_color"); //$NON-NLS-1$
v = this.mContentView.findViewById(R.id.fso_properties_permissions_special_label);
theme.setTextColor(this.mContext, (TextView)v, "text_color"); //$NON-NLS-1$
v = this.mContentView.findViewById(R.id.fso_properties_permissions_read_label);
theme.setTextColor(this.mContext, (TextView)v, "text_color"); //$NON-NLS-1$
v = this.mContentView.findViewById(R.id.fso_properties_permissions_write_label);
theme.setTextColor(this.mContext, (TextView)v, "text_color"); //$NON-NLS-1$
v = this.mContentView.findViewById(R.id.fso_properties_permissions_execute_label);
theme.setTextColor(this.mContext, (TextView)v, "text_color"); //$NON-NLS-1$
v = this.mContentView.findViewById(R.id.fso_properties_permissions_owner_label);
theme.setTextColor(this.mContext, (TextView)v, "text_color"); //$NON-NLS-1$
v = this.mContentView.findViewById(R.id.fso_properties_permissions_group_label);
theme.setTextColor(this.mContext, (TextView)v, "text_color"); //$NON-NLS-1$
v = this.mContentView.findViewById(R.id.fso_properties_permissions_others_label);
theme.setTextColor(this.mContext, (TextView)v, "text_color"); //$NON-NLS-1$
v = this.mContentView.findViewById(R.id.fso_info_msg);
theme.setTextColor(this.mContext, (TextView)v, "text_color"); //$NON-NLS-1$
((TextView)v).setCompoundDrawablesWithIntrinsicBounds(
theme.getDrawable(this.mContext, "filesystem_warning_drawable"), //$NON-NLS-1$
null, null, null);
}
/**
* Method that applies the current theme to the tab host
*/
private void applyTabTheme() {
// Apply the theme
Theme theme = ThemeManager.getCurrentTheme(this.mContext);
View v = this.mContentView.findViewById(R.id.fso_properties_dialog_tab_info);
theme.setTextColor(this.mContext, (TextView)v, "text_color"); //$NON-NLS-1$
v = this.mContentView.findViewById(R.id.fso_properties_dialog_tab_permissions);
theme.setTextColor(this.mContext, (TextView)v, "text_color"); //$NON-NLS-1$
}
}