org.peercast.pecaport.PecaPortFragmentBase.java Source code

Java tutorial

Introduction

Here is the source code for org.peercast.pecaport.PecaPortFragmentBase.java

Source

package org.peercast.pecaport;

import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.Configuration;
import android.database.DataSetObserver;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.ColorRes;
import android.support.annotation.DrawableRes;
import android.support.annotation.IdRes;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.UiThread;
import android.support.v4.app.Fragment;
import android.support.v7.app.AlertDialog;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.Spinner;
import android.widget.TableRow;
import android.widget.TextView;
import android.widget.Toast;

import org.apache.commons.lang3.time.DurationFormatUtils;
import org.fourthline.cling.model.meta.RemoteService;
import org.fourthline.cling.support.model.PortMapping;
import org.peercast.pecaport.widget.DefaultTableAdapter;
import org.peercast.pecaport.widget.PeerCastButton;
import org.peercast.pecaport.widget.TableView;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

/**
 * @author (c) 2015, T Yoshizawa
 *         Dual licensed under the MIT or GPL licenses.
 */
public abstract class PecaPortFragmentBase extends Fragment implements PortManipulator.OnResultListener {
    private static final String TAG = "PecaPortFragmentBase";

    @Nullable
    private RouterDiscoverer mRouterDiscoverer;

    private int mRunningPort;

    @Nullable
    private NetworkInterfaceInfo mActiveNicInfo;
    private final ViewBinder mViewBinder = new ViewBinder();

    private ContainerFrame mContentView;
    private PeerCastButton vPeerCast;
    private WanConnectionsAdapter mWanConnectionAdapter;
    private MappingEntryAdapter mMappingAdapter;
    private PecaPortPreferences mPreferences;

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mPreferences = PecaPortPreferences.from(getContext());
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        //Disable???????????FrameLayout
        ContainerFrame exFrame = new ContainerFrame(container.getContext());
        exFrame.addView(inflater.inflate(R.layout.pecaport, null));

        boolean isTablet = getContext().getResources().getConfiguration()
                .isLayoutSizeAtLeast(Configuration.SCREENLAYOUT_SIZE_LARGE);

        //Gone: ?????
        exFrame.findViewById(R.id.vLayoutPadding1).setVisibility(isTablet ? View.GONE : View.VISIBLE);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            //6.0Wifi?MacAddress?"02:00:00:00:00:00:00"??????
            exFrame.findViewById(R.id.vRowHardwareAddress).setVisibility(View.GONE);
        }
        return exFrame;
    }

    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        mContentView = (ContainerFrame) view;

        final Spinner vWanConnectionSelector = (Spinner) mContentView.findViewById(R.id.vWanConnectionSelector);
        final TableView vMappingEntries = (TableView) mContentView.findViewById(R.id.vMappingEntries);
        vPeerCast = (PeerCastButton) mContentView.findViewById(R.id.vPeerCast);
        final ImageButton vAdd = (ImageButton) mContentView.findViewById(R.id.vAdd);

        if (!mPreferences.isDebug())
            vAdd.setVisibility(View.GONE);

        mWanConnectionAdapter = new WanConnectionsAdapter();
        vWanConnectionSelector.setAdapter(mWanConnectionAdapter);

        final AdapterView.OnItemSelectedListener wanItemListener = new AdapterView.OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
                WanConnection conn = (WanConnection) parent.getItemAtPosition(position);
                String externalIp = conn.getExternalIp();
                if (externalIp == null)
                    externalIp = getContext().getString(R.string.t_empty);
                mViewBinder.updateTextView(R.id.vWanExternalIp, externalIp);

                onPreparePeerCastButton(vPeerCast, conn);
                mMappingAdapter.setPortMappings(conn.getMappingEntries());
                updateAddButton(vAdd);
            }

            @Override
            public void onNothingSelected(AdapterView<?> parent) {
            }
        };
        vWanConnectionSelector.setOnItemSelectedListener(wanItemListener);

        mWanConnectionAdapter.registerDataSetObserver(new DataSetObserver() {
            @Override
            public void onChanged() {
                int enabledPos = mWanConnectionAdapter.getConnectedPosition();
                if (enabledPos != -1) {
                    wanItemListener.onItemSelected(vWanConnectionSelector, null, enabledPos, 0);
                }
                updateAddButton(vAdd);
            }
        });

        mMappingAdapter = new MappingEntryAdapter(getContext(), new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                onDeleteMapping((WanConnection) vWanConnectionSelector.getSelectedItem(), (PortMapping) v.getTag());
            }
        });
        vMappingEntries.setAdapter(mMappingAdapter);

        vPeerCast.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //Log.d(TAG, "" + v);
                WanConnection conn = (WanConnection) vWanConnectionSelector.getSelectedItem();
                if (conn != null)
                    onClickPeerCastButton(vPeerCast, conn);
                else
                    showToast("WanConnection not found.");
            }
        });

        vAdd.setEnabled(mActiveNicInfo != null);
        vAdd.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                onRequestAddPort(mWanConnectionAdapter.getConnected());
            }
        });
    }

    private void updateAddButton(View vAdd) {
        if (!mWanConnectionAdapter.getConnected().isEmpty()) {
            vAdd.setEnabled(true);
            vAdd.setAlpha(1.0f);
        } else {
            vAdd.setEnabled(false);
            vAdd.setAlpha(0.6f);
        }
    }

    protected void startDiscoverer() {
        if (mRouterDiscoverer != null)
            return;

        NetworkDeviceManager nicManager = NetworkDeviceManager.from(getContext());
        mActiveNicInfo = nicManager.getActiveInterface();
        if (mActiveNicInfo == null) {
            Log.i(TAG, "mActiveNicInfo == null");
            mViewBinder.setNetworkInterfaceInfo(null);
        }

        RouterEventHandler routerEventHandler = new RouterEventHandler(mViewBinder);
        mRouterDiscoverer = new RouterDiscoverer(getActivity().getApplicationContext(), routerEventHandler);

        getActivity().getApplicationContext().bindService(new Intent(getContext(), UpnpInternalService.class),
                mRouterDiscoverer, Context.BIND_AUTO_CREATE);
    }

    protected void setRunningPort(int port) {
        if (mRunningPort != port) {
            mRunningPort = port;
            //Log.d(TAG, "port="+mRunningPort);
            mMappingAdapter.notifyDataSetChanged();
        }
    }

    protected void setDebugMode(boolean b) {
        mPreferences.putDebug(b);
    }

    protected boolean isDebugMode() {
        return mPreferences.isDebug();
    }

    private void onPreparePeerCastButton(PeerCastButton button, WanConnection selected) {
        boolean enabled = mActiveNicInfo != null && selected != null;
        button.setEnabled(enabled);
        if (enabled) {
            NetworkIdentity identity = new NetworkIdentity(getActivity(), mActiveNicInfo, selected.getService());
            //Log.d(TAG, identity+"##");
            //Log.d(TAG, mPreferences.getAllDisabledNetworks()+"");
            button.setDeny(mPreferences.getAllDisabledNetworks().contains(identity));
        }
    }

    private void onClickPeerCastButton(PeerCastButton button, WanConnection selected) {

        NetworkIdentity identity = new NetworkIdentity(getActivity(), mActiveNicInfo, selected.getService());
        if (mPreferences.getAllDisabledNetworks().contains(identity)) {
            mPreferences.removeDisabledNetwork(identity);
            showToast(getString(R.string.t_upnp_used_in_this_connection_yes));
        } else {
            mPreferences.addDisabledNetwork(identity);
            showToast(getString(R.string.t_upnp_used_in_this_connection_no));
        }
        onPreparePeerCastButton(button, selected);
    }

    private void onRequestAddPort(Collection<WanConnection> connected) {
        new AddMappingDialog(getContext(), mRunningPort, connected, mActiveNicInfo.getPrivateAddress(),
                new AddMappingDialog.Listener() {
                    @Override
                    public void onOkClick(final WanConnection conn, final PortMapping mapping) {
                        Future f = conn.getManipulator().addPort(mapping, PecaPortFragmentBase.this);
                        getFuture(f);
                    }
                }).show();
    }

    private void onDeleteMapping(final WanConnection conn, final PortMapping mapping) {
        new AlertDialog.Builder(getContext()).setIcon(R.drawable.ic_delete).setTitle(R.string.t_delete)
                .setMessage(getString(R.string.t_do_you_want_to_delete, mapping.getDescription(),
                        mapping.getInternalClient()))
                .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        PortManipulator manipulator = conn.getManipulator();
                        Future f = manipulator.deletePort(mapping, PecaPortFragmentBase.this);
                        getFuture(f);
                    }
                }).setNegativeButton(android.R.string.cancel, null).show();
    }

    @Override
    public void onSuccess(Method m, RemoteService service, PortMapping mapping) {
        research();
    }

    @Override
    public void onFailure(Method m, RemoteService service, PortMapping mapping, String errMsg) {

    }

    protected void research() {
        if (mRouterDiscoverer != null)
            mRouterDiscoverer.research();
    }

    private void getFuture(Future<?> future) {
        try {
            future.get();
        } catch (ExecutionException e) {
            throw new RuntimeException(e.getCause());
        } catch (InterruptedException | CancellationException e) {
            throw new RuntimeException(e);
        }
    }

    private void showToast(CharSequence text) {
        Toast toast = Toast.makeText(getContext(), text, Toast.LENGTH_SHORT);
        toast.setGravity(Gravity.CENTER, 0, 0);
        toast.show();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();

        if (mRouterDiscoverer != null) {
            mRouterDiscoverer.onServiceDisconnected(null);
            getActivity().getApplicationContext().unbindService(mRouterDiscoverer);
        }
    }

    /**
     * Disable???????????FrameLayout
     */
    public static class ContainerFrame extends FrameLayout {
        public ContainerFrame(Context context) {
            super(context);
        }

        @Override
        public void setEnabled(boolean enabled) {
            super.setEnabled(enabled);
            if (enabled) {
                setAlpha(1);
            } else {
                setAlpha(0.5f);
            }
        }

        @Override
        public boolean onInterceptTouchEvent(MotionEvent ev) {
            return !isEnabled();
        }
    }

    /**
     * UI?????
     */
    public class ViewBinder {
        public Context getContext() {
            return PecaPortFragmentBase.this.getContext();
        }

        public void updateTextView(final @IdRes int id, final @Nullable CharSequence text) {
            mContentView.post(new Runnable() {
                @Override
                public void run() {
                    TextView textView = (TextView) mContentView.findViewById(id);
                    textView.setText(text);
                }
            });
        }

        public void updateImageViewResource(final @IdRes int id, final @DrawableRes int drawableRes,
                final @ColorRes int colorRes) {
            mContentView.post(new Runnable() {
                @Override
                public void run() {
                    ImageView imageView = (ImageView) mContentView.findViewById(id);
                    imageView.setImageResource(drawableRes);
                    imageView.setColorFilter(mContentView.getResources().getColor(colorRes));
                }
            });
        }

        public void setNetworkInterfaceInfo(@Nullable NetworkInterfaceInfo nicInfo) {
            if (nicInfo == null) {
                updateImageViewResource(R.id.vNicIcon, R.drawable.ic_close, R.color.md_red_800);
                updateTextView(R.id.vNicName, getContext().getString(R.string.t_network_not_found));
                updateTextView(R.id.vPrivateIp, getContext().getString(R.string.t_empty));
                updateTextView(R.id.vHardwareAddress, getContext().getString(R.string.t_empty));
                updateTextView(R.id.vRouterName, "");
                updateTextView(R.id.vRouterManufacturer, "");
                updateTextView(R.id.vWanExternalIp, "");
                return;
            }

            if (nicInfo instanceof NetworkInterfaceInfo.Ethernet) {
                updateImageViewResource(R.id.vNicIcon, R.drawable.ic_server_network, R.color.md_orange_500);
            } else if (nicInfo instanceof NetworkInterfaceInfo.Wifi) {
                updateImageViewResource(R.id.vNicIcon, R.drawable.ic_wifi, R.color.md_orange_500);
            }
            updateTextView(R.id.vNicName, nicInfo.getDisplayName(getContext()));
            updateTextView(R.id.vPrivateIp, nicInfo.getPrivateAddress().getHostAddress());
            updateTextView(R.id.vHardwareAddress, nicInfo.getHardwareAddress());
        }

        public void setWanConnections(@NonNull Collection<WanConnection> connections) {
            final Collection<WanConnection> connections1 = new ArrayList<>(connections);

            mContentView.post(new Runnable() {
                @Override
                public void run() {
                    mWanConnectionAdapter.setConnections(connections1);
                }
            });
        }

    }

    private class MappingEntryAdapter extends DefaultTableAdapter<Object> {
        private final LayoutInflater mInflater;
        private final View.OnClickListener mOnRemoveButtonClick;

        //??getItem()??
        private static final int C_ICON = 0; //PortMapping -> icon.visible
        private static final int C_CLIENT = 1; //String
        private static final int C_PORT = 2; //String
        private static final int C_PROTO = 3; //String
        private static final int C_DESC = 4; //String
        private static final int C_DURATION = 5; //Long
        private static final int C_ENABLED = 6; //Boolean
        private static final int C_REMOVE = 7; //PortMapping -> removeButton.setTag

        MappingEntryAdapter(Context c, View.OnClickListener onRemove) {
            super(8);
            mInflater = LayoutInflater.from(c);
            mOnRemoveButtonClick = onRemove;
        }

        @Nullable
        @Override
        protected TableRow createHeaderRow(ViewGroup parent) {
            TableRow header = (TableRow) mInflater.inflate(R.layout.mapping_entry_header_row, parent, false);
            int[] resHeaders = { 0, R.string.t_wan_internal_client, R.string.t_wan_external_internal_port,
                    R.string.t_protocol, R.string.t_wan_description, R.string.t_wan_duration, R.string.t_enabled,
                    0 };

            for (int i = 0, count = header.getChildCount(); i < count; i++) {
                if (resHeaders[i] != 0)
                    ((TextView) header.getChildAt(i)).setText(resHeaders[i]);
            }
            return header;
        }

        @UiThread
        public void setPortMappings(List<PortMapping> mappings) {
            removeAll();

            for (PortMapping m : mappings) {
                String port;
                if (m.getExternalPort().equals(m.getInternalPort()))
                    port = m.getExternalPort().toString();
                else
                    port = m.getExternalPort() + "/" + m.getInternalPort();

                addRow(m, m.getInternalClient(), port, m.getProtocol().name(), m.getDescription(),
                        m.getLeaseDurationSeconds().getValue(), m.isEnabled(), m);
            }
            notifyDataSetChanged();
        }

        @NonNull
        @Override
        protected TableRow createRow(ViewGroup parent) {
            return (TableRow) mInflater.inflate(R.layout.mapping_entry_data_row, parent, false);
        }

        @Override
        protected void bindView(View view, int row, int column) {
            Object item = getItem(row, column);
            if (item == null)
                throw new NullPointerException();

            switch (column) {
            case C_ICON:
                view.findViewById(R.id.vIcon)
                        .setVisibility(isPeerCastPort((PortMapping) item) ? View.VISIBLE : View.INVISIBLE);
                break;

            case C_CLIENT:
            case C_PORT:
            case C_PROTO:
                super.bindView(view, row, column);
                ((TextView) view).setGravity(Gravity.CENTER);
                break;

            case C_DURATION: {
                TextView textView = (TextView) view;
                textView.setGravity(Gravity.CENTER);
                long sec = (Long) item;
                if (sec == 0) {
                    textView.setText(R.string.t_wan_duration_is_0);
                } else {
                    textView.setText(DurationFormatUtils.formatDuration(sec * 1000, "dd'd' HH'h'", false));
                }
                break;
            }
            case C_DESC:
                TextView textView = (TextView) view;
                textView.setGravity(Gravity.LEFT);
                super.bindView(view, row, column);
                break;

            case C_ENABLED: {
                break;
            }

            case C_REMOVE:
                ImageButton vRemove = (ImageButton) view.findViewById(R.id.vRemove);
                vRemove.setOnClickListener(mOnRemoveButtonClick);
                //tag is PortMappingAction object
                //Log.d(TAG, view + ",, " + row);
                vRemove.setTag(getItem(row, column));
                break;

            default:
                throw new RuntimeException();
            }
        }

        private boolean isPeerCastPort(PortMapping m) {
            return mRunningPort == m.getExternalPort().getValue().intValue()
                    && mRunningPort == m.getInternalPort().getValue().intValue()
                    && m.getProtocol() == PortMapping.Protocol.TCP;
        }
    }

}