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/java/se/leap/bitmaskclient') 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