com.docd.purefm.ui.dialogs.FilePropertiesDialog.java Source code

Java tutorial

Introduction

Here is the source code for com.docd.purefm.ui.dialogs.FilePropertiesDialog.java

Source

/*
 * Copyright 2014 Yaroslav Mytkalyk
 * 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.docd.purefm.ui.dialogs;

import com.cyanogenmod.filemanager.util.AIDHelper;
import com.docd.purefm.Environment;
import com.docd.purefm.Extras;
import com.docd.purefm.R;
import com.docd.purefm.file.CommandLineFile;
import com.docd.purefm.file.FileFactory;
import com.docd.purefm.file.GenericFile;
import com.docd.purefm.file.Permissions;
import com.docd.purefm.settings.Settings;
import com.docd.purefm.utils.PFMFileUtils;
import com.docd.purefm.utils.PFMTextUtils;
import com.docd.purefm.utils.ThemeUtils;
import com.stericson.RootTools.RootTools;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.DialogFragment;
import android.content.Context;
import android.content.DialogInterface;
import android.content.res.Resources;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.CompoundButton;
import android.widget.TextView;
import android.widget.Toast;

import android.support.annotation.NonNull;
import android.support.annotation.Nullable;

import java.io.IOException;
import java.lang.ref.WeakReference;

public final class FilePropertiesDialog extends DialogFragment {

    public static FilePropertiesDialog newInstance(final @NonNull GenericFile f) {
        final Bundle extras = new Bundle();
        extras.putSerializable(Extras.EXTRA_FILE, f);

        final FilePropertiesDialog fpd = new FilePropertiesDialog();
        fpd.setArguments(extras);
        return fpd;
    }

    private GenericFile file;
    private PropertiesAdapter mAdapter;

    @Override
    public void onCreate(Bundle state) {
        super.onCreate(state);
        final Bundle args = this.getArguments();
        if (args == null) {
            throw new RuntimeException(
                    "Arguments were not supplied. Make sure you created this DialogFragment using newInstance method");
        }
        this.file = (GenericFile) args.getSerializable(Extras.EXTRA_FILE);
    }

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        final Activity activity = getActivity();
        if (activity == null || activity.isFinishing()) {
            return null;
        }
        final AlertDialog.Builder builder = new AlertDialog.Builder(activity);
        mAdapter = new PropertiesAdapter(activity, file);
        builder.setIcon(ThemeUtils.getDrawableNonNull(activity, R.attr.ic_menu_info));
        builder.setTitle(file.getName());
        builder.setNeutralButton(R.string.close, null);
        builder.setPositiveButton(R.string.apply, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                final FilePermissionsPagerItem fragment = (FilePermissionsPagerItem) mAdapter.getItem(1);
                fragment.applyPermissions(getActivity());
            }
        });

        //noinspection InflateParams
        final View content = activity.getLayoutInflater().inflate(R.layout.dialog_properties_container, null);
        if (content == null) {
            throw new RuntimeException("Inflated view is null");
        }
        this.initView(content);
        builder.setView(content);
        final AlertDialog dialog = builder.create();
        dialog.setOnShowListener(new DialogInterface.OnShowListener() {
            @Override
            public void onShow(final DialogInterface dialog) {
                final Button button = ((AlertDialog) dialog).getButton(DialogInterface.BUTTON_POSITIVE);
                if (button == null) {
                    throw new RuntimeException("Can't get positive button");
                }
                button.setVisibility(View.GONE);
            }
        });
        return dialog;
    }

    private void initView(@NonNull final View view) {
        final ViewPager pager = (ViewPager) view.findViewById(R.id.tabsContainer);
        pager.setAdapter(mAdapter);

        final CompoundButton tab1 = (CompoundButton) view.findViewById(R.id.tab1);
        final CompoundButton tab2 = (CompoundButton) view.findViewById(R.id.tab2);

        pager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
            @Override
            public void onPageSelected(int position) {
                tab1.setChecked(position == 0);
                tab2.setChecked(position == 1);
                final AlertDialog dialog = (AlertDialog) getDialog();
                if (dialog == null) {
                    throw new RuntimeException("The dialog is null");
                }
                final Button positive = dialog.getButton(DialogInterface.BUTTON_POSITIVE);
                if (positive == null) {
                    throw new RuntimeException("Can't get positive button");
                }
                positive.setVisibility(
                        position == 0 || !((FilePermissionsPagerItem) mAdapter.getItem(1)).areBoxesEnabled()
                                ? View.GONE
                                : View.VISIBLE);
            }
        });

        tab1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                tab1.setChecked(true);
                tab2.setChecked(false);
                pager.setCurrentItem(0);
            }
        });

        tab2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                tab2.setChecked(true);
                tab1.setChecked(false);
                pager.setCurrentItem(1);
            }
        });
    }

    @Override
    public void onStart() {
        super.onStart();
        mAdapter.onStart();
    }

    @Override
    public void onStop() {
        super.onStop();
        mAdapter.onStop();
    }

    private interface PagerItem {

        void onStart();

        void onStop();

        @NonNull
        View onCreateView(@NonNull LayoutInflater inflater, @NonNull final ViewGroup container);
    }

    static final class FilePermissionsPagerItem implements PagerItem, CompoundButton.OnCheckedChangeListener {

        private LoadFsTask mTask;
        View mView;

        FilePermissionsPagerItem(final GenericFile file) {
            mFile = file;
        }

        @NonNull
        @Override
        public View onCreateView(@NonNull final LayoutInflater inflater, @NonNull final ViewGroup container) {
            //noinspection InflateParams
            mView = inflater.inflate(R.layout.dialog_permissions, null);
            initView(mView);
            return mView;
        }

        @Override
        public void onStart() {
            if (mView != null) {
                if (mTask == null) {
                    mTask = new LoadFsTask(this);
                }
                if (mTask.getStatus() != AsyncTask.Status.RUNNING) {
                    mTask.execute(mFile);
                }
            }
        }

        @Override
        public void onStop() {
            if (mTask != null && mTask.getStatus() == AsyncTask.Status.RUNNING) {
                mTask.cancel(false);
            }
        }

        /**
         * Permissions that file had when FilePermissionsController was created
         */
        private Permissions mInputPermissions;

        /**
         * Currently modified permissions
         */
        private Permissions mModifiedPermissions;

        /**
         * Target file
         */
        private final GenericFile mFile;

        /**
         * User: read
         */
        private CompoundButton ur;

        /**
         * User: write
         */
        private CompoundButton uw;

        /**
         * User: execute
         */
        private CompoundButton ux;

        /**
         * Group: read
         */
        private CompoundButton gr;

        /**
         * Group: write
         */
        private CompoundButton gw;

        /**
         * Group: execute
         */
        private CompoundButton gx;

        /**
         * Others: read
         */
        private CompoundButton or;

        /**
         * Others: write
         */
        private CompoundButton ow;

        /**
         * Others: execute
         */
        private CompoundButton ox;

        private void initView(View table) {
            final TextView owner = (TextView) table.findViewById(R.id.owner);
            final TextView group = (TextView) table.findViewById(R.id.group);

            final Permissions p = mFile.getPermissions();
            this.ur = (CompoundButton) table.findViewById(R.id.uread);
            this.uw = (CompoundButton) table.findViewById(R.id.uwrite);
            this.ux = (CompoundButton) table.findViewById(R.id.uexecute);
            this.gr = (CompoundButton) table.findViewById(R.id.gread);
            this.gw = (CompoundButton) table.findViewById(R.id.gwrite);
            this.gx = (CompoundButton) table.findViewById(R.id.gexecute);
            this.or = (CompoundButton) table.findViewById(R.id.oread);
            this.ow = (CompoundButton) table.findViewById(R.id.owrite);
            this.ox = (CompoundButton) table.findViewById(R.id.oexecute);

            this.ur.setChecked(p.ur);
            this.uw.setChecked(p.uw);
            this.ux.setChecked(p.ux);
            this.gr.setChecked(p.gr);
            this.gw.setChecked(p.gw);
            this.gx.setChecked(p.gx);
            this.or.setChecked(p.or);
            this.ow.setChecked(p.ow);
            this.ox.setChecked(p.ox);

            this.ur.setOnCheckedChangeListener(this);
            this.uw.setOnCheckedChangeListener(this);
            this.ux.setOnCheckedChangeListener(this);
            this.gr.setOnCheckedChangeListener(this);
            this.gw.setOnCheckedChangeListener(this);
            this.gx.setOnCheckedChangeListener(this);
            this.or.setOnCheckedChangeListener(this);
            this.ow.setOnCheckedChangeListener(this);
            this.ox.setOnCheckedChangeListener(this);

            if (mFile instanceof CommandLineFile) {
                final CommandLineFile f = (CommandLineFile) mFile;
                final SparseArray<String> aids = AIDHelper.getAIDs(table.getContext(), false);
                if (aids != null) {
                    owner.setText(aids.get(f.getOwner()));
                    group.setText(aids.get(f.getGroup()));
                }
            } else {
                this.disableBoxes();
            }

            this.mInputPermissions = p;
            this.mModifiedPermissions = p;
        }

        @Override
        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
            this.mModifiedPermissions = new Permissions(this.ur.isChecked(), this.uw.isChecked(),
                    this.ux.isChecked(), this.gr.isChecked(), this.gw.isChecked(), this.gx.isChecked(),
                    this.or.isChecked(), this.ow.isChecked(), this.ox.isChecked());
        }

        private void disableBoxes() {
            this.ur.setEnabled(false);
            this.uw.setEnabled(false);
            this.ux.setEnabled(false);
            this.gr.setEnabled(false);
            this.gw.setEnabled(false);
            this.gx.setEnabled(false);
            this.or.setEnabled(false);
            this.ow.setEnabled(false);
            this.ox.setEnabled(false);
        }

        boolean areBoxesEnabled() {
            return this.ur.isEnabled();
        }

        public void applyPermissions(final Context context) {
            if (!mInputPermissions.equals(mModifiedPermissions)) {
                final ApplyTask task = new ApplyTask(context, mModifiedPermissions);
                task.execute(this.mFile);
            }
        }

        private static final class LoadFsTask extends AsyncTask<GenericFile, Void, String> {

            private final WeakReference<FilePermissionsPagerItem> mItemRef;

            LoadFsTask(@NonNull final FilePermissionsPagerItem item) {
                this.mItemRef = new WeakReference<>(item);
            }

            @Override
            protected String doInBackground(final GenericFile... params) {
                return PFMFileUtils.resolveFileSystem(params[0]);
            }

            @Override
            protected void onPostExecute(final String fsType) {
                final FilePermissionsPagerItem item = mItemRef.get();
                if (item != null) {
                    if (fsType == null || fsType.equals("vfat") || fsType.equals("fuse") || fsType.equals("ntfs")
                            || fsType.equals("msdos") || fsType.equals("sdcardfs")) {
                        item.disableBoxes();
                    }
                    item.mView.findViewById(android.R.id.progress).setVisibility(View.GONE);
                    item.mView.findViewById(R.id.content).setVisibility(View.VISIBLE);
                }
            }
        }

        private static final class ApplyTask extends AsyncTask<GenericFile, Void, Boolean> {

            private final Context mContext;
            private final Permissions mTarget;

            private ApplyTask(Context context, Permissions target) {
                this.mContext = context;
                this.mTarget = target;
            }

            @Override
            protected Boolean doInBackground(final GenericFile... params) {
                final String path = params[0].getAbsolutePath();
                final Settings settings = Settings.getInstance(mContext);
                final boolean remount = settings.useCommandLine() && settings.isSuEnabled()
                        && Environment.needsRemount(path);
                if (remount) {
                    RootTools.remount(path, "RW");
                }
                try {
                    return params[0].applyPermissions(this.mTarget);
                } finally {
                    if (remount) {
                        RootTools.remount(path, "RO");
                    }
                }
            }

            @Override
            protected void onPostExecute(Boolean result) {
                Toast.makeText(this.mContext,
                        this.mContext.getText(result ? R.string.permissions_changed : R.string.applying_failed),
                        Toast.LENGTH_SHORT).show();
            }

        }
    }

    static final class FilePropertiesPagerItem implements PagerItem {

        private final GenericFile mFile;
        private final Settings mSettings;
        private final Resources mResources;
        private PropertiesTask mTask;
        private View mView;

        FilePropertiesPagerItem(@NonNull final GenericFile file, @NonNull final Settings settings,
                @NonNull final Resources resources) {
            mFile = file;
            mSettings = settings;
            mResources = resources;
        }

        @NonNull
        @Override
        public View onCreateView(@NonNull final LayoutInflater inflater, @NonNull final ViewGroup container) {
            //noinspection InflateParams
            mView = inflater.inflate(R.layout.dialog_properties, null);
            return mView;
        }

        @Override
        public void onStart() {
            if (mView != null) {
                if (mTask == null) {
                    mTask = new PropertiesTask(mView, mSettings, mResources);
                }
                if (mTask.getStatus() != AsyncTask.Status.RUNNING) {
                    mTask.execute(mFile);
                }
            }
        }

        @Override
        public void onStop() {
            if (mTask != null && mTask.getStatus() == AsyncTask.Status.RUNNING) {
                mTask.cancel(false);
            }
        }

        private static final class FileProperties {
            final CharSequence mFileName;
            final CharSequence mParentPath;
            final CharSequence mTypeText;
            final CharSequence mMimeTypeText;
            final CharSequence mFileSizeText;
            final CharSequence mLastModifiedText;

            private FileProperties(@NonNull final CharSequence fileName, @NonNull CharSequence parentPath,
                    @NonNull CharSequence typeText, @Nullable CharSequence mimeTypeText,
                    @NonNull CharSequence fileSizeText, @NonNull CharSequence lastModifiedText) {
                this.mFileName = fileName;
                this.mParentPath = parentPath;
                this.mTypeText = typeText;
                this.mMimeTypeText = mimeTypeText;
                this.mFileSizeText = fileSizeText;
                this.mLastModifiedText = lastModifiedText;
            }
        }

        private static final class PropertiesTask extends AsyncTask<GenericFile, Void, FileProperties> {

            private final WeakReference<View> mViewRef;
            private final Settings mSettings;
            private final Resources mResources;

            PropertiesTask(@NonNull final View view, @NonNull final Settings settings,
                    @NonNull final Resources res) {
                this.mViewRef = new WeakReference<>(view);
                this.mSettings = settings;
                this.mResources = res;
            }

            @NonNull
            @Override
            protected FileProperties doInBackground(final GenericFile... params) {
                final GenericFile file = params[0];
                GenericFile par = file.getParentFile();
                if (par == null) {
                    par = FileFactory.newFile(mSettings, Environment.sRootDirectory);
                }
                String parentPath;
                try {
                    parentPath = par.getCanonicalPath();
                } catch (IOException e) {
                    parentPath = par.getAbsolutePath();
                }

                final CharSequence typeText = file.isSymlink() ? mResources.getText(R.string.type_symlink)
                        : file.isDirectory() ? mResources.getText(R.string.type_directory)
                                : mResources.getText(R.string.type_file);

                return new FileProperties(file.getName(), parentPath, typeText, file.getMimeType(),
                        PFMFileUtils.byteCountToDisplaySize(file.lengthTotal()),
                        PFMTextUtils.humanReadableDate(file.lastModified(), file instanceof CommandLineFile));
            }

            @Override
            protected void onPostExecute(final @NonNull FileProperties fileProperties) {
                final View view = mViewRef.get();
                if (view == null) {
                    return;
                }
                final TextView name = (TextView) view.findViewById(R.id.name);
                name.setText(fileProperties.mFileName);

                final TextView parent = (TextView) view.findViewById(R.id.location);
                parent.setText(fileProperties.mParentPath);

                final TextView type = (TextView) view.findViewById(R.id.type);
                type.setText(fileProperties.mTypeText);

                if (fileProperties.mMimeTypeText != null) {
                    final TextView mime = (TextView) view.findViewById(R.id.mime);
                    mime.setText(fileProperties.mMimeTypeText);
                }

                final TextView size = (TextView) view.findViewById(R.id.size);
                size.setText(fileProperties.mFileSizeText);

                final TextView mod = (TextView) view.findViewById(R.id.modified);
                mod.setText(fileProperties.mLastModifiedText);

                view.findViewById(android.R.id.progress).setVisibility(View.GONE);
                view.findViewById(R.id.content).setVisibility(View.VISIBLE);
            }
        }
    }

    private static final class PropertiesAdapter extends PagerAdapter {

        private final LayoutInflater mLayoutInflater;
        private final GenericFile mFile;
        private final PagerItem[] mItems;

        private PropertiesAdapter(@NonNull final Activity context, @NonNull final GenericFile file) {
            mLayoutInflater = context.getLayoutInflater();
            mFile = file;
            //noinspection ConstantConditions
            mItems = new PagerItem[] { new FilePropertiesPagerItem(mFile, Settings.getInstance(context),
                    context.getApplicationContext().getResources()), new FilePermissionsPagerItem(mFile) };
        }

        void onStart() {
            for (final PagerItem item : mItems) {
                item.onStart();
            }
        }

        void onStop() {
            for (final PagerItem item : mItems) {
                item.onStop();
            }
        }

        @NonNull
        PagerItem getItem(final int position) {
            return mItems[position];
        }

        @Override
        public Object instantiateItem(final ViewGroup container, final int position) {
            final PagerItem item = mItems[position];
            final View view = item.onCreateView(mLayoutInflater, container);
            container.addView(view);
            item.onStart();
            return view;
        }

        @Override
        public void destroyItem(ViewGroup container, int position, Object object) {
            container.removeView((View) object);
        }

        @Override
        public int getCount() {
            return mItems.length;
        }

        @Override
        public boolean isViewFromObject(View view, Object object) {
            return view == object;
        }
    }
}