diff options
Diffstat (limited to 'app/src/main')
23 files changed, 365 insertions, 38 deletions
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 @@ <activity android:name=".providersetup.activities.SetupActivity" android:launchMode="singleInstance" + android:screenOrientation="portrait" android:exported="false" /> <service 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/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/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 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/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/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", 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/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<Provider> { 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(); 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..90a32fea --- /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 <http://www.gnu.org/licenses/>. + */ + +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 (getInstance().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/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<Integer> 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/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(); 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..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 @@ -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; @@ -47,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; @@ -84,14 +86,19 @@ public class SetupActivity extends AppCompatActivity implements SetupActivityCal fragmentManager = new FragmentManagerEnhanced(getSupportFragmentManager()); ArrayList<View> 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) { @@ -160,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); @@ -281,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/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); @@ -50,9 +58,38 @@ public class CircumventionSetupFragment extends BaseSetupFragment { } @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/java/se/leap/bitmaskclient/providersetup/fragments/ConfigureProviderFragment.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/fragments/ConfigureProviderFragment.java index 3c36065e..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 @@ -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; @@ -21,20 +22,23 @@ 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; 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; 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,11 +46,13 @@ 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; 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; @@ -60,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(); @@ -97,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(); @@ -116,8 +124,14 @@ 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); + } + binding.progressSpinner.update(ProviderSetupObservable.getProgress()); setupActivityCallback.setNavigationButtonHidden(true); setupActivityCallback.setCancelButtonHidden(false); + ProviderSetupObservable.startSetup(); ProviderAPICommand.execute(getContext(), SET_UP_PROVIDER, setupActivityCallback.getSelectedProvider()); } @@ -145,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; @@ -162,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()); }); } } @@ -191,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; } @@ -205,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: 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/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 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt" + android:name="circle" + android:viewportWidth="91" + android:viewportHeight="91" + android:width="91dp" + android:height="91dp"> + <path + android:pathData="M83.9459 61.7492C81.6735 67.1718 78.2509 72.0496 73.9091 76.0535L45.5808 46.0417L83.9459 61.7492Z" + android:fillColor="#FFCC80" /> + <path + android:pathData="M74.9439 75.0657C70.7802 79.1812 65.7785 82.3744 60.2709 84.4334L45.5806 46.0421L74.9439 75.0657Z" + android:fillColor="#FFE082" /> + <path + android:pathData="M61.4719 83.9632C55.9543 86.2222 50.0087 87.2783 44.0406 87.0594L45.5806 46.0421L61.4719 83.9632Z" + android:fillColor="#FFF59D" /> + <path + android:pathData="M45.5803 87.088C39.516 87.088 33.5253 85.7751 28.0292 83.2417L45.5803 46.0425L45.5803 87.088Z" + android:fillColor="#E6EE9C" /> + <path + android:pathData="M29.6888 83.9635C24.2224 81.7254 19.303 78.3586 15.2601 74.0885L45.5801 46.0424L29.6888 83.9635Z" + android:fillColor="#C5E1A5" /> + <path + android:pathData="M16.2165 75.0658C11.9261 70.825 8.62802 65.7065 6.55433 60.0703L45.5798 46.0422L16.2165 75.0658Z" + android:fillColor="#A5D6A7" /> + <path + android:pathData="M7.21455 61.7497C4.89145 56.2061 3.82625 50.2265 4.09398 44.232L45.5796 46.0422L7.21455 61.7497Z" + android:fillColor="#80CBC4" /> + <path + android:pathData="M4.05357 46.0421C4.05357 40.2602 5.28944 34.5435 7.68023 29.2665L45.5796 46.0421L4.05357 46.0421Z" + android:fillColor="#80DEEA" /> + <path + android:pathData="M7.21454 30.3342C9.56893 24.716 13.1569 19.685 17.7191 15.6051L45.5796 46.0416L7.21454 30.3342Z" + android:fillColor="#81D4FA" /> + <path + android:pathData="M16.216 17.0181C20.5162 12.7677 25.7084 9.50267 31.4256 7.45389L45.5793 46.0416L16.216 17.0181Z" + android:fillColor="#90CAF9" /> + <path + android:pathData="M29.6883 8.12016C35.3597 5.79816 41.4814 4.7479 47.6127 5.04498L45.5796 46.0413L29.6883 8.12016Z" + android:fillColor="#9FA8DA" /> + <path + android:pathData="M45.5798 4.99576C51.3771 4.99576 57.1101 6.19555 62.4099 8.51791L45.5798 46.0413L45.5798 4.99576Z" + android:fillColor="#B39DDB" /> + <path + android:pathData="M61.4714 8.11991C66.8116 10.3063 71.6312 13.5706 75.6218 17.7038L45.5801 46.041L61.4714 8.11991Z" + android:fillColor="#CE93D8" /> + <path + android:pathData="M74.9437 17.0175C79.0466 21.0729 82.2441 25.9333 84.3301 31.2851L45.5803 46.041L74.9437 17.0175Z" + android:fillColor="#F48FB1" /> + <path + android:pathData="M83.9456 30.3337C86.2094 35.7356 87.2793 41.5533 87.0839 47.3971L45.5806 46.0411L83.9456 30.3337Z" + android:fillColor="#EF9A9A" /> + <path + android:pathData="M87.1066 46.0416C87.1066 51.4632 86.02 56.831 83.9094 61.8351L45.5806 46.0416L87.1066 46.0416Z" + android:fillColor="#FFAB91" /> + <path + android:pathData="M83.8543 60.835C81.5944 66.2576 78.1907 71.1354 73.8728 75.1393L45.7004 45.1276L83.8543 60.835Z" + android:fillColor="#FFCC80" /> + <path + android:pathData="M74.9019 74.1516C70.7611 78.2671 65.787 81.4604 60.3097 83.5193L45.7002 45.1281L74.9019 74.1516Z" + android:fillColor="#FFE082" /> + <path + android:pathData="M61.5041 83.0491C56.0168 85.3082 50.1039 86.3642 44.1687 86.1453L45.7002 45.1281L61.5041 83.0491Z" + android:fillColor="#FFF59D" /> + <path + android:pathData="M45.7002 86.1734C39.6693 86.1734 33.7115 84.8606 28.2457 82.3272L45.7002 45.1279L45.7002 86.1734Z" + android:fillColor="#E6EE9C" /> + <path + android:pathData="M29.8961 83.049C24.4598 80.811 19.5675 77.4442 15.5469 73.1741L45.7 45.1279L29.8961 83.049Z" + android:fillColor="#C5E1A5" /> + <path + android:pathData="M16.4977 74.1517C12.231 69.911 8.95103 64.7924 6.88875 59.1563L45.6995 45.1282L16.4977 74.1517Z" + android:fillColor="#A5D6A7" /> + <path + android:pathData="M7.54558 60.8351C5.23527 55.2915 4.17593 49.3119 4.44219 43.3175L45.6995 45.1277L7.54558 60.8351Z" + android:fillColor="#80CBC4" /> + <path + android:pathData="M4.40175 45.1277C4.40175 39.3457 5.63082 33.6291 8.00845 28.3521L45.6992 45.1277L4.40175 45.1277Z" + android:fillColor="#80DEEA" /> + <path + android:pathData="M7.54533 29.4201C9.88677 23.8019 13.455 18.7709 17.992 14.691L45.6992 45.1276L7.54533 29.4201Z" + android:fillColor="#81D4FA" /> + <path + android:pathData="M16.4972 16.104C20.7738 11.8536 25.9374 8.5886 31.6231 6.53981L45.699 45.1276L16.4972 16.104Z" + android:fillColor="#90CAF9" /> + <path + android:pathData="M29.8956 7.20611C35.5358 4.88411 41.6238 3.83384 47.7214 4.13092L45.6995 45.1272L29.8956 7.20611Z" + android:fillColor="#9FA8DA" /> + <path + android:pathData="M45.6997 4.08133C51.465 4.08133 57.1665 5.28113 62.4371 7.60349L45.6997 45.1268L45.6997 4.08133Z" + android:fillColor="#B39DDB" /> + <path + android:pathData="M61.5036 7.20587C66.8144 9.39225 71.6074 12.6565 75.576 16.7898L45.6997 45.127L61.5036 7.20587Z" + android:fillColor="#CE93D8" /> + <path + android:pathData="M74.9017 16.1034C78.982 20.1589 82.162 25.0192 84.2365 30.3711L45.7 45.127L74.9017 16.1034Z" + android:fillColor="#F48FB1" /> + <path + android:pathData="M83.8541 29.4196C86.1054 34.8216 87.1695 40.6392 86.9751 46.4831L45.7002 45.1271L83.8541 29.4196Z" + android:fillColor="#EF9A9A" /> + <path + android:pathData="M86.9979 45.1272C86.9979 50.5487 85.9172 55.9166 83.8183 60.9207L45.7004 45.1272L86.9979 45.1272Z" + android:fillColor="#FFAB91" /> +</vector>
\ 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 Binary files differnew file mode 100644 index 00000000..d7c85e02 --- /dev/null +++ b/app/src/main/res/drawable-hdpi/setup_rotate_progress_image.png 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 Binary files differnew file mode 100644 index 00000000..d6eb6b65 --- /dev/null +++ b/app/src/main/res/drawable-xhdpi/setup_rotate_progress_image.png 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 Binary files differnew file mode 100644 index 00000000..893b074b --- /dev/null +++ b/app/src/main/res/drawable-xxhdpi/setup_rotate_progress_image.png 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 @@ +<?xml version="1.0" encoding="utf-8"?> +<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> + <item + android:left="-25dp" + android:right="-25dp" + android:top="-10dp" + android:bottom="-10dp" + > + <animated-rotate + android:drawable="@drawable/setup_rotate_progress_image" + android:pivotX="50.0%" + android:pivotY="50.0%" + android:fromDegrees="0.0" + android:toDegrees="360.0" + > + </animated-rotate> + </item> + <item + android:bottom="15dp" + android:top="15dp" + > + <shape android:shape="oval"> + <solid android:color="@color/white"/> + <size android:width="250dp" android:height="250dp" /> + </shape> + </item> + +</layer-list>
\ 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 Binary files differnew file mode 100644 index 00000000..fe7f3526 --- /dev/null +++ b/app/src/main/res/drawable/setup_rotate_progress_image.png diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 90d06333..56588bc1 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -215,8 +215,8 @@ <string name="provider_description_calyx">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.</string> <string name="title_circumvention_setup">Do You Require Censorship Circumvention?</string> <string name="circumvention_setup_description">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!</string> - <string name="circumvention_setup_hint">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.</string> - <string name="use_standard_vpn">Use standard Bitmask VPN</string> + <string name="circumvention_setup_hint">%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.</string> + <string name="use_standard_vpn">Use standard %s</string> <string name="use_circumvention_tech">Use circumvention tech (slower)</string> <string name="description_configure_provider">To connect to your provider Bitmask is fetching all the required configuration information. This only happens during first setup.</string> <string name="description_configure_provider_circumvention">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.</string> @@ -236,5 +236,5 @@ <string name="upcoming_notifications_request_description">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.</string> <string name="title_setup_success">You\'re all set!</string> <string name="setup_success_description">Click the button below to connect</string> - + <string name="permission_rejected">Permission request rejected.</string> </resources> |