se.leap.bitmaskclient.ConfigurationWizard.java Source code

Java tutorial

Introduction

Here is the source code for se.leap.bitmaskclient.ConfigurationWizard.java

Source

/**
 * Copyright (c) 2013 LEAP Encryption Access Project and contributers
 *
 * 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 se.leap.bitmaskclient;

import android.app.*;
import android.content.*;
import android.os.*;
import android.view.*;
import android.widget.*;

import com.pedrogomez.renderers.*;

import java.net.*;
import java.util.*;

import butterknife.*;

import org.jetbrains.annotations.*;
import org.json.*;

import javax.inject.*;

import se.leap.bitmaskclient.DownloadFailedDialog.DownloadFailedDialogInterface;
import se.leap.bitmaskclient.NewProviderDialog.NewProviderDialogInterface;
import se.leap.bitmaskclient.ProviderAPIResultReceiver.Receiver;
import se.leap.bitmaskclient.ProviderDetailFragment.ProviderDetailFragmentInterface;
import se.leap.bitmaskclient.eip.Constants;
import se.leap.bitmaskclient.userstatus.SessionDialog;

/**
 * Activity that builds and shows the list of known available providers.
 * <p/>
 * It also allows the user to enter custom providers with a button.
 *
 * @author parmegv
 */
public class ConfigurationWizard extends Activity implements NewProviderDialogInterface,
        ProviderDetailFragmentInterface, DownloadFailedDialogInterface, Receiver {

    @InjectView(R.id.progressbar_configuration_wizard)
    ProgressBar mProgressBar;
    @InjectView(R.id.progressbar_description)
    TextView progressbar_description;

    @InjectView(R.id.provider_list)
    ListView provider_list_view;
    @Inject
    ProviderListAdapter adapter;

    private ProviderManager provider_manager;
    private Intent mConfigState = new Intent();
    private Provider selected_provider;

    final public static String TAG = ConfigurationWizard.class.getSimpleName();

    final protected static String PROVIDER_SET = "PROVIDER SET";
    final protected static String SERVICES_RETRIEVED = "SERVICES RETRIEVED";
    final protected static String ASSETS_URL_FOLDER = "urls";

    final private static String PROGRESSBAR_TEXT = TAG + "PROGRESSBAR_TEXT";
    final private static String PROGRESSBAR_NUMBER = TAG + "PROGRESSBAR_NUMBER";

    public ProviderAPIResultReceiver providerAPI_result_receiver;
    private ProviderAPIBroadcastReceiver_Update providerAPI_broadcast_receiver_update;

    private static SharedPreferences preferences;
    FragmentManagerEnhanced fragment_manager;
    private static boolean setting_up_provider = false;
    private String progressbar_text = "";
    private String provider_name = "";
    private int progress = -1;

    private void initProviderList() {
        List<Renderer<Provider>> prototypes = new ArrayList<Renderer<Provider>>();
        prototypes.add(new ProviderRenderer(this));
        ProviderRendererBuilder providerRendererBuilder = new ProviderRendererBuilder(prototypes);
        adapter = new ProviderListAdapter(getLayoutInflater(), providerRendererBuilder, provider_manager);
        provider_list_view.setAdapter(adapter);
    }

    @Override
    protected void onSaveInstanceState(@NotNull Bundle outState) {
        if (mProgressBar != null)
            outState.putInt(PROGRESSBAR_NUMBER, mProgressBar.getProgress());
        if (progressbar_description != null)
            outState.putString(PROGRESSBAR_TEXT, progressbar_description.getText().toString());
        outState.putParcelable(Provider.KEY, selected_provider);
        super.onSaveInstanceState(outState);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        preferences = getSharedPreferences(Dashboard.SHARED_PREFERENCES, MODE_PRIVATE);
        fragment_manager = new FragmentManagerEnhanced(getFragmentManager());
        provider_manager = ProviderManager.getInstance(getAssets(), getExternalFilesDir(null));

        setUpInitialUI();

        initProviderList();

        if (savedInstanceState != null)
            restoreState(savedInstanceState);
        setUpProviderAPIResultReceiver();
    }

    private void restoreState(Bundle savedInstanceState) {
        progressbar_text = savedInstanceState.getString(PROGRESSBAR_TEXT, "");
        provider_name = savedInstanceState.getString(Provider.NAME, "");
        selected_provider = savedInstanceState.getParcelable(Provider.KEY);

        if (fragment_manager.findFragmentByTag(ProviderDetailFragment.TAG) == null && setting_up_provider) {
            onItemSelectedUi();
            if (progress > 0)
                mProgressBar.setProgress(progress);
        }
    }

    @Override
    protected void onPostResume() {
        super.onPostResume();
        if (!progressbar_text.isEmpty() && !provider_name.isEmpty() && progress != -1) {
            progressbar_description.setText(progressbar_text);
            mProgressBar.setProgress(progress);

            progressbar_text = "";
            provider_name = "";
            progress = -1;
        }
    }

    private void setUpInitialUI() {
        setContentView(R.layout.configuration_wizard_activity);
        ButterKnife.inject(this);

        hideProgressBar();
    }

    private void hideProgressBar() {
        mProgressBar.setVisibility(ProgressBar.INVISIBLE);

        progressbar_description.setVisibility(TextView.INVISIBLE);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (providerAPI_broadcast_receiver_update != null)
            unregisterReceiver(providerAPI_broadcast_receiver_update);
    }

    private void setUpProviderAPIResultReceiver() {
        providerAPI_result_receiver = new ProviderAPIResultReceiver(new Handler(), this);
        providerAPI_broadcast_receiver_update = new ProviderAPIBroadcastReceiver_Update();

        IntentFilter update_intent_filter = new IntentFilter(ProviderAPI.UPDATE_PROGRESSBAR);
        update_intent_filter.addCategory(Intent.CATEGORY_DEFAULT);
        registerReceiver(providerAPI_broadcast_receiver_update, update_intent_filter);
    }

    @Override
    public void onReceiveResult(int resultCode, Bundle resultData) {
        if (resultCode == ProviderAPI.PROVIDER_OK) {
            mConfigState.setAction(PROVIDER_SET);
            try {
                String provider_json_string = preferences.getString(Provider.KEY, "");
                if (!provider_json_string.isEmpty())
                    selected_provider.define(new JSONObject(provider_json_string));
            } catch (JSONException e) {
                e.printStackTrace();
            }

            if (preferences.getBoolean(Constants.ALLOWED_ANON, false)) {
                mConfigState.putExtra(SERVICES_RETRIEVED, true);

                downloadVpnCertificate();
            } else {
                mProgressBar.incrementProgressBy(1);
                hideProgressBar();

                showProviderDetails();
            }
        } else if (resultCode == ProviderAPI.PROVIDER_NOK) {
            hideProgressBar();
            preferences.edit().remove(Provider.KEY).apply();
            setting_up_provider = false;

            setResult(RESULT_CANCELED, mConfigState);

            String reason_to_fail = resultData.getString(ProviderAPI.ERRORS);
            showDownloadFailedDialog(reason_to_fail);
        } else if (resultCode == ProviderAPI.CORRECTLY_DOWNLOADED_CERTIFICATE) {
            mProgressBar.incrementProgressBy(1);
            hideProgressBar();

            showProviderDetails();
        } else if (resultCode == ProviderAPI.INCORRECTLY_DOWNLOADED_CERTIFICATE) {
            hideProgressBar();

            setResult(RESULT_CANCELED, mConfigState);
        } else if (resultCode == AboutActivity.VIEWED) {
            // Do nothing, right now
            // I need this for CW to wait for the About activity to end before going back to Dashboard.
        }
    }

    @OnItemClick(R.id.provider_list)
    void onItemSelected(int position) {
        //TODO Code 2 pane view
        selected_provider = adapter.getItem(position);
        onItemSelectedUi();
        onItemSelectedLogic();
    }

    private void onItemSelectedLogic() {
        setUpProvider();
    }

    private void onItemSelectedUi() {
        startProgressBar();
        adapter.hideAllBut(adapter.indexOf(selected_provider));
    }

    @Override
    public void onBackPressed() {
        if (setting_up_provider) {
            stopSettingUpProvider();
        } else {
            askDashboardToQuitApp();
            super.onBackPressed();
        }
    }

    private void stopSettingUpProvider() {
        ProviderAPI.stop();
        mProgressBar.setVisibility(ProgressBar.GONE);
        mProgressBar.setProgress(0);
        progressbar_description.setVisibility(TextView.GONE);

        cancelSettingUpProvider();
    }

    public void cancelSettingUpProvider() {
        adapter.showAllProviders();
        setting_up_provider = false;
        preferences.edit().remove(Provider.KEY).remove(Constants.ALLOWED_ANON).remove(Constants.KEY).apply();
    }

    private void askDashboardToQuitApp() {
        Intent ask_quit = new Intent();
        ask_quit.putExtra(Dashboard.ACTION_QUIT, Dashboard.ACTION_QUIT);
        setResult(RESULT_CANCELED, ask_quit);
    }

    private void startProgressBar() {
        mProgressBar.setVisibility(ProgressBar.VISIBLE);
        progressbar_description.setVisibility(TextView.VISIBLE);
        mProgressBar.setProgress(0);
        mProgressBar.setMax(3);

        int measured_height = listItemHeight();
        mProgressBar.setTranslationY(measured_height);
        progressbar_description.setTranslationY(measured_height + mProgressBar.getHeight());
    }

    private int listItemHeight() {
        View listItem = adapter.getView(0, null, provider_list_view);
        listItem.setLayoutParams(new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT,
                RelativeLayout.LayoutParams.WRAP_CONTENT));
        WindowManager wm = (WindowManager) getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
        Display display = wm.getDefaultDisplay();
        int screenWidth = display.getWidth(); // deprecated

        int listViewWidth = screenWidth - 10 - 10;
        int widthSpec = View.MeasureSpec.makeMeasureSpec(listViewWidth, View.MeasureSpec.AT_MOST);
        listItem.measure(widthSpec, 0);

        return listItem.getMeasuredHeight();
    }

    /**
     * Asks ProviderAPI to download an anonymous (anon) VPN certificate.
     */
    private void downloadVpnCertificate() {
        Intent provider_API_command = new Intent(this, ProviderAPI.class);

        provider_API_command.setAction(ProviderAPI.DOWNLOAD_CERTIFICATE);
        provider_API_command.putExtra(ProviderAPI.RECEIVER_KEY, providerAPI_result_receiver);

        startService(provider_API_command);
    }

    /**
     * Open the new provider dialog
     */
    public void addAndSelectNewProvider() {
        FragmentTransaction fragment_transaction = fragment_manager.removePreviousFragment(NewProviderDialog.TAG);
        new NewProviderDialog().show(fragment_transaction, NewProviderDialog.TAG);
    }

    /**
     * Open the new provider dialog with data
     */
    public void addAndSelectNewProvider(String main_url) {
        FragmentTransaction fragment_transaction = fragment_manager.removePreviousFragment(NewProviderDialog.TAG);

        DialogFragment newFragment = new NewProviderDialog();
        Bundle data = new Bundle();
        data.putString(Provider.MAIN_URL, main_url);
        newFragment.setArguments(data);
        newFragment.show(fragment_transaction, NewProviderDialog.TAG);
    }

    /**
     * Once selected a provider, this fragment offers the user to log in,
     * use it anonymously (if possible)
     * or cancel his/her election pressing the back button.
     *
     * @param reason_to_fail
     */
    public void showDownloadFailedDialog(String reason_to_fail) {
        FragmentTransaction fragment_transaction = fragment_manager
                .removePreviousFragment(DownloadFailedDialog.TAG);

        DialogFragment newFragment = DownloadFailedDialog.newInstance(reason_to_fail);
        newFragment.show(fragment_transaction, DownloadFailedDialog.TAG);
    }

    /**
     * Once selected a provider, this fragment offers the user to log in,
     * use it anonymously (if possible)
     * or cancel his/her election pressing the back button.
     *
     * @param view
     */
    private void showProviderDetails() {
        if (setting_up_provider) {
            FragmentTransaction fragment_transaction = fragment_manager
                    .removePreviousFragment(ProviderDetailFragment.TAG);

            DialogFragment newFragment = ProviderDetailFragment.newInstance();
            newFragment.show(fragment_transaction, ProviderDetailFragment.TAG);
            setting_up_provider = false;
        }
    }

    public void showAndSelectProvider(String provider_main_url) {
        try {
            selected_provider = new Provider(new URL((provider_main_url)));
            adapter.add(selected_provider);
            adapter.saveProviders();
            autoSelectProvider(selected_provider);
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }
    }

    private void autoSelectProvider(Provider provider) {
        selected_provider = provider;
        onItemSelectedUi();
        onItemSelectedLogic();
    }

    /**
     * Asks ProviderAPI to download a new provider.json file
     *
     * @param provider_name
     * @param provider_main_url
     */
    public void setUpProvider() {
        Intent provider_API_command = new Intent(this, ProviderAPI.class);
        Bundle parameters = new Bundle();
        parameters.putString(Provider.MAIN_URL, selected_provider.mainUrl().toString());
        parameters.putString(Provider.CA_CERT_FINGERPRINT, selected_provider.certificatePin());

        provider_API_command.setAction(ProviderAPI.SET_UP_PROVIDER);
        provider_API_command.putExtra(ProviderAPI.PARAMETERS, parameters);
        provider_API_command.putExtra(ProviderAPI.RECEIVER_KEY, providerAPI_result_receiver);

        startService(provider_API_command);
        setting_up_provider = true;
    }

    public void retrySetUpProvider() {
        cancelSettingUpProvider();
        if (!ProviderAPI.caCertDownloaded()) {
            addAndSelectNewProvider(ProviderAPI.lastProviderMainUrl());
        } else {
            Intent provider_API_command = new Intent(this, ProviderAPI.class);

            provider_API_command.setAction(ProviderAPI.SET_UP_PROVIDER);
            provider_API_command.putExtra(ProviderAPI.RECEIVER_KEY, providerAPI_result_receiver);

            startService(provider_API_command);
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.configuration_wizard_activity, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
        case R.id.about_leap:
            startActivityForResult(new Intent(this, AboutActivity.class), 0);
            return true;
        case R.id.new_provider:
            addAndSelectNewProvider();
            return true;
        default:
            return super.onOptionsItemSelected(item);
        }
    }

    public void showAllProviders() {
        adapter.showAllProviders();
    }

    @Override
    public void login() {
        Intent ask_login = new Intent();
        ask_login.putExtra(Provider.KEY, selected_provider);
        ask_login.putExtra(SessionDialog.TAG, SessionDialog.TAG);
        setResult(RESULT_OK, ask_login);
        setting_up_provider = false;
        finish();
    }

    @Override
    public void use_anonymously() {
        Intent pass_provider = new Intent();
        pass_provider.putExtra(Provider.KEY, selected_provider);
        setResult(RESULT_OK, pass_provider);
        setting_up_provider = false;
        finish();
    }

    public class ProviderAPIBroadcastReceiver_Update extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            int update = intent.getIntExtra(ProviderAPI.CURRENT_PROGRESS, 0);
            mProgressBar.setProgress(update);
        }
    }
}