diff options
Diffstat (limited to 'app/src')
16 files changed, 447 insertions, 384 deletions
| diff --git a/app/src/insecure/java/se/leap/bitmaskclient/AddProviderActivity.java b/app/src/insecure/java/se/leap/bitmaskclient/AddProviderActivity.java new file mode 100644 index 00000000..a63174c8 --- /dev/null +++ b/app/src/insecure/java/se/leap/bitmaskclient/AddProviderActivity.java @@ -0,0 +1,126 @@ +package se.leap.bitmaskclient; + +import android.content.Intent; +import android.os.Bundle; +import android.support.design.widget.TextInputEditText; +import android.support.design.widget.TextInputLayout; +import android.text.Editable; +import android.text.TextWatcher; +import android.view.View; +import android.widget.Button; +import android.widget.CheckBox; + +import javax.inject.Inject; + +import butterknife.InjectView; +import se.leap.bitmaskclient.ProviderListContent.ProviderItem; + +public class AddProviderActivity extends ConfigWizardBaseActivity { + +    final public static String TAG = "AddProviderActivity"; +    final public static String EXTRAS_KEY_NEW_URL = "NEW_URL"; + +    @InjectView(R.id.text_uri_error) +    TextInputLayout urlError; + +    @InjectView(R.id.text_uri) +    TextInputEditText editUrl; + +    @InjectView(R.id.danger_checkbox) +    CheckBox checkboxDanger; + +    @Override +    protected void onCreate(Bundle savedInstanceState) { +        super.onCreate(savedInstanceState); + +        setContentView(R.layout.a_add_provider); +        if (this.getIntent().getExtras() != null) { +            editUrl.setText(this.getIntent().getExtras().getString(ProviderListBaseActivity.EXTRAS_KEY_INVALID_URL)); +        } + +        checkboxDanger.setVisibility(View.VISIBLE); +        checkboxDanger.setText(R.string.danger_checkbox); +        checkboxDanger.setChecked(preferences.getBoolean(ProviderItem.DANGER_ON, false)); + +        final Button saveButton = findViewById(R.id.button_save); +        saveButton.setOnClickListener(new View.OnClickListener() { +            public void onClick(View v) { +                preferences.edit().putBoolean(ProviderItem.DANGER_ON, checkboxDanger.isChecked()).apply(); +                saveProvider(); +            } +        }); + +        final Button cancelButton = findViewById(R.id.button_cancel); +        cancelButton.setOnClickListener(new View.OnClickListener() { +            public void onClick(View v) { +                finish(); +            } +        }); +        setUpListeners(); +        setUpInitialUI(); +    } + +    private void setUpInitialUI() { +        setProviderHeaderText(R.string.add_provider); +        hideProgressBar(); +    } + +    private void saveProvider() { +        String entered_url = getURL(); +        if (validURL(entered_url)) { +            Intent intent = this.getIntent(); +            intent.putExtra(EXTRAS_KEY_NEW_URL, entered_url); +            setResult(RESULT_OK, intent); +            finish(); +        } else { +            editUrl.setText(""); +            urlError.setError(getString(R.string.not_valid_url_entered)); +        } +    } + +    private void setUpListeners() { + +        editUrl.addTextChangedListener(new TextWatcher() { +            @Override +            public void beforeTextChanged(CharSequence s, int start, int count, int after) { +            } + +            @Override +            public void onTextChanged(CharSequence s, int start, int before, int count) { +            } + +            @Override +            public void afterTextChanged(Editable s) { +                if (!validURL(getURL())) { +                    urlError.setError(getString(R.string.not_valid_url_entered)); +                } else { +                    urlError.setError(null); +                } +            } +        }); +    } + +    private String getURL() { +        String entered_url = editUrl.getText().toString().trim(); +        if (entered_url.contains("www.")) entered_url = entered_url.replaceFirst("www.", ""); +        if (!entered_url.startsWith("https://")) { +            if (entered_url.startsWith("http://")) { +                entered_url = entered_url.substring("http://".length()); +            } +            entered_url = "https://".concat(entered_url); +        } +        return entered_url; +    } + +    /** +     * Checks if the entered url is valid or not. +     * +     * @param enteredUrl +     * @return true if it's not empty nor contains only the protocol. +     */ +    boolean validURL(String enteredUrl) { +        return android.util.Patterns.WEB_URL.matcher(enteredUrl).matches(); +    } + + +} diff --git a/app/src/insecure/java/se/leap/bitmaskclient/NewProviderDialog.java b/app/src/insecure/java/se/leap/bitmaskclient/NewProviderDialog.java deleted file mode 100644 index d7d9eec5..00000000 --- a/app/src/insecure/java/se/leap/bitmaskclient/NewProviderDialog.java +++ /dev/null @@ -1,126 +0,0 @@ -/** - * 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.AlertDialog; -import android.app.Dialog; -import android.content.Context; -import android.content.DialogInterface; -import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.v4.app.DialogFragment; -import android.view.LayoutInflater; -import android.view.View; -import android.widget.CheckBox; -import android.widget.EditText; -import android.widget.Toast; - -import butterknife.ButterKnife; -import butterknife.InjectView; -import se.leap.bitmaskclient.ProviderListContent.ProviderItem; - -/** - * Implements the new custom provider dialog. - * - * @author parmegv - */ -public class NewProviderDialog extends DialogFragment { - -    final public static String TAG = "newProviderDialog"; - -    @InjectView(R.id.new_provider_url) -    EditText url_input_field; - -    @InjectView(R.id.danger_checkbox) -    CheckBox danger_checkbox; - -    public interface NewProviderDialogInterface { -        void showAndSelectProvider(String url_provider, boolean danger_on); -    } - -    NewProviderDialogInterface interface_with_ConfigurationWizard; - -    @Override -    public void onAttach(Context context) { -        super.onAttach(context); -        try { -            interface_with_ConfigurationWizard = (NewProviderDialogInterface) context; -        } catch (ClassCastException e) { -            throw new ClassCastException(context.toString() -                    + " must implement NoticeDialogListener"); -        } -    } - -    @Override -    @NonNull -    public Dialog onCreateDialog(Bundle savedInstanceState) { -        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); -        LayoutInflater inflater = getActivity().getLayoutInflater(); -        View view = inflater.inflate(R.layout.new_provider_dialog, null); -        ButterKnife.inject(this, view); -        Bundle arguments = getArguments(); -        if (arguments != null) { -            url_input_field.setText(arguments.getString(Provider.MAIN_URL, "")); -            danger_checkbox.setActivated(arguments.getBoolean(ProviderItem.DANGER_ON, false)); -        } - -        builder.setView(view) -                .setMessage(R.string.introduce_new_provider) -                .setPositiveButton(R.string.save, new DialogInterface.OnClickListener() { -                    public void onClick(DialogInterface dialog, int id) { -                        saveProvider(); -                    } -                }) -                .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { -                    public void onClick(DialogInterface dialog, int id) { -                        dialog.cancel(); -                    } -                }); -        // Create the AlertDialog object and return it -        return builder.create(); -    } - -    private void saveProvider() { -        String entered_url = url_input_field.getText().toString().trim(); -        if (!entered_url.startsWith("https://")) { -            if (entered_url.startsWith("http://")) { -                entered_url = entered_url.substring("http://".length()); -            } -            entered_url = "https://".concat(entered_url); -        } -        boolean danger_on = danger_checkbox.isChecked(); -        if (validURL(entered_url)) { -            interface_with_ConfigurationWizard.showAndSelectProvider(entered_url, danger_on); -            Toast.makeText(getActivity().getApplicationContext(), R.string.valid_url_entered, Toast.LENGTH_LONG).show(); -        } else { -            url_input_field.setText(""); -            danger_checkbox.setChecked(false); -            Toast.makeText(getActivity().getApplicationContext(), R.string.not_valid_url_entered, Toast.LENGTH_LONG).show(); -        } -    } - -    /** -     * Checks if the entered url is valid or not. -     * -     * @param entered_url -     * @return true if it's not empty nor contains only the protocol. -     */ -    boolean validURL(String entered_url) { -        //return !entered_url.isEmpty() && entered_url.matches("http[s]?://.+") && !entered_url.replaceFirst("http[s]?://", "").isEmpty(); -        return android.util.Patterns.WEB_URL.matcher(entered_url).matches(); -    } -} diff --git a/app/src/insecure/java/se/leap/bitmaskclient/ProviderApiManager.java b/app/src/insecure/java/se/leap/bitmaskclient/ProviderApiManager.java index 7e33cd63..e3fb549f 100644 --- a/app/src/insecure/java/se/leap/bitmaskclient/ProviderApiManager.java +++ b/app/src/insecure/java/se/leap/bitmaskclient/ProviderApiManager.java @@ -142,8 +142,7 @@ public class ProviderApiManager extends ProviderApiManagerBase {              providerDotJsonString = downloadFromApiUrlWithProviderCA("/provider.json", caCert, providerDefinition, dangerOn);          if (ConfigHelper.checkErroneousDownload(providerDotJsonString) || !isValidJson(providerDotJsonString)) { -            result.putString(ERRORS, resources.getString(malformed_url)); -            result.putBoolean(BROADCAST_RESULT_KEY, false); +            setErrorResult(result, malformed_url, null);              return result;          } diff --git a/app/src/insecure/java/se/leap/bitmaskclient/ProviderListActivity.java b/app/src/insecure/java/se/leap/bitmaskclient/ProviderListActivity.java index 67565d70..3190d651 100644 --- a/app/src/insecure/java/se/leap/bitmaskclient/ProviderListActivity.java +++ b/app/src/insecure/java/se/leap/bitmaskclient/ProviderListActivity.java @@ -50,29 +50,13 @@ public class ProviderListActivity extends ProviderListBaseActivity {          preferences.edit().remove(ProviderItem.DANGER_ON).apply();      } -    public void showAndSelectProvider(String provider_main_url, boolean danger_on) { -        try { -            provider = new Provider(new URL((provider_main_url))); -            autoSelectProvider(provider, danger_on); -        } catch (MalformedURLException e) { -            e.printStackTrace(); -        } -    } - -    private void autoSelectProvider(Provider provider, boolean danger_on) { -        preferences.edit().putBoolean(ProviderItem.DANGER_ON, danger_on).apply(); -        this.provider = provider; -        onItemSelectedLogic(); -        showProgressBar(); -    } -      /**       * Asks ProviderAPI to download a new provider.json file       *       * @param danger_on tells if HTTPS client should bypass certificate errors       */      public void setUpProvider(boolean danger_on) { -        mConfigState.setAction(SETTING_UP_PROVIDER); +        configState.setAction(SETTING_UP_PROVIDER);          Bundle parameters = new Bundle();          parameters.putBoolean(ProviderItem.DANGER_ON, danger_on); @@ -85,7 +69,7 @@ public class ProviderListActivity extends ProviderListBaseActivity {       */      @Override      public void retrySetUpProvider(@NonNull Provider provider) { -        mConfigState.setAction(SETTING_UP_PROVIDER); +        configState.setAction(SETTING_UP_PROVIDER);          ProviderAPICommand.execute(this, SET_UP_PROVIDER, provider);      } diff --git a/app/src/insecure/res/layout-xlarge/new_provider_dialog.xml b/app/src/insecure/res/layout-xlarge/new_provider_dialog.xml deleted file mode 100644 index fc7d84ab..00000000 --- a/app/src/insecure/res/layout-xlarge/new_provider_dialog.xml +++ /dev/null @@ -1,26 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" -    android:layout_width="wrap_content" -    android:layout_height="wrap_content" -    android:orientation="vertical" -    android:textSize="24sp" > -     -    <EditText -        android:id="@+id/new_provider_url" -        android:inputType="textUri" -        android:layout_width="match_parent" -        android:layout_height="wrap_content" -        android:layout_marginTop="16dp" -        android:layout_marginLeft="4dp" -        android:layout_marginRight="4dp" -        android:textSize="24sp" -        android:hint="@string/new_provider_uri" /> - -    <CheckBox -        android:id="@+id/danger_checkbox" -        android:layout_width="wrap_content" -        android:layout_height="wrap_content" -        android:textSize="24sp" -        android:text="@string/danger_checkbox" /> - -</LinearLayout>
\ No newline at end of file diff --git a/app/src/insecure/res/layout/new_provider_dialog.xml b/app/src/insecure/res/layout/new_provider_dialog.xml deleted file mode 100644 index 8888a1d9..00000000 --- a/app/src/insecure/res/layout/new_provider_dialog.xml +++ /dev/null @@ -1,24 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" -    android:layout_width="wrap_content" -    android:layout_height="wrap_content" -    android:orientation="vertical" > - -    <EditText -        android:id="@+id/new_provider_url" -        android:inputType="textUri" -        android:layout_width="match_parent" -        android:layout_height="wrap_content" -        android:layout_marginTop="16dp" -        android:layout_marginLeft="4dp" -        android:layout_marginRight="4dp" -        android:layout_marginBottom="4dp" -        android:hint="@string/new_provider_uri" /> - -    <CheckBox -        android:id="@+id/danger_checkbox" -        android:layout_width="wrap_content" -        android:layout_height="wrap_content" -        android:text="@string/danger_checkbox" /> - -</LinearLayout>
\ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 8b87d095..b1131850 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -94,6 +94,10 @@              android:label="@string/configuration_wizard_title" />          <activity +            android:name=".AddProviderActivity" +            android:label="@string/add_provider" /> + +        <activity              android:name=".ProviderDetailActivity"              android:label="@string/provider_details_title"              android:launchMode="singleTop" /> diff --git a/app/src/main/java/se/leap/bitmaskclient/Constants.java b/app/src/main/java/se/leap/bitmaskclient/Constants.java index 8ec3fcc7..2efc2c1f 100644 --- a/app/src/main/java/se/leap/bitmaskclient/Constants.java +++ b/app/src/main/java/se/leap/bitmaskclient/Constants.java @@ -21,6 +21,7 @@ public interface Constants {      int REQUEST_CODE_CONFIGURE_LEAP = 0;      int REQUEST_CODE_SWITCH_PROVIDER = 1;      int REQUEST_CODE_LOG_IN = 2; +    int REQUEST_CODE_ADD_PROVIDER = 3;      ////////////////////////////////////////////// diff --git a/app/src/main/java/se/leap/bitmaskclient/ProviderListBaseActivity.java b/app/src/main/java/se/leap/bitmaskclient/ProviderListBaseActivity.java index 6a0a1864..0e1ecae9 100644 --- a/app/src/main/java/se/leap/bitmaskclient/ProviderListBaseActivity.java +++ b/app/src/main/java/se/leap/bitmaskclient/ProviderListBaseActivity.java @@ -1,16 +1,16 @@  /**   * Copyright (c) 2017 LEAP Encryption Access Project and contributors - * + * <p>   * 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. - * + * <p>   * 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. - * + * <p>   * You should have received a copy of the GNU General Public License   * along with this program. If not, see <http://www.gnu.org/licenses/>.   */ @@ -33,10 +33,11 @@ import android.widget.ListView;  import com.pedrogomez.renderers.Renderer;  import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable;  import org.json.JSONException;  import org.json.JSONObject; +import java.net.MalformedURLException; +import java.net.URL;  import java.util.ArrayList;  import java.util.List; @@ -50,6 +51,7 @@ import static se.leap.bitmaskclient.Constants.BROADCAST_PROVIDER_API_EVENT;  import static se.leap.bitmaskclient.Constants.BROADCAST_RESULT_CODE;  import static se.leap.bitmaskclient.Constants.BROADCAST_RESULT_KEY;  import static se.leap.bitmaskclient.Constants.PROVIDER_KEY; +import static se.leap.bitmaskclient.Constants.REQUEST_CODE_ADD_PROVIDER;  import static se.leap.bitmaskclient.Constants.REQUEST_CODE_CONFIGURE_LEAP;  import static se.leap.bitmaskclient.ProviderAPI.CORRECTLY_DOWNLOADED_VPN_CERTIFICATE;  import static se.leap.bitmaskclient.ProviderAPI.DOWNLOAD_VPN_CERTIFICATE; @@ -72,7 +74,7 @@ import static se.leap.bitmaskclient.ProviderAPI.UPDATE_PROVIDER_DETAILS;   */  public abstract class ProviderListBaseActivity extends ConfigWizardBaseActivity -        implements NewProviderDialog.NewProviderDialogInterface, ProviderSetupFailedDialog.DownloadFailedDialogInterface, ProviderAPIResultReceiver.Receiver { +        implements ProviderSetupFailedDialog.DownloadFailedDialogInterface, ProviderAPIResultReceiver.Receiver {      @InjectView(R.id.provider_list)      protected ListView providerListView; @@ -80,7 +82,7 @@ public abstract class ProviderListBaseActivity extends ConfigWizardBaseActivity      protected ProviderListAdapter adapter;      private ProviderManager providerManager; -    protected Intent mConfigState = new Intent(PROVIDER_NOT_SET); +    protected Intent configState = new Intent(PROVIDER_NOT_SET);      final public static String TAG = ProviderListActivity.class.getSimpleName(); @@ -88,25 +90,26 @@ public abstract class ProviderListBaseActivity extends ConfigWizardBaseActivity      final protected static String PROVIDER_NOT_SET = "PROVIDER NOT SET";      final protected static String SETTING_UP_PROVIDER = "PROVIDER GETS SET"; -    final private static  String SHOWING_PROVIDER_DETAILS = "SHOWING PROVIDER DETAILS"; +    final private static String SHOWING_PROVIDER_DETAILS = "SHOWING PROVIDER DETAILS";      final private static String PENDING_SHOW_FAILED_DIALOG = "SHOW FAILED DIALOG PENDING";      final private static String SHOW_FAILED_DIALOG = "SHOW FAILED DIALOG";      final private static String REASON_TO_FAIL = "REASON TO FAIL";      final protected static String SERVICES_RETRIEVED = "SERVICES RETRIEVED"; +    final protected static String EXTRAS_KEY_INVALID_URL = "INVALID_URL";      public ProviderAPIResultReceiver providerAPIResultReceiver;      private ProviderAPIBroadcastReceiver providerAPIBroadcastReceiver; -    FragmentManagerEnhanced fragmentManager; +    private FragmentManagerEnhanced fragmentManager;      private boolean isActivityShowing;      private String reasonToFail; +    private boolean testNewURL;      public abstract void retrySetUpProvider(@NonNull Provider provider);      protected abstract void onItemSelectedLogic(); -      private void initProviderList() {          List<Renderer<Provider>> prototypes = new ArrayList<>();          prototypes.add(new ProviderRenderer(this)); @@ -117,7 +120,7 @@ public abstract class ProviderListBaseActivity extends ConfigWizardBaseActivity      @Override      public void onSaveInstanceState(@NotNull Bundle outState) { -        outState.putString(ACTIVITY_STATE, mConfigState.getAction()); +        outState.putString(ACTIVITY_STATE, configState.getAction());          outState.putString(REASON_TO_FAIL, reasonToFail);          super.onSaveInstanceState(outState); @@ -128,7 +131,7 @@ public abstract class ProviderListBaseActivity extends ConfigWizardBaseActivity          if (savedInstanceState == null) {              return;          } -        mConfigState.setAction(savedInstanceState.getString(ACTIVITY_STATE, PROVIDER_NOT_SET)); +        configState.setAction(savedInstanceState.getString(ACTIVITY_STATE, PROVIDER_NOT_SET));          if (savedInstanceState.containsKey(REASON_TO_FAIL)) {              reasonToFail = savedInstanceState.getString(REASON_TO_FAIL);          } @@ -147,19 +150,19 @@ public abstract class ProviderListBaseActivity extends ConfigWizardBaseActivity      @Override      protected void onResume() { -        Log.d(TAG, "resuming with ConfigState: " + mConfigState.getAction()); +        Log.d(TAG, "resuming with ConfigState: " + configState.getAction());          super.onResume();          setUpProviderAPIResultReceiver();          isActivityShowing = true; -        if (SETTING_UP_PROVIDER.equals(mConfigState.getAction())) { +        if (SETTING_UP_PROVIDER.equals(configState.getAction())) {              showProgressBar();              checkProviderSetUp(); -        } else if (PENDING_SHOW_FAILED_DIALOG.equals(mConfigState.getAction())) { +        } else if (PENDING_SHOW_FAILED_DIALOG.equals(configState.getAction())) {              showProgressBar();              showDownloadFailedDialog(); -        } else if (SHOW_FAILED_DIALOG.equals(mConfigState.getAction())) { +        } else if (SHOW_FAILED_DIALOG.equals(configState.getAction())) {              showProgressBar(); -        } else if (SHOWING_PROVIDER_DETAILS.equals(mConfigState.getAction())) { +        } else if (SHOWING_PROVIDER_DETAILS.equals(configState.getAction())) {              cancelSettingUpProvider();          }      } @@ -191,9 +194,31 @@ public abstract class ProviderListBaseActivity extends ConfigWizardBaseActivity                  setResult(resultCode, data);                  finish();              } +        } else if (requestCode == REQUEST_CODE_ADD_PROVIDER) { +            if (resultCode == RESULT_OK) { +                testNewURL = true; +                String newUrl = data.getStringExtra(AddProviderActivity.EXTRAS_KEY_NEW_URL); +                this.provider.setMainUrl(newUrl); +                showAndSelectProvider(newUrl); +            } +        } +    } + +    public void showAndSelectProvider(String newURL) { +        try { +            provider = new Provider(new URL((newURL))); +            autoSelectProvider(); +        } catch (MalformedURLException e) { +            e.printStackTrace();          }      } +    private void autoSelectProvider() { +        onItemSelectedLogic(); +        showProgressBar(); +    } + +      private void setUpProviderAPIResultReceiver() {          providerAPIResultReceiver = new ProviderAPIResultReceiver(new Handler(), this);          providerAPIBroadcastReceiver = new ProviderAPIBroadcastReceiver(); @@ -208,7 +233,7 @@ public abstract class ProviderListBaseActivity extends ConfigWizardBaseActivity          adapter.add(provider);          adapter.saveProviders();          if (provider.allowsAnonymous()) { -            mConfigState.putExtra(SERVICES_RETRIEVED, true); +            configState.putExtra(SERVICES_RETRIEVED, true);              downloadVpnCertificate();          } else {              showProviderDetails(); @@ -216,6 +241,7 @@ public abstract class ProviderListBaseActivity extends ConfigWizardBaseActivity      }      void handleProviderSetupFailed(Bundle resultData) { +          reasonToFail = resultData.getString(ERRORS);          showDownloadFailedDialog();      } @@ -227,7 +253,7 @@ public abstract class ProviderListBaseActivity extends ConfigWizardBaseActivity      void handleIncorrectlyDownloadedCertificate() {          cancelSettingUpProvider(); -        setResult(RESULT_CANCELED, mConfigState); +        setResult(RESULT_CANCELED, configState);      }      @Override @@ -243,8 +269,8 @@ public abstract class ProviderListBaseActivity extends ConfigWizardBaseActivity      @OnItemClick(R.id.provider_list)      void onItemSelected(int position) { -        if (SETTING_UP_PROVIDER.equals(mConfigState.getAction()) || -                SHOW_FAILED_DIALOG.equals(mConfigState.getAction())) { +        if (SETTING_UP_PROVIDER.equals(configState.getAction()) || +                SHOW_FAILED_DIALOG.equals(configState.getAction())) {              return;          } @@ -252,7 +278,7 @@ public abstract class ProviderListBaseActivity extends ConfigWizardBaseActivity          provider = adapter.getItem(position);          if (provider != null && !provider.isDefault()) {              //TODO Code 2 pane view -            mConfigState.setAction(SETTING_UP_PROVIDER); +            configState.setAction(SETTING_UP_PROVIDER);              showProgressBar();              onItemSelectedLogic();          } else { @@ -262,8 +288,8 @@ public abstract class ProviderListBaseActivity extends ConfigWizardBaseActivity      @Override      public void onBackPressed() { -        if (SETTING_UP_PROVIDER.equals(mConfigState.getAction()) || -                SHOW_FAILED_DIALOG.equals(mConfigState.getAction())) { +        if (SETTING_UP_PROVIDER.equals(configState.getAction()) || +                SHOW_FAILED_DIALOG.equals(configState.getAction())) {              stopSettingUpProvider();          } else {              super.onBackPressed(); @@ -276,14 +302,14 @@ public abstract class ProviderListBaseActivity extends ConfigWizardBaseActivity      @Override      public void cancelSettingUpProvider() { -        mConfigState.setAction(PROVIDER_NOT_SET); +        configState.setAction(PROVIDER_NOT_SET);          provider = null;          hideProgressBar();      }      @Override      public void updateProviderDetails() { -        mConfigState.setAction(SETTING_UP_PROVIDER); +        configState.setAction(SETTING_UP_PROVIDER);          ProviderAPICommand.execute(this, UPDATE_PROVIDER_DETAILS, provider);      } @@ -298,28 +324,24 @@ public abstract class ProviderListBaseActivity extends ConfigWizardBaseActivity          ProviderAPICommand.execute(this, DOWNLOAD_VPN_CERTIFICATE, provider);      } +      /**       * Open the new provider dialog       */      public void addAndSelectNewProvider() { -        addAndSelectNewProvider(null); +        Intent intent = new Intent(this, AddProviderActivity.class); +        startActivityForResult(intent, REQUEST_CODE_ADD_PROVIDER);      }      /**       * Open the new provider dialog -     * @param mainUrl - the main url of the provider to add - if null add a new provider       */ -    public void addAndSelectNewProvider(@Nullable  String mainUrl) { -        FragmentTransaction fragmentTransaction = fragmentManager.removePreviousFragment(NewProviderDialog.TAG); - -        DialogFragment newFragment = new NewProviderDialog(); - -        if (mainUrl != null) { -            Bundle data = new Bundle(); -            data.putString(Provider.MAIN_URL, mainUrl); -            newFragment.setArguments(data); -        } -        newFragment.show(fragmentTransaction, NewProviderDialog.TAG); +    @Override +    public void addAndSelectNewProvider(String url) { +        testNewURL = false; +        Intent intent = new Intent(this, AddProviderActivity.class); +        intent.putExtra(EXTRAS_KEY_INVALID_URL, url); +        startActivityForResult(intent, REQUEST_CODE_ADD_PROVIDER);      }      /** @@ -327,12 +349,12 @@ public abstract class ProviderListBaseActivity extends ConfigWizardBaseActivity       */      public void showDownloadFailedDialog() {          try { -            mConfigState.setAction(SHOW_FAILED_DIALOG); +            configState.setAction(SHOW_FAILED_DIALOG);              FragmentTransaction fragmentTransaction = fragmentManager.removePreviousFragment(ProviderSetupFailedDialog.TAG);              DialogFragment newFragment;              try {                  JSONObject errorJson = new JSONObject(reasonToFail); -                newFragment = ProviderSetupFailedDialog.newInstance(provider, errorJson); +                newFragment = ProviderSetupFailedDialog.newInstance(provider, errorJson, testNewURL);              } catch (JSONException e) {                  e.printStackTrace();                  newFragment = ProviderSetupFailedDialog.newInstance(provider, reasonToFail); @@ -343,23 +365,20 @@ public abstract class ProviderListBaseActivity extends ConfigWizardBaseActivity              newFragment.show(fragmentTransaction, ProviderSetupFailedDialog.TAG);          } catch (IllegalStateException e) {              e.printStackTrace(); -            mConfigState.setAction(PENDING_SHOW_FAILED_DIALOG); +            configState.setAction(PENDING_SHOW_FAILED_DIALOG);          } -      }      /**       * 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. -     * -     *       */      public void showProviderDetails() {          // show only if current activity is shown -        if (isActivityShowing && mConfigState.getAction() != null && -                !mConfigState.getAction().equalsIgnoreCase(SHOWING_PROVIDER_DETAILS)) { -            mConfigState.setAction(SHOWING_PROVIDER_DETAILS); +        if (isActivityShowing && configState.getAction() != null && +                !configState.getAction().equalsIgnoreCase(SHOWING_PROVIDER_DETAILS)) { +            configState.setAction(SHOWING_PROVIDER_DETAILS);              Intent intent = new Intent(this, ProviderDetailActivity.class);              intent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);              intent.putExtra(PROVIDER_KEY, provider); @@ -377,8 +396,8 @@ public abstract class ProviderListBaseActivity extends ConfigWizardBaseActivity                  return;              } -            if (mConfigState.getAction() != null && -                    mConfigState.getAction().equalsIgnoreCase(SETTING_UP_PROVIDER)) { +            if (configState.getAction() != null && +                    configState.getAction().equalsIgnoreCase(SETTING_UP_PROVIDER)) {                  int resultCode = intent.getIntExtra(BROADCAST_RESULT_CODE, RESULT_CANCELED);                  Log.d(TAG, "Broadcast resultCode: " + Integer.toString(resultCode)); diff --git a/app/src/main/java/se/leap/bitmaskclient/ProviderSetupFailedDialog.java b/app/src/main/java/se/leap/bitmaskclient/ProviderSetupFailedDialog.java index 5bd9575e..3cfae776 100644 --- a/app/src/main/java/se/leap/bitmaskclient/ProviderSetupFailedDialog.java +++ b/app/src/main/java/se/leap/bitmaskclient/ProviderSetupFailedDialog.java @@ -52,7 +52,8 @@ public class ProviderSetupFailedDialog extends DialogFragment {          DEFAULT,          ERROR_CORRUPTED_PROVIDER_JSON,          ERROR_INVALID_CERTIFICATE, -        ERROR_CERTIFICATE_PINNING +        ERROR_CERTIFICATE_PINNING, +        ERROR_NEW_URL_NO_VPN_PROVIDER      }      /** @@ -68,7 +69,7 @@ public class ProviderSetupFailedDialog extends DialogFragment {      /**       * @return a new instance of this DialogFragment.       */ -    public static DialogFragment newInstance(Provider provider, JSONObject errorJson) { +    public static DialogFragment newInstance(Provider provider, JSONObject errorJson, boolean testNewURL) {          ProviderSetupFailedDialog dialogFragment = new ProviderSetupFailedDialog();          dialogFragment.provider = provider;          try { @@ -81,6 +82,8 @@ public class ProviderSetupFailedDialog extends DialogFragment {              if (errorJson.has(ERRORID)) {                  dialogFragment.downloadError = valueOf(errorJson.getString(ERRORID)); +            } else if (testNewURL) { +                dialogFragment.downloadError = DOWNLOAD_ERRORS.ERROR_NEW_URL_NO_VPN_PROVIDER;              }          } catch (Exception e) {              e.printStackTrace(); @@ -123,6 +126,13 @@ public class ProviderSetupFailedDialog extends DialogFragment {                      }                  });                  break; +            case ERROR_NEW_URL_NO_VPN_PROVIDER: +                builder.setPositiveButton(R.string.retry, new DialogInterface.OnClickListener() { +                    public void onClick(DialogInterface dialog, int id) { +                        interfaceWithConfigurationWizard.addAndSelectNewProvider(provider.getMainUrlString()); +                    } +                }); +                break;              default:                  builder.setPositiveButton(R.string.retry, new DialogInterface.OnClickListener() {                              public void onClick(DialogInterface dialog, int id) { @@ -142,6 +152,8 @@ public class ProviderSetupFailedDialog extends DialogFragment {          void cancelSettingUpProvider();          void updateProviderDetails(); + +        void addAndSelectNewProvider(String url);      }      DownloadFailedDialogInterface interfaceWithConfigurationWizard; diff --git a/app/src/main/res/layout/a_add_provider.xml b/app/src/main/res/layout/a_add_provider.xml new file mode 100644 index 00000000..fd515bf3 --- /dev/null +++ b/app/src/main/res/layout/a_add_provider.xml @@ -0,0 +1,74 @@ +<?xml version="1.0" encoding="utf-8"?> +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" +    xmlns:app="http://schemas.android.com/apk/res-auto" +    xmlns:tools="http://schemas.android.com/tools" +    style="@style/BitmaskActivity" +    android:layout_width="match_parent" +    android:layout_height="match_parent" +    android:padding="@dimen/stdpadding" +    tools:context=".AddProviderActivity"> + +    <!--Contains header information!??? --> +    <include layout="@layout/v_add_provider" /> + +    <LinearLayout +        android:id="@+id/content" +        android:layout_width="match_parent" +        android:layout_height="match_parent" +        android:layout_alignParentEnd="true" +        android:layout_alignParentRight="true" +        android:layout_alignParentTop="true" +        android:orientation="vertical"> + +        <!-- the header contains the mask--> +        <include layout="@layout/v_provider_header" /> + +        <android.support.design.widget.TextInputLayout +            android:id="@+id/text_uri_error" +            android:layout_width="match_parent" +            android:layout_height="wrap_content" +            android:layout_marginTop="@dimen/activity_vertical_margin" +            android:hint="@string/new_provider_uri" +            app:errorEnabled="true"> + +            <android.support.design.widget.TextInputEditText +                android:id="@+id/text_uri" +                android:layout_width="match_parent" +                android:layout_height="wrap_content" +                android:ems="10" +                android:inputType="text" /> + +        </android.support.design.widget.TextInputLayout> + + +        <CheckBox +            android:id="@+id/danger_checkbox" +            android:layout_width="wrap_content" +            android:layout_height="wrap_content" +            android:visibility="gone" +            android:layout_marginBottom="@dimen/add_button_margin"/> + +        <LinearLayout +            android:layout_width="match_parent" +            android:layout_height="match_parent" +            android:gravity="right" +            android:orientation="horizontal"> + +            <Button +                android:id="@+id/button_cancel" +                android:layout_width="wrap_content" +                android:layout_height="wrap_content" +                android:text="@string/cancel" /> + +            <Button +                android:id="@+id/button_save" +                android:layout_width="wrap_content" +                android:layout_height="wrap_content" +                android:layout_marginLeft="@dimen/activity_horizontal_margin" +                android:layout_marginStart="@dimen/activity_horizontal_margin" +                android:text="@string/save" /> + +        </LinearLayout> +    </LinearLayout> + +</RelativeLayout> diff --git a/app/src/main/res/layout/v_add_provider.xml b/app/src/main/res/layout/v_add_provider.xml new file mode 100644 index 00000000..44146fb5 --- /dev/null +++ b/app/src/main/res/layout/v_add_provider.xml @@ -0,0 +1,41 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" +    xmlns:app="http://schemas.android.com/apk/res-auto" +    android:id="@+id/loading_screen" +    android:layout_width="match_parent" +    android:layout_height="match_parent" +    android:orientation="vertical" +    android:visibility="gone"> + +    <android.support.v7.widget.AppCompatImageView +        android:layout_width="wrap_content" +        android:layout_height="wrap_content" +        android:adjustViewBounds="true" +        app:tint="@color/colorPrimary" +        app:srcCompat="@drawable/action_history" +        android:layout_marginTop="@dimen/loading_screen_icon_vertical_margin" +        android:layout_marginBottom="@dimen/loading_screen_icon_vertical_margin" +        /> + +    <android.support.v7.widget.AppCompatTextView +        android:id="@+id/progressbar_description" +        android:layout_width="wrap_content" +        android:layout_height="wrap_content" +        android:fadingEdge="horizontal" +        android:singleLine="true" +        android:text="@string/introduce_new_provider" +        android:textAppearance="@style/Base.TextAppearance.AppCompat.Medium" +        android:layout_marginTop="@dimen/standard_margin" +        android:layout_marginBottom="@dimen/standard_margin" +        /> + +    <ProgressBar +        android:id="@+id/progressbar" +        style="@style/Widget.AppCompat.ProgressBar.Horizontal" +        android:layout_width="fill_parent" +        android:layout_height="wrap_content" +        android:indeterminate="true" +        android:layout_marginTop="@dimen/standard_margin" +        /> + +</LinearLayout>
\ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 3aa00124..968ac2e0 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -113,6 +113,7 @@    <string name="always_on_vpn">Always-on VPN</string>    <string name="do_not_show_again">Do not show again.</string>    <string name="always_on_vpn_user_message">To enable always-on VPN in Android VPN Settings click on the configure icon [img src] and turn the switch on."</string> +  <string name="title_activity_provider_add">ProviderAddActivity</string>    <string name="donate_title">Donate</string>    <string name="donate_default_message">Please donate today if you value secure communication that is easy for both the end-user and the service provider.</string>    <string name="donate_message">LEAP depends on donations and grants. Please donate today if you value secure communication that is easy for both the end-user and the service provider.</string> diff --git a/app/src/production/java/se/leap/bitmaskclient/AddProviderActivity.java b/app/src/production/java/se/leap/bitmaskclient/AddProviderActivity.java new file mode 100644 index 00000000..13e4e06d --- /dev/null +++ b/app/src/production/java/se/leap/bitmaskclient/AddProviderActivity.java @@ -0,0 +1,113 @@ +package se.leap.bitmaskclient; + +import android.content.Intent; +import android.os.Bundle; +import android.support.design.widget.TextInputEditText; +import android.support.design.widget.TextInputLayout; +import android.text.Editable; +import android.text.TextWatcher; +import android.view.View; +import android.widget.Button; + +import butterknife.InjectView; + +public class AddProviderActivity extends ConfigWizardBaseActivity { + +    final public static String TAG = "AddProviderActivity"; +    final public static String EXTRAS_KEY_NEW_URL = "NEW_URL"; + +    @InjectView(R.id.text_uri_error) +    TextInputLayout urlError; + +    @InjectView(R.id.text_uri) +    TextInputEditText editUrl; + +    @Override +    protected void onCreate(Bundle savedInstanceState) { +        super.onCreate(savedInstanceState); + +        setContentView(R.layout.a_add_provider); +        if (this.getIntent().getExtras() != null) { +            editUrl.setText(this.getIntent().getExtras().getString(ProviderListBaseActivity.EXTRAS_KEY_INVALID_URL)); +        } +        final Button saveButton = findViewById(R.id.button_save); +        saveButton.setOnClickListener(new View.OnClickListener() { +            public void onClick(View v) { +                saveProvider(); +            } +        }); + +        final Button cancelButton = findViewById(R.id.button_cancel); +        cancelButton.setOnClickListener(new View.OnClickListener() { +            public void onClick(View v) { +                finish(); +            } +        }); +        setUpListeners(); +        setUpInitialUI(); +    } + +    private void setUpInitialUI() { +        setProviderHeaderText(R.string.add_provider); +        hideProgressBar(); +    } + +    private void saveProvider() { +        String entered_url = getURL(); +        if (validURL(entered_url)) { +            Intent intent = this.getIntent(); +            intent.putExtra(EXTRAS_KEY_NEW_URL, entered_url); +            setResult(RESULT_OK, intent); +            finish(); +        } else { +            editUrl.setText(""); +            urlError.setError(getString(R.string.not_valid_url_entered)); +        } +    } + +    private void setUpListeners() { + +        editUrl.addTextChangedListener(new TextWatcher() { +            @Override +            public void beforeTextChanged(CharSequence s, int start, int count, int after) { +            } + +            @Override +            public void onTextChanged(CharSequence s, int start, int before, int count) { +            } + +            @Override +            public void afterTextChanged(Editable s) { +                if (!validURL(getURL())) { +                    urlError.setError(getString(R.string.not_valid_url_entered)); +                } else { +                    urlError.setError(null); +                } +            } +        }); +    } + +    private String getURL() { +        String entered_url = editUrl.getText().toString().trim(); +        if (entered_url.contains("www.")) entered_url = entered_url.replaceFirst("www.", ""); +        if (!entered_url.startsWith("https://")) { +            if (entered_url.startsWith("http://")) { +                entered_url = entered_url.substring("http://".length()); +            } +            entered_url = "https://".concat(entered_url); +        } +        return entered_url; +    } + +    /** +     * Checks if the entered url is valid or not. +     * +     * @param enteredUrl +     * @return true if it's not empty nor contains only the protocol. +     */ +    boolean validURL(String enteredUrl) { +        return android.util.Patterns.WEB_URL.matcher(enteredUrl).matches(); +    } + + +} diff --git a/app/src/production/java/se/leap/bitmaskclient/NewProviderDialog.java b/app/src/production/java/se/leap/bitmaskclient/NewProviderDialog.java deleted file mode 100644 index cce49d9b..00000000 --- a/app/src/production/java/se/leap/bitmaskclient/NewProviderDialog.java +++ /dev/null @@ -1,119 +0,0 @@ -/** - * 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.AlertDialog; -import android.app.Dialog; -import android.content.Context; -import android.content.DialogInterface; -import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.v4.app.DialogFragment; -import android.view.LayoutInflater; -import android.view.View; -import android.widget.EditText; -import android.widget.Toast; - -import butterknife.ButterKnife; -import butterknife.InjectView; - -/** - * Implements the new custom provider dialog. - * - * @author parmegv - */ -public class NewProviderDialog extends DialogFragment { - -    final public static String TAG = "newProviderDialog"; - -    @InjectView(R.id.new_provider_url) -    EditText urlInputField; - -    public interface NewProviderDialogInterface { -        void showAndSelectProvider(String url_provider); -    } - -    NewProviderDialogInterface interfaceWithConfigurationWizard; - -    @Override -    public void onAttach(Context context) { -        super.onAttach(context); -        try { -            interfaceWithConfigurationWizard = (NewProviderDialogInterface) context; -        } catch (ClassCastException e) { -            throw new ClassCastException(context.toString() -                    + " must implement NoticeDialogListener"); -        } -    } - -    @Override -    @NonNull -    public Dialog onCreateDialog(Bundle savedInstanceState) { -        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); -        LayoutInflater inflater = getActivity().getLayoutInflater(); -        View view = inflater.inflate(R.layout.d_new_provider, null); -        ButterKnife.inject(this, view); -        Bundle arguments = getArguments(); -        if (arguments != null) { -            urlInputField.setText(arguments.getString(Provider.MAIN_URL, "")); -        } - -        builder.setView(view) -                .setMessage(R.string.introduce_new_provider) -                .setPositiveButton(R.string.save, new DialogInterface.OnClickListener() { -                    public void onClick(DialogInterface dialog, int id) { -                        saveProvider(); -                    } -                }) -                .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { -                    public void onClick(DialogInterface dialog, int id) { -                        dialog.cancel(); -                    } -                }); -        // Create the AlertDialog object and return it -        return builder.create(); -    } - -    private void saveProvider() { -        String entered_url = urlInputField.getText().toString().trim(); -        if (!entered_url.startsWith("https://")) { -            if (entered_url.startsWith("http://")) { -                entered_url = entered_url.substring("http://".length()); -            } -            entered_url = "https://".concat(entered_url); -        } - -        if (validURL(entered_url)) { -            interfaceWithConfigurationWizard.showAndSelectProvider(entered_url); -            Toast.makeText(getActivity().getApplicationContext(), R.string.valid_url_entered, Toast.LENGTH_LONG).show(); -        } else { -            urlInputField.setText(""); -            Toast.makeText(getActivity().getApplicationContext(), R.string.not_valid_url_entered, Toast.LENGTH_LONG).show(); -        } -    } - -    /** -     * Checks if the entered url is valid or not. -     * -     * @param enteredUrl -     * @return true if it's not empty nor contains only the protocol. -     */ -    boolean validURL(String enteredUrl) { -        //return !enteredUrl.isEmpty() && enteredUrl.matches("http[s]?://.+") && !enteredUrl.replaceFirst("http[s]?://", "").isEmpty(); -        return android.util.Patterns.WEB_URL.matcher(enteredUrl).matches(); -    } -} diff --git a/app/src/production/java/se/leap/bitmaskclient/ProviderListActivity.java b/app/src/production/java/se/leap/bitmaskclient/ProviderListActivity.java index cf1d1aa6..172c9e61 100644 --- a/app/src/production/java/se/leap/bitmaskclient/ProviderListActivity.java +++ b/app/src/production/java/se/leap/bitmaskclient/ProviderListActivity.java @@ -39,34 +39,18 @@ public class ProviderListActivity extends ProviderListBaseActivity {          setUpProvider();      } -    @Override -    public void showAndSelectProvider(String provider_main_url) { -        try { -            provider = new Provider(new URL((provider_main_url))); -            autoSelectProvider(provider); -        } catch (MalformedURLException e) { -            e.printStackTrace(); -        } -    } - -    private void autoSelectProvider(Provider provider) { -        this.provider = provider; -        onItemSelectedLogic(); -        showProgressBar(); -    } -      /**       * Asks ProviderAPI to download a new provider.json file       *       */      public void setUpProvider() { -        mConfigState.setAction(SETTING_UP_PROVIDER); +        configState.setAction(SETTING_UP_PROVIDER);          ProviderAPICommand.execute(this, SET_UP_PROVIDER, provider);      }      @Override      public void retrySetUpProvider(@NonNull Provider provider) { -        mConfigState.setAction(SETTING_UP_PROVIDER); +        configState.setAction(SETTING_UP_PROVIDER);          ProviderAPICommand.execute(this, SET_UP_PROVIDER, provider);      } | 
