From f20745dcf2ab15bbfa81756602779b0186602584 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Fri, 31 Aug 2018 14:40:39 +0200 Subject: #8896 skip onboarding for custom branded apps, allow to specify if anonymous usage is preferred over login/signup --- app/build.gradle | 29 ++- app/src/main/AndroidManifest.xml | 10 +- .../bitmaskclient/ConfigWizardBaseActivity.java | 16 +- .../main/java/se/leap/bitmaskclient/Constants.java | 2 + .../bitmaskclient/CustomProviderSetupActivity.java | 115 +++++++++- .../java/se/leap/bitmaskclient/EipFragment.java | 23 +- .../java/se/leap/bitmaskclient/MainActivity.java | 1 + .../leap/bitmaskclient/ProviderApiManagerBase.java | 1 + .../bitmaskclient/ProviderListBaseActivity.java | 199 ++--------------- .../bitmaskclient/ProviderSetupBaseActivity.java | 235 +++++++++++++++++++++ .../bitmaskclient/ProviderSetupFailedDialog.java | 2 +- .../java/se/leap/bitmaskclient/StartActivity.java | 8 +- .../leap/bitmaskclient/TLSCompatSocketFactory.java | 2 +- .../drawer/NavigationDrawerFragment.java | 12 +- .../se/leap/bitmaskclient/utils/ConfigHelper.java | 10 + .../main/res/layout/a_custom_provider_setup.xml | 30 +++ 16 files changed, 487 insertions(+), 208 deletions(-) create mode 100644 app/src/main/java/se/leap/bitmaskclient/ProviderSetupBaseActivity.java create mode 100644 app/src/main/res/layout/a_custom_provider_setup.xml (limited to 'app') diff --git a/app/build.gradle b/app/build.gradle index 75fe40b5..b7522e07 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -11,10 +11,13 @@ android { defaultConfig { applicationId "se.leap.bitmaskclient" + versionCode 134 + versionName "0.9.8" resValue "string", "app_name", appName vectorDrawables.useSupportLibrary = true buildConfigField 'boolean', 'openvpn3', 'false' + //Build Config Fields for default donation details //This is the default donation URL and should be set to the donation page of LEAP @@ -28,6 +31,11 @@ android { buildConfigField 'boolean', 'enable_donation_reminder', 'true' //The duration in days to trigger the donation reminder buildConfigField 'int', 'donation_reminder_duration', '30' + //skip the account creation / login screen if the provider offers anonymous vpn usage, use directly the anonymous cert instead + buildConfigField 'boolean', 'priotize_anonymous_usage', 'false' + //ignore the following config, only used in custom flavor + buildConfigField "String", "customProviderUrl", '""' + testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" dexOptions { jumboMode true @@ -57,21 +65,29 @@ android { } - //************************************************************************** - //************************************************************************** - //Configurations for custom branded app. custom { dimension "branding" + + //************************************************************************** + //************************************************************************** + //Configurations for custom branded app. + //Change the package name as needed applicationId "net.riseup.black" //Set app name here appName = "Riseup VPN" resValue "string", "app_name", appName + //Provider base url, e.g. '"https://example.com"' + def customProviderUrl = '"https://riseup.net"' + buildConfigField "String", "customProviderUrl", customProviderUrl //Change the versionCode as needed versionCode 1 //Change the versionName as needed versionName "1.0" + //skip the account creation / login screen if the provider offers anonymous vpn usage, use directly the anonymous cert instead + buildConfigField 'boolean', 'priotize_anonymous_usage', 'true' + //Build Config Fields for default donation details //This is the donation URL and should be set to the relevant donation page. @@ -82,10 +98,11 @@ android { buildConfigField 'boolean', 'enable_donation_reminder', 'true' //The duration in days to trigger the donation reminder buildConfigField 'int', 'donation_reminder_duration', '30' - } - //************************************************************************** - //************************************************************************** + //************************************************************************** + //************************************************************************** + + } } buildTypes { diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index b1131850..66f36256 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -15,10 +15,8 @@ limitations under the License. --> - + package="se.leap.bitmaskclient"> + @@ -93,6 +91,10 @@ android:name=".ProviderListActivity" android:label="@string/configuration_wizard_title" /> + + diff --git a/app/src/main/java/se/leap/bitmaskclient/ConfigWizardBaseActivity.java b/app/src/main/java/se/leap/bitmaskclient/ConfigWizardBaseActivity.java index 227c8cf4..7aa50add 100644 --- a/app/src/main/java/se/leap/bitmaskclient/ConfigWizardBaseActivity.java +++ b/app/src/main/java/se/leap/bitmaskclient/ConfigWizardBaseActivity.java @@ -12,7 +12,6 @@ import android.support.constraint.ConstraintLayout; import android.support.constraint.Guideline; import android.support.v4.content.ContextCompat; import android.support.v7.widget.AppCompatTextView; -import android.util.Log; import android.view.View; import android.view.ViewGroup; import android.view.ViewTreeObserver; @@ -72,6 +71,8 @@ public abstract class ConfigWizardBaseActivity extends ButterKnifeActivity { protected Provider provider; protected boolean isCompactLayout = false; + protected boolean isActivityShowing; + private float defaultGuidelineTopPercentage; private float defaultGuidelineBottomPercentage; @@ -79,7 +80,6 @@ public abstract class ConfigWizardBaseActivity extends ButterKnifeActivity { protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); preferences = getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE); - provider = getIntent().getParcelableExtra(PROVIDER_KEY); } @@ -135,6 +135,18 @@ public abstract class ConfigWizardBaseActivity extends ButterKnifeActivity { } } + @Override + protected void onPause() { + super.onPause(); + isActivityShowing = false; + } + + @Override + protected void onResume() { + super.onResume(); + isActivityShowing = true; + } + protected void restoreState(Bundle savedInstanceState) { if (savedInstanceState != null && savedInstanceState.containsKey(PROVIDER_KEY)) { provider = savedInstanceState.getParcelable(PROVIDER_KEY); diff --git a/app/src/main/java/se/leap/bitmaskclient/Constants.java b/app/src/main/java/se/leap/bitmaskclient/Constants.java index 2efc2c1f..15bec955 100644 --- a/app/src/main/java/se/leap/bitmaskclient/Constants.java +++ b/app/src/main/java/se/leap/bitmaskclient/Constants.java @@ -30,6 +30,8 @@ public interface Constants { String APP_ACTION_QUIT = "quit"; String APP_ACTION_CONFIGURE_ALWAYS_ON_PROFILE = "configure always-on profile"; + String DEFAULT_BITMASK = "normal"; + String CUSTOM_BITMASK = "custom"; ////////////////////////////////////////////// diff --git a/app/src/main/java/se/leap/bitmaskclient/CustomProviderSetupActivity.java b/app/src/main/java/se/leap/bitmaskclient/CustomProviderSetupActivity.java index 3d4f801b..3763f506 100644 --- a/app/src/main/java/se/leap/bitmaskclient/CustomProviderSetupActivity.java +++ b/app/src/main/java/se/leap/bitmaskclient/CustomProviderSetupActivity.java @@ -1,8 +1,121 @@ +/** + * Copyright (c) 2018 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 . + */ package se.leap.bitmaskclient; +import android.content.Intent; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; + +import static se.leap.bitmaskclient.Constants.REQUEST_CODE_CONFIGURE_LEAP; +import static se.leap.bitmaskclient.ProviderAPI.SET_UP_PROVIDER; +import static se.leap.bitmaskclient.ProviderSetupInterface.ProviderConfigState.SETTING_UP_PROVIDER; +import static se.leap.bitmaskclient.utils.ConfigHelper.preferAnonymousUsage; + /** * Created by cyberta on 17.08.18. */ -public class CustomProviderSetupActivity { +public class CustomProviderSetupActivity extends ProviderSetupBaseActivity { + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setUpInitialUI(); + restoreState(savedInstanceState); + setProvider(new Provider(BuildConfig.customProviderUrl)); + } + + @Override + protected void onResume() { + super.onResume(); + if (getConfigState() == ProviderConfigState.PROVIDER_NOT_SET) { + showProgressBar(); + setupProvider(); + } + } + + private void setUpInitialUI() { + setContentView(R.layout.a_custom_provider_setup); + setProviderHeaderText(R.string.setup_provider); + hideProgressBar(); + } + + private void setupProvider() { + setProviderConfigState(SETTING_UP_PROVIDER); + ProviderAPICommand.execute(this, SET_UP_PROVIDER, getProvider()); + } + + // ------- ProviderSetupInterface ---v + @Override + public void handleProviderSetUp(Provider provider) { + setProvider(provider); + if (provider.allowsAnonymous()) { + downloadVpnCertificate(); + } else { + showProviderDetails(); + } + } + + @Override + public void handleCorrectlyDownloadedCertificate(Provider provider) { + if (preferAnonymousUsage()) { + finishWithSetupWithProvider(provider); + } else { + this.provider = provider; + showProviderDetails(); + } + } + + // ------- DownloadFailedDialogInterface ---v + @Override + public void retrySetUpProvider(@NonNull Provider provider) { + setupProvider(); + showProgressBar(); + } + + @Override + public void cancelSettingUpProvider() { + super.cancelSettingUpProvider(); + finish(); + } + + @Override + public void addAndSelectNewProvider(String url) { + // ignore + } + + private void finishWithSetupWithProvider(Provider provider) { + Intent intent = new Intent(); + intent.putExtra(Provider.KEY, provider); + setResult(RESULT_OK, intent); + finish(); + } + + @Override + public void onReceiveResult(int resultCode, Bundle resultData) { + + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + if (requestCode == REQUEST_CODE_CONFIGURE_LEAP) { + setResult(resultCode, data); + finish(); + } + } } diff --git a/app/src/main/java/se/leap/bitmaskclient/EipFragment.java b/app/src/main/java/se/leap/bitmaskclient/EipFragment.java index a168059f..fb4f16c7 100644 --- a/app/src/main/java/se/leap/bitmaskclient/EipFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/EipFragment.java @@ -58,14 +58,17 @@ import se.leap.bitmaskclient.views.VpnStateImage; import static android.view.View.GONE; import static android.view.View.VISIBLE; import static de.blinkt.openvpn.core.ConnectionStatus.LEVEL_NONETWORK; +import static se.leap.bitmaskclient.Constants.DEFAULT_BITMASK; import static se.leap.bitmaskclient.Constants.EIP_RESTART_ON_BOOT; import static se.leap.bitmaskclient.Constants.PROVIDER_KEY; +import static se.leap.bitmaskclient.Constants.REQUEST_CODE_CONFIGURE_LEAP; import static se.leap.bitmaskclient.Constants.REQUEST_CODE_LOG_IN; import static se.leap.bitmaskclient.Constants.REQUEST_CODE_SWITCH_PROVIDER; import static se.leap.bitmaskclient.Constants.SHARED_PREFERENCES; import static se.leap.bitmaskclient.ProviderAPI.UPDATE_INVALID_VPN_CERTIFICATE; import static se.leap.bitmaskclient.ProviderAPI.USER_MESSAGE; import static se.leap.bitmaskclient.R.string.vpn_certificate_user_message; +import static se.leap.bitmaskclient.utils.ConfigHelper.isDefaultBitmask; public class EipFragment extends Fragment implements Observer { @@ -113,18 +116,30 @@ public class EipFragment extends Fragment implements Observer { if (arguments != null) { provider = arguments.getParcelable(PROVIDER_KEY); if (provider == null) { - activity.startActivityForResult(new Intent(activity, ProviderListActivity.class), REQUEST_CODE_SWITCH_PROVIDER); + handleNoProvider(activity); } else { Log.d(TAG, provider.getName() + " configured as provider"); } } else { - Log.e(TAG, "no provider given - starting ProviderListActivity"); - activity.startActivityForResult(new Intent(activity, ProviderListActivity.class), REQUEST_CODE_SWITCH_PROVIDER); + handleNoProvider(activity); } } } - @Override + private void handleNoProvider(Activity activity) { + if (isDefaultBitmask()) { + activity.startActivityForResult(new Intent(activity, ProviderListActivity.class), REQUEST_CODE_SWITCH_PROVIDER); + } else { + Log.e(TAG, "no provider given - try to reconfigure custom provider"); + startActivityForResult(new Intent(activity, CustomProviderSetupActivity.class), REQUEST_CODE_CONFIGURE_LEAP); + + } + + } + + + + @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); openVpnConnection = new EipFragmentServiceConnection(); diff --git a/app/src/main/java/se/leap/bitmaskclient/MainActivity.java b/app/src/main/java/se/leap/bitmaskclient/MainActivity.java index c44e8a3e..84c7c16a 100644 --- a/app/src/main/java/se/leap/bitmaskclient/MainActivity.java +++ b/app/src/main/java/se/leap/bitmaskclient/MainActivity.java @@ -190,6 +190,7 @@ public class MainActivity extends AppCompatActivity { EipCommand.stopVPN(this); break; case REQUEST_CODE_CONFIGURE_LEAP: + Log.d(TAG, "REQUEST_CODE_CONFIGURE_LEAP - onActivityResult - MainActivity"); break; case REQUEST_CODE_LOG_IN: EipCommand.startVPN(this, true); diff --git a/app/src/main/java/se/leap/bitmaskclient/ProviderApiManagerBase.java b/app/src/main/java/se/leap/bitmaskclient/ProviderApiManagerBase.java index 8f3acf1d..113b07f5 100644 --- a/app/src/main/java/se/leap/bitmaskclient/ProviderApiManagerBase.java +++ b/app/src/main/java/se/leap/bitmaskclient/ProviderApiManagerBase.java @@ -145,6 +145,7 @@ public abstract class ProviderApiManagerBase { Provider provider = command.getParcelableExtra(PROVIDER_KEY); if (provider == null) { + //TODO: consider returning error back e.g. NO_PROVIDER Log.e(TAG, action +" called without provider!"); return; } diff --git a/app/src/main/java/se/leap/bitmaskclient/ProviderListBaseActivity.java b/app/src/main/java/se/leap/bitmaskclient/ProviderListBaseActivity.java index c786a6fa..a29d4b61 100644 --- a/app/src/main/java/se/leap/bitmaskclient/ProviderListBaseActivity.java +++ b/app/src/main/java/se/leap/bitmaskclient/ProviderListBaseActivity.java @@ -49,7 +49,6 @@ import static se.leap.bitmaskclient.Constants.BROADCAST_PROVIDER_API_EVENT; 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.DOWNLOAD_VPN_CERTIFICATE; import static se.leap.bitmaskclient.ProviderAPI.ERRORS; import static se.leap.bitmaskclient.ProviderAPI.PROVIDER_SET_UP; import static se.leap.bitmaskclient.ProviderAPI.UPDATE_PROVIDER_DETAILS; @@ -70,32 +69,24 @@ import static se.leap.bitmaskclient.ProviderSetupInterface.ProviderConfigState.S * @author cyberta */ -public abstract class ProviderListBaseActivity extends ConfigWizardBaseActivity - implements ProviderSetupInterface, ProviderSetupFailedDialog.DownloadFailedDialogInterface, ProviderAPIResultReceiver.Receiver { +public abstract class ProviderListBaseActivity extends ProviderSetupBaseActivity { @InjectView(R.id.provider_list) protected ListView providerListView; @Inject protected ProviderListAdapter adapter; - private ProviderManager providerManager; - final public static String TAG = ProviderListActivity.class.getSimpleName(); - - final private static String ACTIVITY_STATE = "ACTIVITY STATE"; - - protected ProviderConfigState providerConfigState = PROVIDER_NOT_SET; - final private static String REASON_TO_FAIL = "REASON TO FAIL"; final protected static String EXTRAS_KEY_INVALID_URL = "INVALID_URL"; - public ProviderAPIResultReceiver providerAPIResultReceiver; - private ProviderApiSetupBroadcastReceiver providerAPIBroadcastReceiver; - private FragmentManagerEnhanced fragmentManager; - - private boolean isActivityShowing; - private String reasonToFail; - private boolean testNewURL; + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setUpInitialUI(); + initProviderList(); + restoreState(savedInstanceState); + } public abstract void retrySetUpProvider(@NonNull Provider provider); @@ -105,80 +96,16 @@ public abstract class ProviderListBaseActivity extends ConfigWizardBaseActivity List> prototypes = new ArrayList<>(); prototypes.add(new ProviderRenderer(this)); ProviderRendererBuilder providerRendererBuilder = new ProviderRendererBuilder(prototypes); - adapter = new ProviderListAdapter(getLayoutInflater(), providerRendererBuilder, providerManager); + adapter = new ProviderListAdapter(getLayoutInflater(), providerRendererBuilder, getProviderManager()); providerListView.setAdapter(adapter); } - @Override - public void onSaveInstanceState(@NotNull Bundle outState) { - outState.putString(ACTIVITY_STATE, providerConfigState.toString()); - outState.putString(REASON_TO_FAIL, reasonToFail); - - super.onSaveInstanceState(outState); - } - - protected void restoreState(Bundle savedInstanceState) { - super.restoreState(savedInstanceState); - if (savedInstanceState == null) { - return; - } - this.providerConfigState = ProviderConfigState.valueOf(savedInstanceState.getString(ACTIVITY_STATE, PROVIDER_NOT_SET.toString())); - if (savedInstanceState.containsKey(REASON_TO_FAIL)) { - reasonToFail = savedInstanceState.getString(REASON_TO_FAIL); - } - } - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - fragmentManager = new FragmentManagerEnhanced(getSupportFragmentManager()); - providerManager = ProviderManager.getInstance(getAssets(), getExternalFilesDir(null)); - - setUpInitialUI(); - initProviderList(); - restoreState(savedInstanceState); - } - - @Override - protected void onResume() { - Log.d(TAG, "resuming with ConfigState: " + providerConfigState.toString()); - super.onResume(); - setUpProviderAPIResultReceiver(); - isActivityShowing = true; - if (SETTING_UP_PROVIDER == providerConfigState) { - showProgressBar(); - checkProviderSetUp(); - } else if (PENDING_SHOW_FAILED_DIALOG == providerConfigState) { - showProgressBar(); - showDownloadFailedDialog(); - } else if (SHOW_FAILED_DIALOG == providerConfigState) { - showProgressBar(); - } else if (SHOWING_PROVIDER_DETAILS == providerConfigState) { - cancelSettingUpProvider(); - } - } - private void setUpInitialUI() { setContentView(R.layout.a_provider_list); setProviderHeaderText(R.string.setup_provider); hideProgressBar(); } - @Override - protected void onPause() { - super.onPause(); - isActivityShowing = false; - if (providerAPIBroadcastReceiver != null) - LocalBroadcastManager.getInstance(this).unregisterReceiver(providerAPIBroadcastReceiver); - } - - @Override - protected void onDestroy() { - super.onDestroy(); - providerAPIResultReceiver = null; - } - @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == REQUEST_CODE_CONFIGURE_LEAP) { @@ -212,16 +139,7 @@ public abstract class ProviderListBaseActivity extends ConfigWizardBaseActivity showProgressBar(); } - - private void setUpProviderAPIResultReceiver() { - providerAPIResultReceiver = new ProviderAPIResultReceiver(new Handler(), this); - providerAPIBroadcastReceiver = new ProviderApiSetupBroadcastReceiver(this); - - IntentFilter updateIntentFilter = new IntentFilter(BROADCAST_PROVIDER_API_EVENT); - updateIntentFilter.addCategory(Intent.CATEGORY_DEFAULT); - LocalBroadcastManager.getInstance(this).registerReceiver(providerAPIBroadcastReceiver, updateIntentFilter); - } - + // ------- ProviderSetupInterface ---v @Override public void handleProviderSetUp(Provider handledProvider) { this.provider = handledProvider; @@ -235,40 +153,21 @@ public abstract class ProviderListBaseActivity extends ConfigWizardBaseActivity } } - @Override - public void handleProviderSetupFailed(Bundle resultData) { - reasonToFail = resultData.getString(ERRORS); - showDownloadFailedDialog(); - } - @Override public void handleCorrectlyDownloadedCertificate(Provider handledProvider) { this.provider = handledProvider; showProviderDetails(); } + // ----------------------------------------- - @Override - public void handleIncorrectlyDownloadedCertificate() { - cancelSettingUpProvider(); - setResult(RESULT_CANCELED, new Intent(getConfigState().toString())); - } - - public Provider getProvider() { - return provider; - } - - public ProviderConfigState getConfigState() { - return providerConfigState; - } - + //TODO: only keep empty method for testing purposes @Override public void onReceiveResult(int resultCode, Bundle resultData) { - if (resultCode == ProviderAPI.PROVIDER_OK) { - Provider provider = resultData.getParcelable(PROVIDER_KEY); - handleProviderSetUp(provider); - } else if (resultCode == AboutFragment.VIEWED) { + super.onReceiveResult(resultCode, resultData); + if (resultCode == AboutFragment.VIEWED) { // Do nothing, right now // I need this for CW to wait for the About activity to end before going back to Dashboard. + //FIXME: WEEEIRD! } } @@ -301,31 +200,6 @@ public abstract class ProviderListBaseActivity extends ConfigWizardBaseActivity } } - @Override - public void cancelSettingUpProvider() { - providerConfigState = PROVIDER_NOT_SET; - provider = null; - hideProgressBar(); - } - - @Override - public void updateProviderDetails() { - providerConfigState = SETTING_UP_PROVIDER; - ProviderAPICommand.execute(this, UPDATE_PROVIDER_DETAILS, provider); - } - - public void checkProviderSetUp() { - ProviderAPICommand.execute(this, PROVIDER_SET_UP, provider, providerAPIResultReceiver); - } - - /** - * Asks ProviderApiService to download an anonymous (anon) VPN certificate. - */ - private void downloadVpnCertificate() { - ProviderAPICommand.execute(this, DOWNLOAD_VPN_CERTIFICATE, provider); - } - - /** * Open the new provider dialog */ @@ -344,46 +218,5 @@ public abstract class ProviderListBaseActivity extends ConfigWizardBaseActivity intent.putExtra(EXTRAS_KEY_INVALID_URL, url); startActivityForResult(intent, REQUEST_CODE_ADD_PROVIDER); } - - /** - * Shows an error dialog, if configuring of a provider failed. - */ - public void showDownloadFailedDialog() { - try { - providerConfigState = SHOW_FAILED_DIALOG; - FragmentTransaction fragmentTransaction = fragmentManager.removePreviousFragment(ProviderSetupFailedDialog.TAG); - DialogFragment newFragment; - try { - JSONObject errorJson = new JSONObject(reasonToFail); - newFragment = ProviderSetupFailedDialog.newInstance(provider, errorJson, testNewURL); - } catch (JSONException e) { - e.printStackTrace(); - newFragment = ProviderSetupFailedDialog.newInstance(provider, reasonToFail); - } catch (NullPointerException e) { - //reasonToFail was null - return; - } - newFragment.show(fragmentTransaction, ProviderSetupFailedDialog.TAG); - } catch (IllegalStateException e) { - e.printStackTrace(); - providerConfigState = 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 && - providerConfigState != SHOWING_PROVIDER_DETAILS) { - providerConfigState = SHOWING_PROVIDER_DETAILS; - Intent intent = new Intent(this, ProviderDetailActivity.class); - intent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION); - intent.putExtra(PROVIDER_KEY, provider); - startActivityForResult(intent, REQUEST_CODE_CONFIGURE_LEAP); - } - } + } diff --git a/app/src/main/java/se/leap/bitmaskclient/ProviderSetupBaseActivity.java b/app/src/main/java/se/leap/bitmaskclient/ProviderSetupBaseActivity.java new file mode 100644 index 00000000..8731a2cc --- /dev/null +++ b/app/src/main/java/se/leap/bitmaskclient/ProviderSetupBaseActivity.java @@ -0,0 +1,235 @@ +package se.leap.bitmaskclient; + +import android.content.Intent; +import android.content.IntentFilter; +import android.os.Bundle; +import android.os.Handler; +import android.os.PersistableBundle; +import android.support.annotation.Nullable; +import android.support.v4.app.DialogFragment; +import android.support.v4.app.FragmentTransaction; +import android.support.v4.content.LocalBroadcastManager; +import android.util.Log; + +import org.jetbrains.annotations.NotNull; +import org.json.JSONException; +import org.json.JSONObject; + +import static se.leap.bitmaskclient.Constants.BROADCAST_PROVIDER_API_EVENT; +import static se.leap.bitmaskclient.Constants.PROVIDER_KEY; +import static se.leap.bitmaskclient.Constants.REQUEST_CODE_CONFIGURE_LEAP; +import static se.leap.bitmaskclient.ProviderAPI.DOWNLOAD_VPN_CERTIFICATE; +import static se.leap.bitmaskclient.ProviderAPI.ERRORS; +import static se.leap.bitmaskclient.ProviderAPI.PROVIDER_SET_UP; +import static se.leap.bitmaskclient.ProviderAPI.UPDATE_PROVIDER_DETAILS; +import static se.leap.bitmaskclient.ProviderSetupInterface.ProviderConfigState.PENDING_SHOW_FAILED_DIALOG; +import static se.leap.bitmaskclient.ProviderSetupInterface.ProviderConfigState.PROVIDER_NOT_SET; +import static se.leap.bitmaskclient.ProviderSetupInterface.ProviderConfigState.SETTING_UP_PROVIDER; +import static se.leap.bitmaskclient.ProviderSetupInterface.ProviderConfigState.SHOWING_PROVIDER_DETAILS; +import static se.leap.bitmaskclient.ProviderSetupInterface.ProviderConfigState.SHOW_FAILED_DIALOG; + +/** + * Created by cyberta on 19.08.18. + */ + +public abstract class ProviderSetupBaseActivity extends ConfigWizardBaseActivity implements ProviderAPIResultReceiver.Receiver, ProviderSetupInterface, ProviderSetupFailedDialog.DownloadFailedDialogInterface { + final public static String TAG = "PoviderSetupActivity"; + final private static String ACTIVITY_STATE = "ACTIVITY STATE"; + final private static String REASON_TO_FAIL = "REASON TO FAIL"; + + protected ProviderSetupInterface.ProviderConfigState providerConfigState = PROVIDER_NOT_SET; + private ProviderManager providerManager; + private FragmentManagerEnhanced fragmentManager; + + private String reasonToFail; + protected boolean testNewURL; + + private ProviderApiSetupBroadcastReceiver providerAPIBroadcastReceiver; + private ProviderAPIResultReceiver providerAPIResultReceiver; + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + fragmentManager = new FragmentManagerEnhanced(getSupportFragmentManager()); + providerManager = ProviderManager.getInstance(getAssets(), getExternalFilesDir(null)); + } + + @Override + protected void onResume() { + super.onResume(); + Log.d(TAG, "resuming with ConfigState: " + providerConfigState.toString()); + setUpProviderAPIResultReceiver(); + if (SETTING_UP_PROVIDER == providerConfigState) { + showProgressBar(); + checkProviderSetUp(); + } else if (PENDING_SHOW_FAILED_DIALOG == providerConfigState) { + showProgressBar(); + showDownloadFailedDialog(); + } else if (SHOW_FAILED_DIALOG == providerConfigState) { + showProgressBar(); + } else if (SHOWING_PROVIDER_DETAILS == providerConfigState) { + cancelSettingUpProvider(); + } + } + + @Override + protected void onPause() { + super.onPause(); + if (providerAPIBroadcastReceiver != null) + LocalBroadcastManager.getInstance(this).unregisterReceiver(providerAPIBroadcastReceiver); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + providerAPIResultReceiver = null; + } + + + @Override + public void onSaveInstanceState(@NotNull Bundle outState) { + outState.putString(ACTIVITY_STATE, providerConfigState.toString()); + outState.putString(REASON_TO_FAIL, reasonToFail); + + super.onSaveInstanceState(outState); + } + + protected FragmentManagerEnhanced getFragmentManagerEnhanced() { + return fragmentManager; + } + + protected ProviderManager getProviderManager() { + return providerManager; + } + + protected void setProviderConfigState(ProviderConfigState state) { + this.providerConfigState = state; + } + + protected void setProvider(Provider provider) { + this.provider = provider; + } + + // --------- ProviderSetupInterface ---v + @Override + public Provider getProvider() { + return provider; + } + + @Override + public ProviderConfigState getConfigState() { + return providerConfigState; + } + + @Override + public void handleProviderSetupFailed(Bundle resultData) { + reasonToFail = resultData.getString(ERRORS); + showDownloadFailedDialog(); + } + + @Override + public void handleIncorrectlyDownloadedCertificate() { + cancelSettingUpProvider(); + setResult(RESULT_CANCELED, new Intent(getConfigState().toString())); + } + + // -------- DownloadFailedDialogInterface ---v + @Override + public void cancelSettingUpProvider() { + providerConfigState = PROVIDER_NOT_SET; + provider = null; + hideProgressBar(); + } + + @Override + public void updateProviderDetails() { + providerConfigState = SETTING_UP_PROVIDER; + ProviderAPICommand.execute(this, UPDATE_PROVIDER_DETAILS, provider); + } + + // -------- ProviderAPIResultReceiver.Receiver ---v + @Override + public void onReceiveResult(int resultCode, Bundle resultData) { + if (resultCode == ProviderAPI.PROVIDER_OK) { + Provider provider = resultData.getParcelable(PROVIDER_KEY); + handleProviderSetUp(provider); + } + } + + protected void restoreState(Bundle savedInstanceState) { + super.restoreState(savedInstanceState); + if (savedInstanceState == null) { + return; + } + this.providerConfigState = ProviderSetupInterface.ProviderConfigState.valueOf(savedInstanceState.getString(ACTIVITY_STATE, PROVIDER_NOT_SET.toString())); + if (savedInstanceState.containsKey(REASON_TO_FAIL)) { + reasonToFail = savedInstanceState.getString(REASON_TO_FAIL); + } + } + + private void setUpProviderAPIResultReceiver() { + providerAPIResultReceiver = new ProviderAPIResultReceiver(new Handler(), this); + providerAPIBroadcastReceiver = new ProviderApiSetupBroadcastReceiver(this); + + IntentFilter updateIntentFilter = new IntentFilter(BROADCAST_PROVIDER_API_EVENT); + updateIntentFilter.addCategory(Intent.CATEGORY_DEFAULT); + LocalBroadcastManager.getInstance(this).registerReceiver(providerAPIBroadcastReceiver, updateIntentFilter); + } + + /** + * Asks ProviderApiService to download an anonymous (anon) VPN certificate. + */ + protected void downloadVpnCertificate() { + ProviderAPICommand.execute(this, DOWNLOAD_VPN_CERTIFICATE, provider); + } + + /* + * + */ + public void checkProviderSetUp() { + ProviderAPICommand.execute(this, PROVIDER_SET_UP, provider, providerAPIResultReceiver); + } + + /** + * 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 && + providerConfigState != SHOWING_PROVIDER_DETAILS) { + providerConfigState = SHOWING_PROVIDER_DETAILS; + Intent intent = new Intent(this, ProviderDetailActivity.class); + intent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION); + intent.putExtra(PROVIDER_KEY, provider); + startActivityForResult(intent, REQUEST_CODE_CONFIGURE_LEAP); + } + } + + /** + * Shows an error dialog, if configuring of a provider failed. + */ + public void showDownloadFailedDialog() { + try { + providerConfigState = SHOW_FAILED_DIALOG; + FragmentTransaction fragmentTransaction = fragmentManager.removePreviousFragment(ProviderSetupFailedDialog.TAG); + DialogFragment newFragment; + try { + JSONObject errorJson = new JSONObject(reasonToFail); + newFragment = ProviderSetupFailedDialog.newInstance(provider, errorJson, testNewURL); + } catch (JSONException e) { + e.printStackTrace(); + newFragment = ProviderSetupFailedDialog.newInstance(provider, reasonToFail); + } catch (NullPointerException e) { + //reasonToFail was null + return; + } + newFragment.show(fragmentTransaction, ProviderSetupFailedDialog.TAG); + } catch (IllegalStateException e) { + e.printStackTrace(); + providerConfigState = PENDING_SHOW_FAILED_DIALOG; + } + } + +} diff --git a/app/src/main/java/se/leap/bitmaskclient/ProviderSetupFailedDialog.java b/app/src/main/java/se/leap/bitmaskclient/ProviderSetupFailedDialog.java index 3cfae776..71b67df1 100644 --- a/app/src/main/java/se/leap/bitmaskclient/ProviderSetupFailedDialog.java +++ b/app/src/main/java/se/leap/bitmaskclient/ProviderSetupFailedDialog.java @@ -171,8 +171,8 @@ public class ProviderSetupFailedDialog extends DialogFragment { @Override public void onCancel(DialogInterface dialog) { - interfaceWithConfigurationWizard.cancelSettingUpProvider(); dialog.dismiss(); + interfaceWithConfigurationWizard.cancelSettingUpProvider(); } @Override diff --git a/app/src/main/java/se/leap/bitmaskclient/StartActivity.java b/app/src/main/java/se/leap/bitmaskclient/StartActivity.java index 33c13b90..28eebb07 100644 --- a/app/src/main/java/se/leap/bitmaskclient/StartActivity.java +++ b/app/src/main/java/se/leap/bitmaskclient/StartActivity.java @@ -18,6 +18,7 @@ import se.leap.bitmaskclient.userstatus.User; import se.leap.bitmaskclient.utils.ConfigHelper; import static se.leap.bitmaskclient.Constants.APP_ACTION_CONFIGURE_ALWAYS_ON_PROFILE; +import static se.leap.bitmaskclient.Constants.DEFAULT_BITMASK; import static se.leap.bitmaskclient.Constants.EIP_RESTART_ON_BOOT; import static se.leap.bitmaskclient.Constants.PREFERENCES_APP_VERSION; import static se.leap.bitmaskclient.Constants.PROVIDER_EIP_DEFINITION; @@ -25,6 +26,7 @@ import static se.leap.bitmaskclient.Constants.PROVIDER_KEY; import static se.leap.bitmaskclient.Constants.REQUEST_CODE_CONFIGURE_LEAP; import static se.leap.bitmaskclient.Constants.SHARED_PREFERENCES; import static se.leap.bitmaskclient.MainActivity.ACTION_SHOW_VPN_FRAGMENT; +import static se.leap.bitmaskclient.utils.ConfigHelper.isDefaultBitmask; import static se.leap.bitmaskclient.utils.PreferenceHelper.getSavedProviderFromSharedPreferences; import static se.leap.bitmaskclient.utils.PreferenceHelper.providerInSharedPreferences; import static se.leap.bitmaskclient.utils.PreferenceHelper.storeProviderInPreferences; @@ -181,7 +183,11 @@ public class StartActivity extends Activity{ if (getIntent().hasExtra(APP_ACTION_CONFIGURE_ALWAYS_ON_PROFILE)) { getIntent().removeExtra(APP_ACTION_CONFIGURE_ALWAYS_ON_PROFILE); } - startActivityForResult(new Intent(this, ProviderListActivity.class), REQUEST_CODE_CONFIGURE_LEAP); + if (isDefaultBitmask()) { + startActivityForResult(new Intent(this, ProviderListActivity.class), REQUEST_CODE_CONFIGURE_LEAP); + } else { // custom branded app + startActivityForResult(new Intent(this, CustomProviderSetupActivity.class), REQUEST_CODE_CONFIGURE_LEAP); + } } @Override diff --git a/app/src/main/java/se/leap/bitmaskclient/TLSCompatSocketFactory.java b/app/src/main/java/se/leap/bitmaskclient/TLSCompatSocketFactory.java index cca75bdf..32652964 100644 --- a/app/src/main/java/se/leap/bitmaskclient/TLSCompatSocketFactory.java +++ b/app/src/main/java/se/leap/bitmaskclient/TLSCompatSocketFactory.java @@ -73,7 +73,7 @@ public class TLSCompatSocketFactory extends SSLSocketFactory { trustManager = trustManagers[0]; - // Create an SSLContext that uses our TrustManager + // Create a SSLContext that uses our TrustManager SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(null, tmf.getTrustManagers(), null); internalSSLSocketFactory = sslContext.getSocketFactory(); diff --git a/app/src/main/java/se/leap/bitmaskclient/drawer/NavigationDrawerFragment.java b/app/src/main/java/se/leap/bitmaskclient/drawer/NavigationDrawerFragment.java index 6e9879dd..769bd887 100644 --- a/app/src/main/java/se/leap/bitmaskclient/drawer/NavigationDrawerFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/drawer/NavigationDrawerFragment.java @@ -50,7 +50,6 @@ import android.widget.ArrayAdapter; import android.widget.CompoundButton; import android.widget.ListView; -import se.leap.bitmaskclient.utils.ConfigHelper; import se.leap.bitmaskclient.DrawerSettingsAdapter; import se.leap.bitmaskclient.DrawerSettingsAdapter.DrawerSettingsItem; import se.leap.bitmaskclient.EipFragment; @@ -64,11 +63,11 @@ import se.leap.bitmaskclient.fragments.LogFragment; import static android.content.Context.MODE_PRIVATE; import static se.leap.bitmaskclient.BitmaskApp.getRefWatcher; +import static se.leap.bitmaskclient.Constants.DONATION_URL; +import static se.leap.bitmaskclient.Constants.ENABLE_DONATION; import static se.leap.bitmaskclient.Constants.PROVIDER_KEY; import static se.leap.bitmaskclient.Constants.REQUEST_CODE_SWITCH_PROVIDER; import static se.leap.bitmaskclient.Constants.SHARED_PREFERENCES; -import static se.leap.bitmaskclient.Constants.DONATION_URL; -import static se.leap.bitmaskclient.Constants.ENABLE_DONATION; import static se.leap.bitmaskclient.DrawerSettingsAdapter.ABOUT; import static se.leap.bitmaskclient.DrawerSettingsAdapter.ALWAYS_ON; import static se.leap.bitmaskclient.DrawerSettingsAdapter.BATTERY_SAVER; @@ -78,14 +77,15 @@ import static se.leap.bitmaskclient.DrawerSettingsAdapter.DrawerSettingsItem.get import static se.leap.bitmaskclient.DrawerSettingsAdapter.LOG; import static se.leap.bitmaskclient.DrawerSettingsAdapter.SWITCH_PROVIDER; import static se.leap.bitmaskclient.R.string.about_fragment_title; +import static se.leap.bitmaskclient.R.string.donate_title; import static se.leap.bitmaskclient.R.string.log_fragment_title; import static se.leap.bitmaskclient.R.string.switch_provider_menu_option; +import static se.leap.bitmaskclient.utils.ConfigHelper.isDefaultBitmask; import static se.leap.bitmaskclient.utils.PreferenceHelper.getProviderName; import static se.leap.bitmaskclient.utils.PreferenceHelper.getSaveBattery; import static se.leap.bitmaskclient.utils.PreferenceHelper.getSavedProviderFromSharedPreferences; import static se.leap.bitmaskclient.utils.PreferenceHelper.getShowAlwaysOnDialog; import static se.leap.bitmaskclient.utils.PreferenceHelper.saveBattery; -import static se.leap.bitmaskclient.R.string.donate_title; /** * Fragment used for managing interactions for and presentation of a navigation drawer. @@ -286,7 +286,9 @@ public class NavigationDrawerFragment extends Fragment { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { settingsListAdapter.addItem(getSimpleTextInstance(getString(R.string.always_on_vpn), ALWAYS_ON)); } - settingsListAdapter.addItem(getSimpleTextInstance(getString(switch_provider_menu_option), SWITCH_PROVIDER)); + if (isDefaultBitmask()) { + settingsListAdapter.addItem(getSimpleTextInstance(getString(switch_provider_menu_option), SWITCH_PROVIDER)); + } settingsListAdapter.addItem(getSimpleTextInstance(getString(log_fragment_title), LOG)); if (ENABLE_DONATION) { settingsListAdapter.addItem(getSimpleTextInstance(getString(donate_title), DONATE)); diff --git a/app/src/main/java/se/leap/bitmaskclient/utils/ConfigHelper.java b/app/src/main/java/se/leap/bitmaskclient/utils/ConfigHelper.java index 5bb637b7..326139c0 100644 --- a/app/src/main/java/se/leap/bitmaskclient/utils/ConfigHelper.java +++ b/app/src/main/java/se/leap/bitmaskclient/utils/ConfigHelper.java @@ -40,8 +40,11 @@ import java.security.interfaces.RSAPrivateKey; import java.security.spec.InvalidKeySpecException; import java.security.spec.PKCS8EncodedKeySpec; +import se.leap.bitmaskclient.BuildConfig; import se.leap.bitmaskclient.ProviderAPI; +import static se.leap.bitmaskclient.Constants.DEFAULT_BITMASK; + /** * Stores constants, and implements auxiliary methods used across all Bitmask Android classes. * @@ -167,4 +170,11 @@ public class ConfigHelper { } } + public static boolean isDefaultBitmask() { + return BuildConfig.FLAVOR_branding.equals(DEFAULT_BITMASK); + } + + public static boolean preferAnonymousUsage() { + return BuildConfig.priotize_anonymous_usage; + } } diff --git a/app/src/main/res/layout/a_custom_provider_setup.xml b/app/src/main/res/layout/a_custom_provider_setup.xml new file mode 100644 index 00000000..34c59259 --- /dev/null +++ b/app/src/main/res/layout/a_custom_provider_setup.xml @@ -0,0 +1,30 @@ + + + + + + + + + + -- cgit v1.2.3