org.mythdroid.fragments.RecEditFragment.java Source code

Java tutorial

Introduction

Here is the source code for org.mythdroid.fragments.RecEditFragment.java

Source

/*
MythDroid: Android MythTV Remote
Copyright (C) 2009-2010 foobum@gmail.com
    
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
    
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
    
You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

package org.mythdroid.fragments;

import java.io.IOException;

import org.mythdroid.Enums.RecStatus;
import org.mythdroid.Globals;
import org.mythdroid.R;
import org.mythdroid.Enums.RecDupIn;
import org.mythdroid.Enums.RecDupMethod;
import org.mythdroid.Enums.RecEpiFilter;
import org.mythdroid.Enums.RecType;
import org.mythdroid.activities.MDFragmentActivity;
import org.mythdroid.backend.BackendManager;
import org.mythdroid.data.Program;
import org.mythdroid.data.RecordingRule;
import org.mythdroid.mdd.MDDManager;
import org.mythdroid.resource.Messages;
import org.mythdroid.services.DvrService;
import org.mythdroid.util.ErrUtil;

import android.os.Bundle;
import android.os.Handler;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.AdapterView.OnItemSelectedListener;

/** Edit a recording rule */
public class RecEditFragment extends Fragment {

    int recId;
    RecDupMethod dupMethod;
    RecDupIn dupIn;
    RecEpiFilter epiFilter;
    String recGroup, storGroup;

    private MDFragmentActivity activity = null;
    private View view = null;
    private Program prog = null;
    private BackendManager beMgr = null;
    private Handler handler = new Handler();
    private Object initLock = new Object();

    private int prio;
    private RecType type;

    private RecEditSchedFragment resf = null;
    private RecEditGroupsFragment regf = null;

    private Button save, schedOptions, groupOptions;
    private Spinner prioSpinner;

    private boolean childrenModified = false, modified = false, inlineOpts = false, initErr = false;

    private int containerId;

    private DvrService dvr = null;
    private RecordingRule rule = null;

    private StringBuilder updates = new StringBuilder(16);

    private Runnable doneRunnable = new Runnable() {
        @Override
        public void run() {
            done();
        }
    };

    private Runnable getRuleRunnable = new Runnable() {
        @Override
        public void run() {

            synchronized (initLock) {

                activity.showLoadingDialog();
                try {
                    beMgr = Globals.getBackend();
                } catch (IOException e) {
                    activity.dismissLoadingDialog();
                    initError(e);
                    initLock.notify();
                    return;
                }
                if ((prog = Globals.curProg) == null) {
                    ErrUtil.report(Messages.getString("RecEditFragment.0")); //$NON-NLS-1$
                    activity.dismissLoadingDialog();
                    initError(new IllegalArgumentException(Messages.getString("RecEditFragment.0") //$NON-NLS-1$
                    ));
                    initLock.notify();
                    return;
                }

                recId = prog.RecID;
                type = prog.Type;
                prio = prog.RecPrio;
                dupMethod = prog.DupMethod;
                dupIn = prog.DupIn;
                epiFilter = prog.EpiFilter;
                recGroup = prog.RecGroup;
                storGroup = prog.StorGroup;

                if (!Globals.haveServices()) {
                    if (recId != -1)
                        try {
                            type = prog.Type = MDDManager.getRecType(beMgr.addr, recId);
                            if (storGroup == null) {
                                storGroup = prog.StorGroup = MDDManager.getStorageGroup(beMgr.addr, recId);
                            }
                        } catch (IOException e) {
                            activity.dismissLoadingDialog();
                            initError(e);
                            initLock.notify();
                            return;
                        }
                    rule = new RecordingRule();
                } else {
                    dvr = new DvrService(beMgr.addr);
                    try {
                        rule = dvr.getRecRule(recId);
                    } catch (Exception e) {
                        activity.dismissLoadingDialog();
                        initError(e);
                        initLock.notify();
                        return;
                    }
                    if (rule == null)
                        rule = new RecordingRule(prog);
                    else {
                        type = prog.Type = rule.type;
                        prio = prog.RecPrio = rule.recpriority;
                        dupMethod = prog.DupMethod = rule.dupMethod;
                        dupIn = prog.DupIn = rule.dupIn;
                        recGroup = prog.RecGroup = rule.recGroup;
                        storGroup = prog.StorGroup = rule.storGroup;
                    }
                }
                activity.dismissLoadingDialog();
                initLock.notify();
            }
        }
    };

    private Runnable saveRunnable = new Runnable() {
        @Override
        public void run() {

            activity.showLoadingDialog();

            int recid = -1;

            if (modified) {
                if (prio != prog.RecPrio) {
                    addUpdate("RecPriority", prio); //$NON-NLS-1$
                    prog.RecPrio = rule.recpriority = prio;
                }
                if (type != prog.Type) {

                    addUpdate("Type", type.value()); //$NON-NLS-1$
                    prog.Type = rule.type = type;

                    if (type == RecType.NOT && prog.RecID != -1) {

                        try {
                            if (!Globals.haveServices()) {
                                MDDManager.deleteRecording(beMgr.addr, prog.RecID);
                                beMgr.reschedule(prog.RecID);
                            } else
                                dvr.deleteRecording(prog.RecID);
                        } catch (IOException e) {
                            ErrUtil.postErr(activity, e);
                            handler.post(doneRunnable);
                            return;
                        } finally {
                            activity.dismissLoadingDialog();
                        }
                        prog.RecID = -1;
                        RecDetailFragment rdf = ((RecDetailFragment) getFragmentManager()
                                .findFragmentByTag("RecDetailFragment")); //$NON-NLS-1$
                        if (rdf != null)
                            rdf.refresh();
                        handler.post(doneRunnable);
                        return;
                    }

                    addUpdate("FindDay", prog.StartTime.getDay()); //$NON-NLS-1$
                    rule.day = prog.StartTime.getDay();
                    String time = prog.StartTime.getHours() + ":" + //$NON-NLS-1$
                    prog.StartTime.getMinutes() + ":" + //$NON-NLS-1$
                    prog.StartTime.getSeconds();
                    addUpdate("FindTime", time);//$NON-NLS-1$
                    rule.time = time;
                    long id = (prog.StartTime.getTime() / (1000 * 60 * 60 * 24)) + 719528;
                    addUpdate("FindId", id); //$NON-NLS-1$
                    rule.findid = id;

                }
            }

            if (childrenModified) {
                if (dupMethod != prog.DupMethod) {
                    addUpdate("DupMethod", dupMethod.value()); //$NON-NLS-1$
                    prog.DupMethod = rule.dupMethod = dupMethod;
                }
                if (dupIn != prog.DupIn || epiFilter != prog.EpiFilter) {
                    addUpdate("DupIn", (dupIn.value() | epiFilter.value())); //$NON-NLS-1$
                    prog.DupIn = rule.dupIn = dupIn;
                }
                if (!recGroup.equals(prog.RecGroup)) {
                    addUpdate("RecGroup", recGroup); //$NON-NLS-1$
                    prog.RecGroup = rule.recGroup = recGroup;
                }
                if (!storGroup.equals(prog.StorGroup)) {
                    addUpdate("StorageGroup", storGroup); //$NON-NLS-1$
                    prog.StorGroup = rule.storGroup = storGroup;
                }
            }

            if (updates.length() != 0)
                updateRecording(recid, updates);

            activity.dismissLoadingDialog();
            handler.post(doneRunnable);

        }

    };

    @Override
    public void onCreate(Bundle icicle) {

        super.onCreate(icicle);
        activity = (MDFragmentActivity) getActivity();
        Globals.runOnThreadPool(getRuleRunnable);

    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle icicle) {

        synchronized (initLock) {
            while (!initErr && rule == null)
                try {
                    initLock.wait();
                } catch (InterruptedException e) {
                }
        }

        if (container == null || initErr)
            return null;

        containerId = container.getId();

        view = inflater.inflate(R.layout.recording_edit, null, false);

        View schedOptFrame = view.findViewById(R.id.schedOptFrame);
        inlineOpts = schedOptFrame != null && schedOptFrame.getVisibility() == View.VISIBLE;

        if (inlineOpts) {
            resf = new RecEditSchedFragment();
            regf = new RecEditGroupsFragment();
            getFragmentManager().beginTransaction()
                    .replace(R.id.schedOptFrame, resf, resf.getClass().getSimpleName())
                    .replace(R.id.groupOptFrame, regf, regf.getClass().getSimpleName())
                    .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN).commitAllowingStateLoss();
        }

        if ((prog = Globals.curProg) == null) {
            initError(new IllegalArgumentException(Messages.getString("RecEditFragment.0") //$NON-NLS-1$
            ));
            return view;
        }

        setViews();
        if (!inlineOpts)
            checkChildren();

        return view;
    }

    @Override
    public void onResume() {

        super.onResume();

        Globals.runOnThreadPool(new Runnable() {
            @Override
            public void run() {
                activity.showLoadingDialog();
                try {
                    beMgr = Globals.getBackend();
                } catch (IOException e) {
                    initError(e);
                    return;
                } finally {
                    activity.dismissLoadingDialog();
                }

                if (!Globals.haveServices())
                    try {
                        MDDManager mdd = new MDDManager(beMgr.addr, Globals.muxConns);
                        mdd.shutdown();
                    } catch (IOException e) {
                        initError(new IOException(Messages.getString("RecordingEdit.2") + //$NON-NLS-1$
                        beMgr.addr));
                    }
            }
        });

    }

    /** Check for changes that child fragments might have made */
    public void checkChildren() {
        if (prog == null)
            return;
        if (resf != null && !resf.isEnabled())
            childrenModified = false;
        else if (dupMethod != prog.DupMethod || dupIn != prog.DupIn || epiFilter != prog.EpiFilter
                || !recGroup.equals(prog.RecGroup) || !storGroup.equals(prog.StorGroup))
            childrenModified = true;
        else
            childrenModified = false;
        updateSaveEnabled();
    }

    private void setViews() {

        ((TextView) view.findViewById(R.id.title)).setText(prog.Title);
        ((TextView) view.findViewById(R.id.subtitle)).setText(prog.SubTitle);
        ((TextView) view.findViewById(R.id.channel)).setText(prog.Channel);
        ((TextView) view.findViewById(R.id.start)).setText(prog.startString());

        final Spinner typeSpinner = ((Spinner) view.findViewById(R.id.type));
        final ArrayAdapter<String> typeAdapter = new ArrayAdapter<String>(activity,
                android.R.layout.simple_spinner_item);
        typeAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);

        for (RecType type : RecType.values()) {
            if (type == RecType.DONT || type == RecType.OVERRIDE)
                continue;
            typeAdapter.add(type.msg());
        }

        typeSpinner.setAdapter(typeAdapter);
        typeSpinner.setSelection(type.ordinal());
        typeSpinner.setOnItemSelectedListener(new OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
                type = RecType.values()[pos];
                if (type != prog.Type || prio != prog.RecPrio)
                    modified = true;
                else
                    modified = false;
                updateSaveEnabled();

                if (type == RecType.NOT) {
                    prioSpinner.setEnabled(false);
                    if (!inlineOpts) {
                        schedOptions.setEnabled(false);
                        groupOptions.setEnabled(false);
                    } else {
                        resf.setEnabled(false);
                        regf.setEnabled(false);
                    }
                } else {
                    prioSpinner.setEnabled(true);
                    if (!inlineOpts) {
                        schedOptions.setEnabled(true);
                        groupOptions.setEnabled(true);
                    } else {
                        resf.setEnabled(true);
                        regf.setEnabled(true);
                    }
                }
            }

            @Override
            public void onNothingSelected(AdapterView<?> arg0) {
            }

        });

        prioSpinner = ((Spinner) view.findViewById(R.id.prio));

        final String[] prios = new String[21];
        for (int i = -10, j = 0; i < 11; i++)
            prios[j++] = String.valueOf(i);

        final ArrayAdapter<String> prioAdapter = new ArrayAdapter<String>(activity,
                android.R.layout.simple_spinner_item, prios);
        prioAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);

        prioSpinner.setAdapter(prioAdapter);
        prioSpinner.setSelection(prio + 10);
        prioSpinner.setOnItemSelectedListener(new OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
                prio = pos - 10;
                if (type != prog.Type || prio != prog.RecPrio)
                    modified = true;
                else
                    modified = false;
                updateSaveEnabled();
            }

            @Override
            public void onNothingSelected(AdapterView<?> arg0) {
            }

        });
        prioSpinner.setEnabled(type == RecType.NOT ? false : true);

        if (!inlineOpts) {
            schedOptions = (Button) view.findViewById(R.id.schedOptions);
            schedOptions.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    getFragmentManager().beginTransaction()
                            .replace(containerId, new RecEditSchedFragment(), "RecEditSchedFragment" //$NON-NLS-1$
                    ).setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE).addToBackStack(null)
                            .commitAllowingStateLoss();
                }
            });
            schedOptions.setEnabled(type == RecType.NOT ? false : true);

            groupOptions = (Button) view.findViewById(R.id.groupOptions);
            groupOptions.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    getFragmentManager().beginTransaction()
                            .replace(containerId, new RecEditGroupsFragment(), "RecEditGroupsFragment" //$NON-NLS-1$
                    ).setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE).addToBackStack(null)
                            .commitAllowingStateLoss();
                }
            });
            groupOptions.setEnabled(type == RecType.NOT ? false : true);
        }

        save = (Button) view.findViewById(R.id.save);
        save.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                doSave();
            }
        });
        save.setEnabled(false);

    }

    private void updateSaveEnabled() {
        if (modified || childrenModified)
            save.setEnabled(true);
        else
            save.setEnabled(false);
    }

    // Save the changes and reschedule the rule
    private void doSave() {
        Globals.runOnThreadPool(saveRunnable);
    }

    private void updateRecording(int recid, StringBuilder updates) {

        // Send the schedule updates to MDD, get back the (new) recid
        if (!Globals.haveServices())
            try {
                recid = MDDManager.updateRecording(beMgr.addr, prog, updates.toString());
            } catch (IOException e) {
                ErrUtil.postErr(activity, e);
                return;
            }
        else {
            /* We need to use the program start time, not that of the rule
               Strange, but true because of the implementation of 
               AddRecordSchedule in the services api */
            rule.startTime = prog.StartTime;

            // New recording, fill in some sensible defaults
            if (prog.RecID != 1) {
                rule.autoexpire = true;
                rule.autoflag = true;
                rule.autometa = true;
            }
            try {
                recid = dvr.updateRecording(rule);
            } catch (IOException e) {
                ErrUtil.postErr(activity, e);
                return;
            }
        }
        prog.RecID = recid;

        if (recid == -1) {
            ErrUtil.postErr(activity, Messages.getString("RecordingEdit.0") //$NON-NLS-1$
            );
            return;
        }

        // Tell the backend to reschedule this rule
        try {
            beMgr.reschedule(recid);
        } catch (IOException e) {
            ErrUtil.postErr(activity, e);
        }

        if (prog.Status != RecStatus.RECORDED) {
            RecDetailFragment rdf = ((RecDetailFragment) getFragmentManager()
                    .findFragmentByTag("RecDetailFragment")); //$NON-NLS-1$
            if (rdf != null)
                rdf.refresh();
        }

    }

    /**
     * Add to the list of schedule updates to send to MDD 
     * @param update new schedule update
     */
    private void addUpdate(String update, long value) {
        if (updates.length() > 0)
            updates.append(", "); //$NON-NLS-1$
        updates.append(update).append(" = ").append(value); //$NON-NLS-1$
    }

    /**
     * Add to the list of schedule updates to send to MDD 
     * @param update new schedule update
     */
    private void addUpdate(String update, String value) {
        if (updates.length() > 0)
            updates.append(", "); //$NON-NLS-1$
        updates.append(update).append(" = '").append(value).append("'"); //$NON-NLS-1$ //$NON-NLS-2$
    }

    private void removeInlineFrags() {
        if (!inlineOpts && resf == null && regf == null)
            return;
        FragmentTransaction ft = getFragmentManager().beginTransaction();
        ft.remove(resf);
        ft.remove(regf);
        ft.commitAllowingStateLoss();
    }

    private void initError(Exception e) {
        if (e != null)
            ErrUtil.postErr(activity, e);
        initErr = true;
        removeInlineFrags();
        getFragmentManager().popBackStack();
    }

    private void done() {
        removeInlineFrags();
        getFragmentManager().popBackStackImmediate();
    }
}