From d157f98aebc088205f427861ac414d19c7a05c3a Mon Sep 17 00:00:00 2001 From: cyBerta Date: Tue, 24 Oct 2023 21:57:06 +0200 Subject: show progress spinner during provider setup in custom flavored apps --- .../bitmaskclient/base/views/ProgressSpinner.java | 5 + .../fragments/ConfigureProviderFragment.java | 8 ++ .../setup_rotate_progress_image.xml | 103 +++++++++++++++++++++ .../drawable-hdpi/setup_rotate_progress_image.png | Bin 0 -> 6427 bytes .../drawable-xhdpi/setup_rotate_progress_image.png | Bin 0 -> 9736 bytes .../setup_rotate_progress_image.png | Bin 0 -> 12752 bytes .../main/res/drawable/setup_progress_spinner.xml | 28 ++++++ .../res/drawable/setup_rotate_progress_image.png | Bin 0 -> 4945 bytes 8 files changed, 144 insertions(+) create mode 100644 app/src/main/res/drawable-anydpi-v24/setup_rotate_progress_image.xml create mode 100644 app/src/main/res/drawable-hdpi/setup_rotate_progress_image.png create mode 100644 app/src/main/res/drawable-xhdpi/setup_rotate_progress_image.png create mode 100644 app/src/main/res/drawable-xxhdpi/setup_rotate_progress_image.png create mode 100644 app/src/main/res/drawable/setup_progress_spinner.xml create mode 100644 app/src/main/res/drawable/setup_rotate_progress_image.png (limited to 'app/src/main') diff --git a/app/src/main/java/se/leap/bitmaskclient/base/views/ProgressSpinner.java b/app/src/main/java/se/leap/bitmaskclient/base/views/ProgressSpinner.java index 380ddf23..97238ec6 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/views/ProgressSpinner.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/views/ProgressSpinner.java @@ -2,6 +2,7 @@ package se.leap.bitmaskclient.base.views; import android.annotation.TargetApi; import android.content.Context; +import android.graphics.drawable.Drawable; import android.util.AttributeSet; import android.view.LayoutInflater; import android.widget.RelativeLayout; @@ -60,4 +61,8 @@ public class ProgressSpinner extends RelativeLayout { } textView.setText(text); } + + public void setAnimatedSpinnerDrawable(Drawable drawable) { + spinnerView.setImageDrawable(drawable); + } } diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/fragments/ConfigureProviderFragment.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/fragments/ConfigureProviderFragment.java index 3c36065e..26eb5f4c 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/fragments/ConfigureProviderFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/fragments/ConfigureProviderFragment.java @@ -9,6 +9,7 @@ import static se.leap.bitmaskclient.R.string.description_configure_provider_circ import static se.leap.bitmaskclient.base.models.Constants.BROADCAST_RESULT_CODE; import static se.leap.bitmaskclient.base.models.Constants.BROADCAST_RESULT_KEY; import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_KEY; +import static se.leap.bitmaskclient.base.utils.ConfigHelper.isDefaultBitmask; import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getUseSnowflake; import static se.leap.bitmaskclient.base.utils.ViewHelper.animateContainerVisibility; import static se.leap.bitmaskclient.providersetup.ProviderAPI.CORRECTLY_DOWNLOADED_VPN_CERTIFICATE; @@ -28,6 +29,7 @@ import static se.leap.bitmaskclient.tor.TorStatusObservable.getLastTorLog; import android.app.Activity; import android.content.Intent; +import android.graphics.drawable.Drawable; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; @@ -35,6 +37,7 @@ import android.view.ViewGroup; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.core.content.res.ResourcesCompat; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; @@ -42,6 +45,7 @@ import java.util.List; import java.util.Observable; import java.util.Observer; +import se.leap.bitmaskclient.R; import se.leap.bitmaskclient.base.models.Provider; import se.leap.bitmaskclient.databinding.FConfigureProviderBinding; import se.leap.bitmaskclient.eip.EipSetupListener; @@ -116,6 +120,10 @@ public class ConfigureProviderFragment extends BaseSetupFragment implements Obse ignoreProviderAPIUpdates = false; binding.detailContainer.setVisibility(getUseSnowflake() ? VISIBLE : GONE); binding.tvCircumventionDescription.setText(getUseSnowflake() ? description_configure_provider_circumvention : description_configure_provider); + if (!isDefaultBitmask()) { + Drawable drawable = ResourcesCompat.getDrawable(getResources(), R.drawable.setup_progress_spinner, null); + binding.progressSpinner.setAnimatedSpinnerDrawable(drawable); + } setupActivityCallback.setNavigationButtonHidden(true); setupActivityCallback.setCancelButtonHidden(false); ProviderAPICommand.execute(getContext(), SET_UP_PROVIDER, setupActivityCallback.getSelectedProvider()); diff --git a/app/src/main/res/drawable-anydpi-v24/setup_rotate_progress_image.xml b/app/src/main/res/drawable-anydpi-v24/setup_rotate_progress_image.xml new file mode 100644 index 00000000..44a35ba9 --- /dev/null +++ b/app/src/main/res/drawable-anydpi-v24/setup_rotate_progress_image.xml @@ -0,0 +1,103 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable-hdpi/setup_rotate_progress_image.png b/app/src/main/res/drawable-hdpi/setup_rotate_progress_image.png new file mode 100644 index 00000000..d7c85e02 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/setup_rotate_progress_image.png differ diff --git a/app/src/main/res/drawable-xhdpi/setup_rotate_progress_image.png b/app/src/main/res/drawable-xhdpi/setup_rotate_progress_image.png new file mode 100644 index 00000000..d6eb6b65 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/setup_rotate_progress_image.png differ diff --git a/app/src/main/res/drawable-xxhdpi/setup_rotate_progress_image.png b/app/src/main/res/drawable-xxhdpi/setup_rotate_progress_image.png new file mode 100644 index 00000000..893b074b Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/setup_rotate_progress_image.png differ diff --git a/app/src/main/res/drawable/setup_progress_spinner.xml b/app/src/main/res/drawable/setup_progress_spinner.xml new file mode 100644 index 00000000..1664e2b7 --- /dev/null +++ b/app/src/main/res/drawable/setup_progress_spinner.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/setup_rotate_progress_image.png b/app/src/main/res/drawable/setup_rotate_progress_image.png new file mode 100644 index 00000000..fe7f3526 Binary files /dev/null and b/app/src/main/res/drawable/setup_rotate_progress_image.png differ -- cgit v1.2.3 From f64576feee47a783a3058ac181e8460fb19a30ce Mon Sep 17 00:00:00 2001 From: cyBerta Date: Tue, 24 Oct 2023 21:57:49 +0200 Subject: replace snake_case with camelCase in ProviderManager --- .../java/se/leap/bitmaskclient/providersetup/ProviderManager.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'app/src/main') diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderManager.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderManager.java index 0f6c5090..b46072ff 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderManager.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderManager.java @@ -73,9 +73,9 @@ public class ProviderManager implements AdapteeCollection { addCustomProviders(externalFilesDir); } - private void addDefaultProviders(AssetManager assets_manager) { + private void addDefaultProviders(AssetManager assetManager) { try { - defaultProviders = providersFromAssets(URLS, assets_manager.list(URLS)); + defaultProviders = providersFromAssets(URLS, assetManager.list(URLS)); defaultProviderURLs = getProviderUrlSetFromProviderSet(defaultProviders); } catch (IOException e) { e.printStackTrace(); -- cgit v1.2.3 From 6d7a966b39a8a1208d67981e726c63d02efd4f4a Mon Sep 17 00:00:00 2001 From: cyBerta Date: Tue, 24 Oct 2023 22:02:29 +0200 Subject: use new provider setup flow for custom branded apps --- .../se/leap/bitmaskclient/base/StartActivity.java | 10 ++--- .../providersetup/SetupViewPagerAdapter.java | 5 ++- .../providersetup/activities/SetupActivity.java | 14 +++++-- .../fragments/CircumventionSetupFragment.java | 43 ++++++++++++++++++++-- app/src/main/res/values/strings.xml | 4 +- 5 files changed, 59 insertions(+), 17 deletions(-) (limited to 'app/src/main') diff --git a/app/src/main/java/se/leap/bitmaskclient/base/StartActivity.java b/app/src/main/java/se/leap/bitmaskclient/base/StartActivity.java index 8372b6ad..19f03dee 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/StartActivity.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/StartActivity.java @@ -247,13 +247,9 @@ public class StartActivity extends Activity{ if (getIntent().hasExtra(APP_ACTION_CONFIGURE_ALWAYS_ON_PROFILE)) { getIntent().removeExtra(APP_ACTION_CONFIGURE_ALWAYS_ON_PROFILE); } - if (isDefaultBitmask()) { - Intent intent = new Intent(this, SetupActivity.class); - intent.putExtra(SetupActivity.EXTRA_SWITCH_PROVIDER, false); - startActivityForResult(intent, REQUEST_CODE_CONFIGURE_LEAP); - } else { // custom branded app - startActivityForResult(new Intent(this, CustomProviderSetupActivity.class), REQUEST_CODE_CONFIGURE_LEAP); - } + Intent intent = new Intent(this, SetupActivity.class); + intent.putExtra(SetupActivity.EXTRA_SWITCH_PROVIDER, false); + startActivityForResult(intent, REQUEST_CODE_CONFIGURE_LEAP); } @Override diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/SetupViewPagerAdapter.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/SetupViewPagerAdapter.java index a4a8fabd..00630f39 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/SetupViewPagerAdapter.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/SetupViewPagerAdapter.java @@ -1,5 +1,6 @@ package se.leap.bitmaskclient.providersetup; +import static se.leap.bitmaskclient.base.utils.ConfigHelper.isDefaultBitmask; import static se.leap.bitmaskclient.providersetup.fragments.SetupFragmentFactory.CIRCUMVENTION_SETUP_FRAGMENT; import static se.leap.bitmaskclient.providersetup.fragments.SetupFragmentFactory.CONFIGURE_PROVIDER_FRAGMENT; import static se.leap.bitmaskclient.providersetup.fragments.SetupFragmentFactory.NOTIFICATION_PERMISSON_EDUCATIONAL_FRAGMENT; @@ -33,7 +34,9 @@ public class SetupViewPagerAdapter extends FragmentStateAdapter { this(fragmentManager, lifecycle); ArrayList fragments = new ArrayList<>(); if (providerSetup) { - fragments.add(PROVIDER_SELECTION_FRAGMENT); + if (isDefaultBitmask()) { + fragments.add(PROVIDER_SELECTION_FRAGMENT); + } fragments.add(CIRCUMVENTION_SETUP_FRAGMENT); fragments.add(CONFIGURE_PROVIDER_FRAGMENT); } diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/SetupActivity.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/SetupActivity.java index a6e50769..724543e4 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/SetupActivity.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/SetupActivity.java @@ -3,6 +3,7 @@ package se.leap.bitmaskclient.providersetup.activities; import static android.view.View.GONE; import static android.view.View.VISIBLE; import static androidx.appcompat.app.ActionBar.DISPLAY_SHOW_CUSTOM; +import static se.leap.bitmaskclient.base.utils.ConfigHelper.isDefaultBitmask; import static se.leap.bitmaskclient.base.utils.PreferenceHelper.deleteProviderDetailsFromPreferences; import static se.leap.bitmaskclient.providersetup.fragments.SetupFragmentFactory.CONFIGURE_PROVIDER_FRAGMENT; import static se.leap.bitmaskclient.tor.TorStatusObservable.TorStatus.OFF; @@ -84,14 +85,19 @@ public class SetupActivity extends AppCompatActivity implements SetupActivityCal fragmentManager = new FragmentManagerEnhanced(getSupportFragmentManager()); ArrayList indicatorViews = new ArrayList<>(); - // indicator views for provider selection and config setup + if (isDefaultBitmask()) { + // indicator view for provider selection + addIndicatorView(indicatorViews); + } + + // indicator views for config setup boolean basicProviderSetup = !ProviderObservable.getInstance().getCurrentProvider().isConfigured() || switchProvider; if (basicProviderSetup) { - for (int i = 0; i < 3; i++) { - addIndicatorView(indicatorViews); - } + addIndicatorView(indicatorViews); + addIndicatorView(indicatorViews); } + // indicator views for VPN permission Intent requestVpnPermission = VpnService.prepare(this); if (requestVpnPermission != null) { diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/fragments/CircumventionSetupFragment.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/fragments/CircumventionSetupFragment.java index 11fa582b..34a93319 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/fragments/CircumventionSetupFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/fragments/CircumventionSetupFragment.java @@ -1,5 +1,8 @@ package se.leap.bitmaskclient.providersetup.fragments; +import static se.leap.bitmaskclient.base.utils.ConfigHelper.isDefaultBitmask; + +import android.content.Context; import android.graphics.Typeface; import android.os.Bundle; import android.view.LayoutInflater; @@ -9,10 +12,14 @@ import android.view.ViewGroup; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import se.leap.bitmaskclient.R; import se.leap.bitmaskclient.base.utils.PreferenceHelper; import se.leap.bitmaskclient.databinding.FCircumventionSetupBinding; +import se.leap.bitmaskclient.providersetup.ProviderManager; +import se.leap.bitmaskclient.providersetup.activities.CancelCallback; +import se.leap.bitmaskclient.providersetup.activities.SetupActivityCallback; -public class CircumventionSetupFragment extends BaseSetupFragment { +public class CircumventionSetupFragment extends BaseSetupFragment implements CancelCallback { public static CircumventionSetupFragment newInstance(int position) { CircumventionSetupFragment fragment = new CircumventionSetupFragment(); @@ -24,7 +31,8 @@ public class CircumventionSetupFragment extends BaseSetupFragment { public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { FCircumventionSetupBinding binding = FCircumventionSetupBinding.inflate(inflater, container, false); - + binding.rbPlainVpn.setText(getString(R.string.use_standard_vpn, getString(R.string.app_name))); + binding.tvCircumventionDetailDescription.setText(getString(R.string.circumvention_setup_hint, getString(R.string.app_name))); binding.circumventionRadioGroup.setOnCheckedChangeListener((group, checkedId) -> { if (binding.rbCircumvention.getId() == checkedId) { PreferenceHelper.useBridges(true); @@ -49,10 +57,39 @@ public class CircumventionSetupFragment extends BaseSetupFragment { return binding.getRoot(); } + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + setupActivityCallback.registerCancelCallback(this); + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + setupActivityCallback.removeCancelCallback(this); + } + @Override public void onFragmentSelected() { super.onFragmentSelected(); - setupActivityCallback.setCancelButtonHidden(false); + setupActivityCallback.setCancelButtonHidden(!isDefaultBitmask()); setupActivityCallback.setNavigationButtonHidden(false); + if (!isDefaultBitmask()) { + loadProviderFromAssets(); + } + } + + private void loadProviderFromAssets() { + ProviderManager providerManager = ProviderManager.getInstance(getContext().getApplicationContext().getAssets(), + getContext().getExternalFilesDir(null)); + providerManager.setAddDummyEntry(false); + setupActivityCallback.onProviderSelected(providerManager.providers().get(0)); + } + + @Override + public void onCanceled() { + if (!isDefaultBitmask()) { + loadProviderFromAssets(); + } } } \ 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 90d06333..baefac16 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -215,8 +215,8 @@ Calyx is a non-profit education and research organization devoted to studying, testing, developing and implementing privacy technology and tools to promote free speech, free expression, civic engagement and privacy rights on the internet and in the mobile communications industry. Do You Require Censorship Circumvention? If you live where the internet is censored you can use our censorship circumvention options to access all internet services. These options will slow down your connection! - Bitmask will automatically try to connect you to the internet using a variety of circumvention technologies. You can fine tune this in the advanced settings. - Use standard Bitmask VPN + %s will automatically try to connect you to the internet using a variety of circumvention technologies. You can fine tune this in the advanced settings. + Use standard %s Use circumvention tech (slower) To connect to your provider Bitmask is fetching all the required configuration information. This only happens during first setup. Bitmask is attempting to collect all required configuration data from the provider. This only happens during first setup. You selected to use circumvention technology, so this might take some time. -- cgit v1.2.3 From b2956073c6f0770347ec71bdc592b74426fddf2a Mon Sep 17 00:00:00 2001 From: cyBerta Date: Wed, 25 Oct 2023 14:54:41 +0200 Subject: always show provider setup progress in percentage, combine tor bootstrap progress and provider api communication progress in case circumvention is needed --- .../se/leap/bitmaskclient/base/BitmaskApp.java | 5 +- .../leap/bitmaskclient/eip/EipSetupObserver.java | 2 + .../providersetup/ProviderApiManagerBase.java | 6 ++ .../providersetup/ProviderSetupObservable.java | 103 +++++++++++++++++++++ .../providersetup/activities/SetupActivity.java | 3 + .../fragments/ConfigureProviderFragment.java | 25 +++-- 6 files changed, 136 insertions(+), 8 deletions(-) create mode 100644 app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderSetupObservable.java (limited to 'app/src/main') diff --git a/app/src/main/java/se/leap/bitmaskclient/base/BitmaskApp.java b/app/src/main/java/se/leap/bitmaskclient/base/BitmaskApp.java index a66f75d7..0fa62285 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/BitmaskApp.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/BitmaskApp.java @@ -26,7 +26,6 @@ import static se.leap.bitmaskclient.base.utils.ConfigHelper.isCalyxOSWithTetheri import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getSavedProviderFromSharedPreferences; import android.content.IntentFilter; -import android.content.SharedPreferences; import androidx.appcompat.app.AppCompatDelegate; import androidx.localbroadcastmanager.content.LocalBroadcastManager; @@ -42,6 +41,7 @@ import se.leap.bitmaskclient.base.models.ProviderObservable; import se.leap.bitmaskclient.base.utils.PRNGFixes; import se.leap.bitmaskclient.base.utils.PreferenceHelper; import se.leap.bitmaskclient.eip.EipSetupObserver; +import se.leap.bitmaskclient.providersetup.ProviderSetupObservable; import se.leap.bitmaskclient.tethering.TetheringStateManager; import se.leap.bitmaskclient.tor.TorStatusObservable; @@ -56,6 +56,8 @@ public class BitmaskApp extends MultiDexApplication { private DownloadBroadcastReceiver downloadBroadcastReceiver; private TorStatusObservable torStatusObservable; + private ProviderSetupObservable providerSetupObservable; + private PreferenceHelper preferenceHelper; @@ -69,6 +71,7 @@ public class BitmaskApp extends MultiDexApplication { providerObservable = ProviderObservable.getInstance(); providerObservable.updateProvider(getSavedProviderFromSharedPreferences()); torStatusObservable = TorStatusObservable.getInstance(); + providerSetupObservable = ProviderSetupObservable.getInstance(); EipSetupObserver.init(this); AppCompatDelegate.setCompatVectorFromResourcesEnabled(true); if (!isCalyxOSWithTetheringSupport(this)) { diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/EipSetupObserver.java b/app/src/main/java/se/leap/bitmaskclient/eip/EipSetupObserver.java index ed83770b..c8b8bea4 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/EipSetupObserver.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/EipSetupObserver.java @@ -79,6 +79,7 @@ import se.leap.bitmaskclient.base.models.ProviderObservable; import se.leap.bitmaskclient.base.utils.PreferenceHelper; import se.leap.bitmaskclient.providersetup.ProviderAPI; import se.leap.bitmaskclient.providersetup.ProviderAPICommand; +import se.leap.bitmaskclient.providersetup.ProviderSetupObservable; import se.leap.bitmaskclient.tor.TorServiceCommand; import se.leap.bitmaskclient.tor.TorStatusObservable; @@ -177,6 +178,7 @@ public class EipSetupObserver extends BroadcastReceiver implements VpnStatus.Sta Integer bootstrap = intent.getIntExtra(TorService.EXTRA_STATUS_DETAIL_BOOTSTRAP, -1); String logKey = intent.getStringExtra(TorService.EXTRA_STATUS_DETAIL_LOGKEY); TorStatusObservable.updateState(appContext, status, bootstrap, logKey); + ProviderSetupObservable.updateTorSetupProgress(); } diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java index 9468f76e..93648bb0 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java @@ -96,6 +96,8 @@ import static se.leap.bitmaskclient.providersetup.ProviderSetupFailedDialog.DOWN import static se.leap.bitmaskclient.providersetup.ProviderSetupFailedDialog.DOWNLOAD_ERRORS.ERROR_CORRUPTED_PROVIDER_JSON; import static se.leap.bitmaskclient.providersetup.ProviderSetupFailedDialog.DOWNLOAD_ERRORS.ERROR_INVALID_CERTIFICATE; import static se.leap.bitmaskclient.providersetup.ProviderSetupFailedDialog.DOWNLOAD_ERRORS.ERROR_TOR_TIMEOUT; +import static se.leap.bitmaskclient.providersetup.ProviderSetupObservable.DOWNLOADED_GEOIP_JSON; +import static se.leap.bitmaskclient.providersetup.ProviderSetupObservable.DOWNLOADED_VPN_CERTIFICATE; import static se.leap.bitmaskclient.tor.TorStatusObservable.TorStatus.OFF; import static se.leap.bitmaskclient.tor.TorStatusObservable.TorStatus.ON; import static se.leap.bitmaskclient.tor.TorStatusObservable.getProxyPort; @@ -256,6 +258,9 @@ public abstract class ProviderApiManagerBase { result = setUpProvider(provider, parameters); if (result.getBoolean(BROADCAST_RESULT_KEY)) { getGeoIPJson(provider); + if (provider.hasGeoIpJson()) { + ProviderSetupObservable.updateProgress(DOWNLOADED_GEOIP_JSON); + } sendToReceiverOrBroadcast(receiver, PROVIDER_OK, result, provider); } else { sendToReceiverOrBroadcast(receiver, PROVIDER_NOK, result, provider); @@ -289,6 +294,7 @@ public abstract class ProviderApiManagerBase { ProviderObservable.getInstance().setProviderForDns(provider); result = updateVpnCertificate(provider); if (result.getBoolean(BROADCAST_RESULT_KEY)) { + ProviderSetupObservable.updateProgress(DOWNLOADED_VPN_CERTIFICATE); sendToReceiverOrBroadcast(receiver, CORRECTLY_DOWNLOADED_VPN_CERTIFICATE, result, provider); } else { sendToReceiverOrBroadcast(receiver, INCORRECTLY_DOWNLOADED_VPN_CERTIFICATE, result, provider); diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderSetupObservable.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderSetupObservable.java new file mode 100644 index 00000000..56ef357b --- /dev/null +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderSetupObservable.java @@ -0,0 +1,103 @@ +package se.leap.bitmaskclient.providersetup; +/** + * Copyright (c) 2023 LEAP Encryption Access Project and contributors + * + * 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 . + */ + +import android.os.Handler; +import android.os.Looper; + +import java.util.Observable; + +import se.leap.bitmaskclient.tor.TorStatusObservable; + +public class ProviderSetupObservable extends Observable { + + private static final String TAG = ProviderSetupObservable.class.getSimpleName(); + + private int progress = 0; + private boolean canceled = false; + public static final int DOWNLOADED_PROVIDER_JSON = 20; + public static final int DOWNLOADED_CA_CERT = 40; + public static final int DOWNLOADED_EIP_SERVICE_JSON = 60; + public static final int DOWNLOADED_GEOIP_JSON = 80; + public static final int DOWNLOADED_VPN_CERTIFICATE = 100; + + private static ProviderSetupObservable instance; + private final Handler handler = new Handler(Looper.getMainLooper()); + private long lastUpdate = 0; + + public static ProviderSetupObservable getInstance() { + if (instance == null) { + instance = new ProviderSetupObservable(); + } + return instance; + } + + public static void updateProgress(int progress) { + if (instance.canceled) { + return; + } + long now = System.currentTimeMillis(); + getInstance().handler.postDelayed(() -> { + if (TorStatusObservable.isRunning()) { + getInstance().progress = (TorStatusObservable.getBootstrapProgress() + progress) / 2; + } else { + getInstance().progress = progress; + } + + getInstance().setChanged(); + getInstance().notifyObservers(); + }, now - getInstance().lastUpdate < 500L ? 500L : 0L); + getInstance().lastUpdate = System.currentTimeMillis() + 500; + } + + public static void updateTorSetupProgress() { + if (!TorStatusObservable.isRunning() || getInstance().canceled) { + return; + } + long now = System.currentTimeMillis(); + getInstance().handler.postDelayed(() -> { + getInstance().progress = (TorStatusObservable.getBootstrapProgress()) / 2; + + getInstance().setChanged(); + getInstance().notifyObservers(); + }, now - getInstance().lastUpdate < 500L ? 500L : 0); + getInstance().lastUpdate = System.currentTimeMillis() + 500; + } + + public static int getProgress() { + return getInstance().progress; + } + + public static void reset() { + getInstance().progress = 0; + getInstance().setChanged(); + getInstance().notifyObservers(); + } + + public static void cancel() { + getInstance().canceled = true; + reset(); + } + + public static boolean isCanceled() { + return getInstance().canceled; + } + + public static void startSetup() { + getInstance().canceled = false; + } +} diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/SetupActivity.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/SetupActivity.java index 724543e4..b258a100 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/SetupActivity.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/SetupActivity.java @@ -48,6 +48,7 @@ import se.leap.bitmaskclient.base.utils.ViewHelper; import se.leap.bitmaskclient.base.views.ActionBarTitle; import se.leap.bitmaskclient.databinding.ActivitySetupBinding; import se.leap.bitmaskclient.providersetup.ProviderSetupFailedDialog; +import se.leap.bitmaskclient.providersetup.ProviderSetupObservable; import se.leap.bitmaskclient.providersetup.SetupViewPagerAdapter; import se.leap.bitmaskclient.tor.TorServiceCommand; import se.leap.bitmaskclient.tor.TorStatusObservable; @@ -166,6 +167,7 @@ public class SetupActivity extends AppCompatActivity implements SetupActivityCal private void cancel() { binding.viewPager.setCurrentItem(0, false); + ProviderSetupObservable.cancel(); if (TorStatusObservable.getStatus() != OFF) { Log.d(TAG, "SHUTDOWN - cancelSettingUpProvider"); TorServiceCommand.stopTorServiceAsync(this); @@ -287,6 +289,7 @@ public class SetupActivity extends AppCompatActivity implements SetupActivityCal @Override public void onSetupFinished() { + ProviderSetupObservable.reset(); Intent intent = getIntent(); if (provider == null && ProviderObservable.getInstance().getCurrentProvider().isConfigured()) { // only permissions were requested, no new provider configured, so reuse previously configured one diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/fragments/ConfigureProviderFragment.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/fragments/ConfigureProviderFragment.java index 26eb5f4c..ec646cac 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/fragments/ConfigureProviderFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/fragments/ConfigureProviderFragment.java @@ -22,7 +22,6 @@ import static se.leap.bitmaskclient.providersetup.ProviderAPI.PROVIDER_OK; import static se.leap.bitmaskclient.providersetup.ProviderAPI.SET_UP_PROVIDER; import static se.leap.bitmaskclient.providersetup.ProviderAPI.TOR_EXCEPTION; import static se.leap.bitmaskclient.providersetup.ProviderAPI.TOR_TIMEOUT; -import static se.leap.bitmaskclient.tor.TorStatusObservable.getBootstrapProgress; import static se.leap.bitmaskclient.tor.TorStatusObservable.getLastLogs; import static se.leap.bitmaskclient.tor.TorStatusObservable.getLastSnowflakeLog; import static se.leap.bitmaskclient.tor.TorStatusObservable.getLastTorLog; @@ -31,6 +30,8 @@ import android.app.Activity; import android.content.Intent; import android.graphics.drawable.Drawable; import android.os.Bundle; +import android.os.Handler; +import android.os.Looper; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -51,6 +52,7 @@ import se.leap.bitmaskclient.databinding.FConfigureProviderBinding; import se.leap.bitmaskclient.eip.EipSetupListener; import se.leap.bitmaskclient.eip.EipSetupObserver; import se.leap.bitmaskclient.providersetup.ProviderAPICommand; +import se.leap.bitmaskclient.providersetup.ProviderSetupObservable; import se.leap.bitmaskclient.providersetup.TorLogAdapter; import se.leap.bitmaskclient.providersetup.activities.CancelCallback; import se.leap.bitmaskclient.tor.TorStatusObservable; @@ -64,6 +66,8 @@ public class ConfigureProviderFragment extends BaseSetupFragment implements Obse private boolean ignoreProviderAPIUpdates = false; private TorLogAdapter torLogAdapter; + private Handler handler = new Handler(Looper.getMainLooper()); + public static ConfigureProviderFragment newInstance(int position) { ConfigureProviderFragment fragment = new ConfigureProviderFragment(); @@ -101,14 +105,14 @@ public class ConfigureProviderFragment extends BaseSetupFragment implements Obse public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); setupActivityCallback.registerCancelCallback(this); - TorStatusObservable.getInstance().addObserver(this); + ProviderSetupObservable.getInstance().addObserver(this); EipSetupObserver.addListener(this); } @Override public void onDestroyView() { setupActivityCallback.removeCancelCallback(this); - TorStatusObservable.getInstance().deleteObserver(this); + ProviderSetupObservable.getInstance().deleteObserver(this); EipSetupObserver.removeListener(this); binding = null; super.onDestroyView(); @@ -124,8 +128,10 @@ public class ConfigureProviderFragment extends BaseSetupFragment implements Obse Drawable drawable = ResourcesCompat.getDrawable(getResources(), R.drawable.setup_progress_spinner, null); binding.progressSpinner.setAnimatedSpinnerDrawable(drawable); } + binding.progressSpinner.update(ProviderSetupObservable.getProgress()); setupActivityCallback.setNavigationButtonHidden(true); setupActivityCallback.setCancelButtonHidden(false); + ProviderSetupObservable.startSetup(); ProviderAPICommand.execute(getContext(), SET_UP_PROVIDER, setupActivityCallback.getSelectedProvider()); } @@ -153,7 +159,7 @@ public class ConfigureProviderFragment extends BaseSetupFragment implements Obse @Override public void update(Observable o, Object arg) { - if (o instanceof TorStatusObservable) { + if (o instanceof ProviderSetupObservable) { Activity activity = getActivity(); if (activity == null || binding == null) { return; @@ -170,7 +176,7 @@ public class ConfigureProviderFragment extends BaseSetupFragment implements Obse } } binding.tvProgressStatus.setText(TorStatusObservable.getStringForCurrentStatus(activity)); - binding.progressSpinner.update(getBootstrapProgress()); + binding.progressSpinner.update(ProviderSetupObservable.getProgress()); }); } } @@ -199,7 +205,8 @@ public class ConfigureProviderFragment extends BaseSetupFragment implements Obse Provider provider = resultData.getParcelable(PROVIDER_KEY); if (ignoreProviderAPIUpdates || provider == null || - !setupActivityCallback.getSelectedProvider().getDomain().equals(provider.getDomain())) { + (setupActivityCallback.getSelectedProvider() != null && + !setupActivityCallback.getSelectedProvider().getDomain().equals(provider.getDomain()))) { return; } @@ -213,7 +220,11 @@ public class ConfigureProviderFragment extends BaseSetupFragment implements Obse break; case CORRECTLY_DOWNLOADED_VPN_CERTIFICATE: setupActivityCallback.onProviderSelected(provider); - setupActivityCallback.onConfigurationSuccess(); + handler.postDelayed(() -> { + if (!ProviderSetupObservable.isCanceled()) { + setupActivityCallback.onConfigurationSuccess(); + } + }, 750); break; case PROVIDER_NOK: case INCORRECTLY_DOWNLOADED_VPN_CERTIFICATE: -- cgit v1.2.3 From 743cd82d2c061631e493f13685065c987c8665ea Mon Sep 17 00:00:00 2001 From: cyBerta Date: Wed, 25 Oct 2023 14:56:50 +0200 Subject: deprecate old Provider API jobs, such as login and signup --- .../java/se/leap/bitmaskclient/providersetup/ProviderAPI.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'app/src/main') diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java index 07ea4691..ed30c454 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java @@ -52,15 +52,18 @@ public class ProviderAPI extends JobIntentService implements ProviderApiManagerB */ static final int JOB_ID = 161375; + @Deprecated + final public static String + UPDATE_PROVIDER_DETAILS = "updateProviderDetails", + SIGN_UP = "srpRegister", + LOG_IN = "srpAuth", + LOG_OUT = "logOut"; + final public static String TAG = ProviderAPI.class.getSimpleName(), SET_UP_PROVIDER = "setUpProvider", - UPDATE_PROVIDER_DETAILS = "updateProviderDetails", DOWNLOAD_GEOIP_JSON = "downloadGeoIpJson", DOWNLOAD_MOTD = "downloadMotd", - SIGN_UP = "srpRegister", - LOG_IN = "srpAuth", - LOG_OUT = "logOut", // all vpn certificate download commands are used in different scenarios with different error handling // command key used for the initial vpn certificate download during the provider setup DOWNLOAD_VPN_CERTIFICATE = "downloadUserAuthedVPNCertificate", -- cgit v1.2.3 From 3668796930633a4850aa9a5e0117c3c4d4d21af6 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Wed, 25 Oct 2023 14:57:32 +0200 Subject: make linter happy about missing super() call in CustomProviderSetupActivity --- .../providersetup/activities/CustomProviderSetupActivity.java | 1 + 1 file changed, 1 insertion(+) (limited to 'app/src/main') diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/CustomProviderSetupActivity.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/CustomProviderSetupActivity.java index 9cd46049..520395f8 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/CustomProviderSetupActivity.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/CustomProviderSetupActivity.java @@ -145,6 +145,7 @@ public class CustomProviderSetupActivity extends ProviderSetupBaseActivity { @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); if (requestCode == REQUEST_CODE_CONFIGURE_LEAP) { setResult(resultCode, data); finish(); -- cgit v1.2.3 From 923c51413b577754320667ead42b6393472051b9 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Wed, 25 Oct 2023 16:34:54 +0200 Subject: automatically move to next provider setup fragment after permission dialog was either accepted or rejected --- .../fragments/EmptyPermissionSetupFragment.java | 15 +++++++++------ app/src/main/res/values/strings.xml | 2 +- 2 files changed, 10 insertions(+), 7 deletions(-) (limited to 'app/src/main') diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/fragments/EmptyPermissionSetupFragment.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/fragments/EmptyPermissionSetupFragment.java index 4226d804..849ac681 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/fragments/EmptyPermissionSetupFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/fragments/EmptyPermissionSetupFragment.java @@ -14,6 +14,7 @@ import androidx.activity.result.contract.ActivityResultContracts; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import se.leap.bitmaskclient.R; import se.leap.bitmaskclient.databinding.FEmptyPermissionSetupBinding; public class EmptyPermissionSetupFragment extends BaseSetupFragment { @@ -31,9 +32,10 @@ public class EmptyPermissionSetupFragment extends BaseSetupFragment { setupActivityCallback.onConfigurationSuccess(); } } else { - Toast.makeText(getContext(), "Permission request failed :(", Toast.LENGTH_LONG).show(); - setupActivityCallback.setNavigationButtonHidden(false); - // TODO: implement sth. useful + Toast.makeText(getContext(), getText(R.string.permission_rejected), Toast.LENGTH_LONG).show(); + if (setupActivityCallback != null) { + setupActivityCallback.onConfigurationSuccess(); + } } }); @@ -46,9 +48,10 @@ public class EmptyPermissionSetupFragment extends BaseSetupFragment { setupActivityCallback.onConfigurationSuccess(); } } else { - Toast.makeText(getContext(), "Permission request failed :(", Toast.LENGTH_LONG).show(); - setupActivityCallback.setNavigationButtonHidden(false); - // TODO: implement sth. useful + Toast.makeText(getContext(), getText(R.string.permission_rejected), Toast.LENGTH_LONG).show(); + if (setupActivityCallback != null) { + setupActivityCallback.onConfigurationSuccess(); + } } } ); diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index baefac16..56588bc1 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -236,5 +236,5 @@ In the next panel Android will ask if you want to allow notifications. This will ensure a stable background connection and enable you to see your data usage from within Android’s notification center. You\'re all set! Click the button below to connect - + Permission request rejected. -- cgit v1.2.3 From 8940bf064378457979e3e49f168d45fa6ed7d5b6 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Wed, 25 Oct 2023 16:36:59 +0200 Subject: lock provider setup screenOrientation to portrait for now to work around a bug which appears if the user has accepted the permission requests and rotates the screen afterwards --- app/src/main/AndroidManifest.xml | 1 + 1 file changed, 1 insertion(+) (limited to 'app/src/main') diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 091fa0b6..cf4f6150 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -30,6 +30,7 @@ Date: Wed, 25 Oct 2023 22:56:53 +0200 Subject: tint action bar toggle in GatewaySelectionFragment --- .../leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'app/src/main') diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java index dc7f64e1..99b1ac39 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java @@ -39,6 +39,7 @@ import android.view.ViewGroup; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.widget.AppCompatTextView; +import androidx.core.content.ContextCompat; import androidx.fragment.app.Fragment; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; @@ -105,6 +106,10 @@ public class GatewaySelectionFragment extends Fragment implements Observer, Loca initRecommendedLocationEntry(); initBridgesHint(view); setActionBarSubtitle(this, R.string.gateway_selection_title); + Activity activity = getActivity(); + if (activity != null) { + ((MainActivity) activity).setActionBarToggleColor(ContextCompat.getColor(activity, R.color.colorActionBarTitleFont)); + } } @Override -- cgit v1.2.3 From f74107e3c47824e1cf4fdbc415d32871eb85f83c Mon Sep 17 00:00:00 2001 From: cyBerta Date: Thu, 26 Oct 2023 15:57:11 +0200 Subject: fix possible NPE in ProviderSetupObservable --- .../se/leap/bitmaskclient/providersetup/ProviderSetupObservable.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app/src/main') diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderSetupObservable.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderSetupObservable.java index 56ef357b..90a32fea 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderSetupObservable.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderSetupObservable.java @@ -47,7 +47,7 @@ public class ProviderSetupObservable extends Observable { } public static void updateProgress(int progress) { - if (instance.canceled) { + if (getInstance().canceled) { return; } long now = System.currentTimeMillis(); -- cgit v1.2.3