nl.eduvpn.app.fragment.ProviderSelectionFragment.java Source code

Java tutorial

Introduction

Here is the source code for nl.eduvpn.app.fragment.ProviderSelectionFragment.java

Source

/*
 *  This file is part of eduVPN.
 *
 *     eduVPN 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.
 *
 *     eduVPN 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 eduVPN.  If not, see <http://www.gnu.org/licenses/>.
 */

package nl.eduvpn.app.fragment;

import android.app.ProgressDialog;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.design.widget.Snackbar;
import android.support.v4.app.Fragment;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast;

import org.json.JSONObject;

import javax.inject.Inject;

import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.Unbinder;
import nl.eduvpn.app.Constants;
import nl.eduvpn.app.EduVPNApplication;
import nl.eduvpn.app.R;
import nl.eduvpn.app.adapter.ProviderAdapter;
import nl.eduvpn.app.entity.AuthorizationType;
import nl.eduvpn.app.entity.DiscoveredAPI;
import nl.eduvpn.app.entity.Instance;
import nl.eduvpn.app.service.APIService;
import nl.eduvpn.app.service.ConfigurationService;
import nl.eduvpn.app.service.ConnectionService;
import nl.eduvpn.app.service.HistoryService;
import nl.eduvpn.app.service.PreferencesService;
import nl.eduvpn.app.service.SerializerService;
import nl.eduvpn.app.utils.ErrorDialog;
import nl.eduvpn.app.utils.ItemClickSupport;
import nl.eduvpn.app.utils.Log;

/**
 * The fragment showing the provider list.
 * Created by Daniel Zolnai on 2016-10-07.
 */
public class ProviderSelectionFragment extends Fragment {

    private static final String TAG = ProviderSelectionFragment.class.getName();
    public static final String EXTRA_AUTHORIZATION_TYPE = "extra_authorization_type";

    @BindView(R.id.provider_list)
    protected RecyclerView _providerList;

    @BindView(R.id.provider_status)
    protected TextView _providerStatus;

    @BindView(R.id.header)
    protected TextView _header;

    @BindView(R.id.description)
    protected TextView _description;

    @Inject
    protected ConfigurationService _configurationService;

    @Inject
    protected APIService _apiService;

    @Inject
    protected SerializerService _serializerService;

    @Inject
    protected ConnectionService _connectionService;

    @Inject
    protected HistoryService _historyService;

    @Inject
    protected PreferencesService _preferencesService;

    private Unbinder _unbinder;

    @AuthorizationType
    private int _authorizationType;

    private RecyclerView.AdapterDataObserver _dataObserver;

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (savedInstanceState != null) {
            //noinspection WrongConstant
            _authorizationType = savedInstanceState.getInt(EXTRA_AUTHORIZATION_TYPE, -1);
            if (_authorizationType < 0) {
                throw new RuntimeException("Selected connection type was not saved into instance state!");
            }
        } else {
            //noinspection WrongConstant
            _authorizationType = getArguments().getInt(EXTRA_AUTHORIZATION_TYPE, -1);
            if (_authorizationType < 0) {
                throw new RuntimeException("Selected connection type was not provided via arguments!");
            }
        }
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putInt(EXTRA_AUTHORIZATION_TYPE, _authorizationType);
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
            @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_provider_selection, container, false);
        _unbinder = ButterKnife.bind(this, view);
        EduVPNApplication.get(view.getContext()).component().inject(this);
        if (_authorizationType == AuthorizationType.LOCAL) {
            _header.setText(R.string.select_your_institution_title);
            _description.setVisibility(View.GONE);
        } else {
            _header.setText(R.string.select_your_country_title);
            _description.setVisibility(View.VISIBLE);
        }
        _providerList.setHasFixedSize(true);
        _providerList
                .setLayoutManager(new LinearLayoutManager(view.getContext(), LinearLayoutManager.VERTICAL, false));
        final ProviderAdapter adapter = new ProviderAdapter(_configurationService, _authorizationType);
        _providerList.setAdapter(adapter);
        ItemClickSupport.addTo(_providerList).setOnItemClickListener(new ItemClickSupport.OnItemClickListener() {
            @Override
            public void onItemClicked(RecyclerView recyclerView, int position, View v) {
                Instance instance = ((ProviderAdapter) recyclerView.getAdapter()).getItem(position);
                if (instance == null) {
                    // Should never happen
                    View mainView = getView();
                    if (mainView != null) {
                        Snackbar.make(mainView, R.string.error_selected_instance_not_found, Snackbar.LENGTH_LONG)
                                .show();
                    }
                    Log.e(TAG, "Instance not found for position: " + String.valueOf(position));
                } else {
                    _connectToApi(instance);
                }
            }
        });
        // When clicked long on an item, display its name in a toast.
        ItemClickSupport.addTo(_providerList)
                .setOnItemLongClickListener(new ItemClickSupport.OnItemLongClickListener() {
                    @Override
                    public boolean onItemLongClicked(RecyclerView recyclerView, int position, View v) {
                        Instance instance = ((ProviderAdapter) recyclerView.getAdapter()).getItem(position);
                        String name = instance == null ? getString(R.string.display_other_name)
                                : instance.getDisplayName();
                        Toast.makeText(recyclerView.getContext(), name, Toast.LENGTH_LONG).show();
                        return true;
                    }
                });
        adapter.registerAdapterDataObserver(_dataObserver = new RecyclerView.AdapterDataObserver() {
            @Override
            public void onChanged() {
                if (adapter.getItemCount() > 0) {
                    _providerStatus.setVisibility(View.GONE);
                } else if (adapter.isDiscoveryPending()) {
                    _providerStatus.setText(R.string.discovering_providers);
                    _providerStatus.setVisibility(View.VISIBLE);
                } else {
                    _providerStatus.setText(R.string.no_provider_found);
                    _providerStatus.setVisibility(View.VISIBLE);
                }
            }
        });
        // Trigger initial status
        _dataObserver.onChanged();
        return view;
    }

    /**
     * Starts connecting to an API provider.
     *
     * @param instance The instance to connect to.
     */
    private void _connectToApi(final Instance instance) {
        DiscoveredAPI discoveredAPI = _historyService.getCachedDiscoveredAPI(instance.getSanitizedBaseURI());
        // If there's only a discovered API, initiate the connection
        if (discoveredAPI != null) {
            Log.d(TAG, "Cached discovered API found.");
            _connectionService.initiateConnection(getActivity(), instance, discoveredAPI);
            return;
        }
        // If no discovered API, fetch it first, then initiate the connection for the login
        Log.d(TAG, "No cached discovered API found, continuing with discovery.");
        final ProgressDialog dialog = ProgressDialog.show(getContext(), getString(R.string.progress_dialog_title),
                getString(R.string.api_discovery_message), true);
        // Discover the API
        _apiService.getJSON(instance.getSanitizedBaseURI() + Constants.API_DISCOVERY_POSTFIX, null,
                new APIService.Callback<JSONObject>() {
                    @Override
                    public void onSuccess(JSONObject result) {
                        try {
                            DiscoveredAPI discoveredAPI = _serializerService.deserializeDiscoveredAPI(result);
                            dialog.dismiss();
                            // Cache the result
                            _historyService.cacheDiscoveredAPI(instance.getSanitizedBaseURI(), discoveredAPI);
                            _connectionService.initiateConnection(getActivity(), instance, discoveredAPI);
                        } catch (SerializerService.UnknownFormatException ex) {
                            Log.e(TAG, "Error parsing discovered API!", ex);
                            ErrorDialog.show(getContext(), R.string.error_dialog_title, ex.toString());
                            dialog.dismiss();
                        }
                    }

                    @Override
                    public void onError(String errorMessage) {
                        dialog.dismiss();
                        Log.e(TAG, "Error while fetching discovered API: " + errorMessage);
                        ErrorDialog.show(getContext(), R.string.error_dialog_title, errorMessage);
                    }
                });
    }

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

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        if (_providerList != null && _providerList.getAdapter() != null && _dataObserver != null) {
            _providerList.getAdapter().unregisterAdapterDataObserver(_dataObserver);
            _dataObserver = null;
        }
        _unbinder.unbind();
    }
}