From 14b082f7670b25aabe22a3cd8db334b327645f8f Mon Sep 17 00:00:00 2001 From: cyBerta Date: Mon, 12 Dec 2022 14:06:52 +0100 Subject: setting spannable in ActionBar correctly. Fixes crash --- app/src/main/java/se/leap/bitmaskclient/base/utils/ViewHelper.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app/src/main/java') diff --git a/app/src/main/java/se/leap/bitmaskclient/base/utils/ViewHelper.java b/app/src/main/java/se/leap/bitmaskclient/base/utils/ViewHelper.java index 8076f99e..bbd77c36 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/utils/ViewHelper.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/utils/ViewHelper.java @@ -61,7 +61,7 @@ public class ViewHelper { public static void setActionBarTextColor(ActionBar bar, @ColorRes int titleColor) { CharSequence titleCharSequence = bar.getTitle(); - if (titleCharSequence == null) { + if (titleCharSequence == null || titleCharSequence.length() == 0) { return; } String title = titleCharSequence.toString(); -- cgit v1.2.3 From cb0eae7999271ba3db98d160fb60f0fdf6991841 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Tue, 13 Dec 2022 02:34:51 +0100 Subject: balance registering and un-registering listeners and observers in GatewaySelectionFragment --- .../leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'app/src/main/java') 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 a2bfff7c..00bd55ef 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 @@ -90,16 +90,16 @@ public class GatewaySelectionFragment extends Fragment implements Observer, Loca super.onCreate(savedInstanceState); gatewaysManager = new GatewaysManager(getContext()); eipStatus = EipStatus.getInstance(); - eipStatus.addObserver(this); preferences = getContext().getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE); - selectedTransport = getUseBridges(preferences) ? PT : OPENVPN; - preferences.registerOnSharedPreferenceChangeListener(this); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Inflate the layout for this fragment + selectedTransport = getUseBridges(preferences) ? PT : OPENVPN; + preferences.registerOnSharedPreferenceChangeListener(this); + eipStatus.addObserver(this); return inflater.inflate(R.layout.f_gateway_selection, container, false); } -- cgit v1.2.3 From 628f2466d6c351357ee7f1fd6623f750d1d6f46a Mon Sep 17 00:00:00 2001 From: cyBerta Date: Tue, 13 Dec 2022 02:37:51 +0100 Subject: don't create a new GatewaysSelectionFragment if it is already shown --- .../leap/bitmaskclient/base/fragments/NavigationDrawerFragment.java | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'app/src/main/java') diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/NavigationDrawerFragment.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/NavigationDrawerFragment.java index fe36e00a..5c4e891e 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/NavigationDrawerFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/NavigationDrawerFragment.java @@ -307,6 +307,10 @@ public class NavigationDrawerFragment extends Fragment implements SharedPreferen manualGatewaySelection.setOnClickListener(v -> { FragmentManagerEnhanced fragmentManager = new FragmentManagerEnhanced(getActivity().getSupportFragmentManager()); closeDrawer(); + Fragment current = fragmentManager.findFragmentByTag(MainActivity.TAG); + if (current instanceof GatewaySelectionFragment) { + return; + } Fragment fragment = new GatewaySelectionFragment(); fragmentManager.replace(R.id.main_container, fragment, MainActivity.TAG); }); -- cgit v1.2.3 From 4dd2f6ba1268dd4f122722d9f9e857193eb90965 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Wed, 14 Dec 2022 02:01:28 +0100 Subject: force nulling context after TorServiceConnection.close() --- .../java/se/leap/bitmaskclient/tor/TorServiceConnection.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'app/src/main/java') diff --git a/app/src/main/java/se/leap/bitmaskclient/tor/TorServiceConnection.java b/app/src/main/java/se/leap/bitmaskclient/tor/TorServiceConnection.java index dbfce2b5..87d3cad4 100644 --- a/app/src/main/java/se/leap/bitmaskclient/tor/TorServiceConnection.java +++ b/app/src/main/java/se/leap/bitmaskclient/tor/TorServiceConnection.java @@ -15,6 +15,9 @@ package se.leap.bitmaskclient.tor; * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + +import static se.leap.bitmaskclient.base.utils.ConfigHelper.ensureNotOnMainThread; + import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -30,13 +33,9 @@ import java.io.Closeable; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; -import se.leap.bitmaskclient.providersetup.ProviderAPI; - -import static se.leap.bitmaskclient.base.utils.ConfigHelper.ensureNotOnMainThread; - public class TorServiceConnection implements Closeable { private static final String TAG = TorServiceConnection.class.getSimpleName(); - private final Context context; + private Context context; private ServiceConnection serviceConnection; private TorService torService; @@ -50,6 +49,9 @@ public class TorServiceConnection implements Closeable { @Override public void close() { context.unbindService(serviceConnection); + context = null; + serviceConnection = null; + torService = null; } private void initSynchronizedServiceConnection(final Context context) throws InterruptedException { -- cgit v1.2.3 From 97615aefafc0cea0f4728202c2e92b38e7e7773a Mon Sep 17 00:00:00 2001 From: cyBerta Date: Wed, 14 Dec 2022 13:42:18 +0100 Subject: remove EipFragmentServiceConnection, fixes memory leaks --- .../bitmaskclient/base/fragments/EipFragment.java | 94 ++-------------------- .../java/se/leap/bitmaskclient/eip/EipStatus.java | 7 ++ 2 files changed, 14 insertions(+), 87 deletions(-) (limited to 'app/src/main/java') diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java index 02feafd3..c5ed7d12 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java @@ -16,7 +16,6 @@ */ package se.leap.bitmaskclient.base.fragments; -import static de.blinkt.openvpn.core.ConnectionStatus.LEVEL_NONETWORK; import static se.leap.bitmaskclient.R.string.vpn_certificate_user_message; import static se.leap.bitmaskclient.base.models.Constants.ASK_TO_CANCEL_VPN; import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_START; @@ -36,16 +35,12 @@ import static se.leap.bitmaskclient.providersetup.ProviderAPI.UPDATE_INVALID_VPN import static se.leap.bitmaskclient.providersetup.ProviderAPI.USER_MESSAGE; import android.app.Activity; -import android.content.ComponentName; import android.content.Context; import android.content.Intent; -import android.content.ServiceConnection; import android.content.SharedPreferences; import android.graphics.drawable.Animatable; -import android.graphics.drawable.Animatable2; import android.graphics.drawable.Drawable; import android.os.Bundle; -import android.os.IBinder; import android.text.Spannable; import android.text.SpannableString; import android.text.TextUtils; @@ -65,17 +60,13 @@ import androidx.core.content.ContextCompat; import androidx.fragment.app.DialogFragment; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentTransaction; -import androidx.vectordrawable.graphics.drawable.Animatable2Compat; import androidx.vectordrawable.graphics.drawable.Animatable2Compat.AnimationCallback; import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat; import java.util.Observable; import java.util.Observer; -import java.util.concurrent.atomic.AtomicBoolean; import de.blinkt.openvpn.core.ConnectionStatus; -import de.blinkt.openvpn.core.IOpenVPNServiceInternal; -import de.blinkt.openvpn.core.OpenVPNService; import de.blinkt.openvpn.core.VpnStatus; import de.blinkt.openvpn.core.connection.Connection; import se.leap.bitmaskclient.R; @@ -129,10 +120,6 @@ public class EipFragment extends Fragment implements Observer { //------------------------ AlertDialog alertDialog; - private IOpenVPNServiceInternal mService; - // We use this service connection to detect if openvpn is running without network - private EipFragmentServiceConnection openVpnConnection; - @Override public void onAttach(Context context) { super.onAttach(context); @@ -166,7 +153,6 @@ public class EipFragment extends Fragment implements Observer { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - openVpnConnection = new EipFragmentServiceConnection(); eipStatus = EipStatus.getInstance(); providerObservable = ProviderObservable.getInstance(); torStatusObservable = TorStatusObservable.getInstance(); @@ -233,16 +219,14 @@ public class EipFragment extends Fragment implements Observer { @Override public void onResume() { super.onResume(); - if (!eipStatus.isDisconnected()) { - openVpnConnection.bindService(); - } + Log.d(TAG, "onResume"); handleNewState(); } @Override public void onPause() { super.onPause(); - openVpnConnection.unbindService(); + Log.d(TAG, "onPause"); } @Override @@ -270,6 +254,8 @@ public class EipFragment extends Fragment implements Observer { @Override public void onDestroyView() { super.onDestroyView(); + Log.d(TAG, "onDestroyView"); + Activity activity = getActivity(); if (activity != null) { ((MainActivity) activity).setDefaultActivityBarColor(); @@ -290,7 +276,7 @@ public class EipFragment extends Fragment implements Observer { } void handleIcon() { - if (isOpenVpnRunningWithoutNetwork() || eipStatus.isConnected() || eipStatus.isConnecting() || eipStatus.isUpdatingVpnCert()) + if (eipStatus.isVPNRunningWithoutNetwork() || eipStatus.isConnected() || eipStatus.isConnecting() || eipStatus.isUpdatingVpnCert()) handleSwitchOff(); else handleSwitchOn(); @@ -326,7 +312,7 @@ public class EipFragment extends Fragment implements Observer { } private void handleSwitchOff() { - if (isOpenVpnRunningWithoutNetwork() || eipStatus.isConnecting() || eipStatus.isUpdatingVpnCert()) { + if (eipStatus.isVPNRunningWithoutNetwork() || eipStatus.isConnecting() || eipStatus.isUpdatingVpnCert()) { askPendingStartCancellation(); } else if (eipStatus.isConnected()) { askToStopEIP(); @@ -420,13 +406,6 @@ public class EipFragment extends Fragment implements Observer { eipStatus = (EipStatus) observable; handleNewStateOnMain(); - if (eipStatus.isConnecting()) { - openVpnConnection.bindService(); - } - if ("NOPROCESS".equals(EipStatus.getInstance().getState())) { - //assure that the Service is shutdown completely if openvpn was stopped - openVpnConnection.unbindService(); - } } else if (observable instanceof ProviderObservable) { provider = ((ProviderObservable) observable).getCurrentProvider(); } else if (observable instanceof TorStatusObservable && EipStatus.getInstance().isUpdatingVpnCert()) { @@ -511,7 +490,7 @@ public class EipFragment extends Fragment implements Observer { background.setImageResource(R.drawable.bg_connected); animateState(R.drawable.state_connected); setActivityBarColor(R.color.bg_running_top, R.color.bg_running_top_light_transparent); - } else if(isOpenVpnRunningWithoutNetwork()) { + } else if(eipStatus.isVPNRunningWithoutNetwork()) { Log.d(TAG, "eip fragment eipStatus - isOpenVpnRunningWithoutNetwork"); setMainButtonEnabled(true); mainButton.updateState(true, false, true); @@ -614,19 +593,6 @@ public class EipFragment extends Fragment implements Observer { } } - private boolean isOpenVpnRunningWithoutNetwork() { - boolean isRunning = false; - try { - isRunning = eipStatus.getLevel() == LEVEL_NONETWORK && - mService.isVpnRunning(); - } catch (Exception e) { - //eat me - e.printStackTrace(); - } - - return isRunning; - } - private void updateInvalidVpnCertificate() { eipStatus.setUpdatingVpnCert(true); ProviderAPICommand.execute(getContext(), UPDATE_INVALID_VPN_CERTIFICATE, provider); @@ -646,52 +612,6 @@ public class EipFragment extends Fragment implements Observer { } } - private class EipFragmentServiceConnection implements ServiceConnection { - private final AtomicBoolean bind = new AtomicBoolean(false); - - void bindService() { - Activity activity = getActivity(); - if (activity == null) { - Log.e(TAG, "activity is null when binding OpenVpn"); - return; - } - if (!bind.get()) { - activity.runOnUiThread(() -> { - Intent intent = new Intent(activity, OpenVPNService.class); - intent.setAction(OpenVPNService.START_SERVICE); - - activity.bindService(intent, EipFragmentServiceConnection.this, Context.BIND_AUTO_CREATE); - bind.set(true); - }); - } - } - - void unbindService() { - Activity activity = getActivity(); - if (activity == null) { - return; - } - if (bind.get()) { - activity.runOnUiThread(() -> { - activity.unbindService(EipFragmentServiceConnection.this); - bind.set(false); - }); - } - } - - @Override - public void onServiceConnected(ComponentName className, - IBinder service) { - mService = IOpenVPNServiceInternal.Stub.asInterface(service); - handleNewState(); - } - - @Override - public void onServiceDisconnected(ComponentName arg0) { - mService = null; - } - } - public void showDonationReminderDialog() { try { FragmentTransaction fragmentTransaction = new FragmentManagerEnhanced( diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/EipStatus.java b/app/src/main/java/se/leap/bitmaskclient/eip/EipStatus.java index c9cf6041..9244f531 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/EipStatus.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/EipStatus.java @@ -16,6 +16,8 @@ */ package se.leap.bitmaskclient.eip; +import static de.blinkt.openvpn.core.ConnectionStatus.LEVEL_NONETWORK; + import android.content.Context; import android.os.AsyncTask; import androidx.annotation.VisibleForTesting; @@ -92,6 +94,11 @@ public class EipStatus extends Observable implements VpnStatus.StateListener { return "RECONNECTING".equals(currentStatus.getState()); } + public boolean isVPNRunningWithoutNetwork() { + return currentStatus.getLevel() == LEVEL_NONETWORK && + !"NO_PROCESS".equals(currentStatus.getState()); + } + private void setEipLevel(ConnectionStatus level) { switch (level) { case LEVEL_CONNECTED: -- cgit v1.2.3 From 27c380f0c6cef8f18219726045b8c22c8a990c67 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Wed, 14 Dec 2022 14:07:29 +0100 Subject: remove superfluous parameter in MainButtons update method --- .../leap/bitmaskclient/base/fragments/EipFragment.java | 16 +++++++++------- .../se/leap/bitmaskclient/base/views/MainButton.java | 2 +- 2 files changed, 10 insertions(+), 8 deletions(-) (limited to 'app/src/main/java') diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java index c5ed7d12..66f976f6 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java @@ -459,7 +459,7 @@ public class EipFragment extends Fragment implements Observer { } background.setImageResource(R.drawable.bg_connecting); animateState(R.drawable.state_connecting); - mainButton.updateState(false, true, false); + mainButton.updateState(false, true); setActivityBarColor(R.color.bg_connecting_top, R.color.bg_connecting_top_light_transparent); } else if (eipStatus.isConnecting()) { setMainButtonEnabled(true); @@ -475,11 +475,11 @@ public class EipFragment extends Fragment implements Observer { subDescription.setText(null); background.setImageResource(R.drawable.bg_connecting); animateState(R.drawable.state_connecting); - mainButton.updateState(false, true, false); + mainButton.updateState(false, true); setActivityBarColor(R.color.bg_connecting_top, R.color.bg_connecting_top_light_transparent); } else if (eipStatus.isConnected()) { setMainButtonEnabled(true); - mainButton.updateState(true, false, false); + mainButton.updateState(true, false); Connection.TransportType transportType = PreferenceHelper.getUseBridges(getContext()) ? Connection.TransportType.OBFS4 : Connection.TransportType.OPENVPN; locationButton.setLocationLoad(PreferenceHelper.useObfuscationPinning(getContext()) ? GatewaysManager.Load.UNKNOWN : gatewaysManager.getLoadForLocation(VpnStatus.getLastConnectedVpnName(), transportType)); locationButton.setText(VpnStatus.getLastConnectedVpnName()); @@ -493,7 +493,7 @@ public class EipFragment extends Fragment implements Observer { } else if(eipStatus.isVPNRunningWithoutNetwork()) { Log.d(TAG, "eip fragment eipStatus - isOpenVpnRunningWithoutNetwork"); setMainButtonEnabled(true); - mainButton.updateState(true, false, true); + mainButton.updateState(false, true); locationButton.setText(VpnStatus.getCurrentlyConnectingVpnName()); locationButton.showBridgeIndicator(VpnStatus.isUsingBridges()); locationButton.showBridgeIndicator(VpnStatus.isUsingBridges()); @@ -504,6 +504,8 @@ public class EipFragment extends Fragment implements Observer { animateState(R.drawable.state_connecting); setActivityBarColor(R.color.bg_connecting_top, R.color.bg_connecting_top_light_transparent); } else if (eipStatus.isDisconnected() && reconnectingWithDifferentGateway()) { + setMainButtonEnabled(true); + mainButton.updateState(false, true); locationButton.setText(VpnStatus.getCurrentlyConnectingVpnName()); locationButton.setLocationLoad(UNKNOWN); locationButton.showBridgeIndicator(false); @@ -515,7 +517,7 @@ public class EipFragment extends Fragment implements Observer { setActivityBarColor(R.color.bg_connecting_top, R.color.bg_connecting_top_light_transparent); } else if (eipStatus.isDisconnecting()) { setMainButtonEnabled(false); - mainButton.updateState(false, false, false); + mainButton.updateState(false, false); mainDescription.setText(R.string.eip_status_unsecured); background.setImageResource(R.drawable.bg_disconnected); if (previousEipLevel == EipStatus.EipLevel.CONNECTED) { @@ -526,7 +528,7 @@ public class EipFragment extends Fragment implements Observer { setActivityBarColor(R.color.bg_disconnected_top, R.color.bg_disconnected_top_light_transparent); } else if (eipStatus.isBlocking()) { setMainButtonEnabled(true); - mainButton.updateState(false, true, true); + mainButton.updateState(false, true); locationButton.setText(R.string.no_location); locationButton.setLocationLoad(UNKNOWN); locationButton.showBridgeIndicator(false); @@ -539,7 +541,7 @@ public class EipFragment extends Fragment implements Observer { } else { locationButton.setText(R.string.vpn_button_turn_on); setMainButtonEnabled(true); - mainButton.updateState(false, false, false); + mainButton.updateState(false, false); locationButton.setLocationLoad(UNKNOWN); locationButton.showBridgeIndicator(false); String city = getPreferredCity(getContext()); diff --git a/app/src/main/java/se/leap/bitmaskclient/base/views/MainButton.java b/app/src/main/java/se/leap/bitmaskclient/base/views/MainButton.java index 715063b5..fc86fc0b 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/views/MainButton.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/views/MainButton.java @@ -45,7 +45,7 @@ public class MainButton extends RelativeLayout { button = binding.button; } - public void updateState(boolean isOn, boolean isProcessing, boolean isError) { + public void updateState(boolean isOn, boolean isProcessing) { if (isProcessing) { button.setImageDrawable(ContextCompat.getDrawable(getContext(), R.drawable.button_circle_cancel)); } else { -- cgit v1.2.3 From dc5338510457ace0bbd0b98b135e14be8e850ecf Mon Sep 17 00:00:00 2001 From: cyBerta Date: Wed, 14 Dec 2022 14:48:24 +0100 Subject: null explicitely service openvpn serviceconnections after they've been closed --- app/src/main/java/se/leap/bitmaskclient/eip/EIP.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'app/src/main/java') diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/EIP.java b/app/src/main/java/se/leap/bitmaskclient/eip/EIP.java index b3efd21f..88cdc715 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/EIP.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/EIP.java @@ -594,7 +594,7 @@ public final class EIP extends JobIntentService implements Observer { } public static class VoidVpnServiceConnection implements Closeable { - private final Context context; + private Context context; private ServiceConnection serviceConnection; private VoidVpnService voidVpnService; @@ -608,6 +608,9 @@ public final class EIP extends JobIntentService implements Observer { @Override public void close() { context.unbindService(serviceConnection); + serviceConnection = null; + voidVpnService = null; + context = null; } private void initSynchronizedServiceConnection(final Context context) throws InterruptedException { @@ -649,7 +652,7 @@ public final class EIP extends JobIntentService implements Observer { */ @WorkerThread public static class OpenVpnServiceConnection implements Closeable { - private final Context context; + private Context context; private ServiceConnection serviceConnection; private IOpenVPNServiceInternal service; @@ -686,6 +689,9 @@ public final class EIP extends JobIntentService implements Observer { @Override public void close() { context.unbindService(serviceConnection); + serviceConnection = null; + service = null; + context = null; } public IOpenVPNServiceInternal getService() { -- cgit v1.2.3 From e090b6dd60daca11603b36a197dfe5b05ecc3cb9 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Thu, 15 Dec 2022 15:11:22 +0100 Subject: center and capitalize actionbar title, in Bitmask, center but not capitalize title in riseupvpn, allow to configure both properties on compile time in build.gradle --- .../se/leap/bitmaskclient/base/MainActivity.java | 96 ++++++++-------------- .../base/fragments/AboutFragment.java | 4 +- .../bitmaskclient/base/fragments/EipFragment.java | 15 +--- .../base/fragments/ExcludeAppsFragment.java | 2 +- .../base/fragments/GatewaySelectionFragment.java | 5 +- .../bitmaskclient/base/fragments/LogFragment.java | 11 ++- .../base/fragments/NavigationDrawerFragment.java | 55 +------------ .../base/fragments/SettingsFragment.java | 4 +- .../leap/bitmaskclient/base/utils/ViewHelper.java | 80 +++++++++++++++++- .../bitmaskclient/base/views/ActionBarTitle.java | 96 ++++++++++++++++++++++ 10 files changed, 224 insertions(+), 144 deletions(-) create mode 100644 app/src/main/java/se/leap/bitmaskclient/base/views/ActionBarTitle.java (limited to 'app/src/main/java') diff --git a/app/src/main/java/se/leap/bitmaskclient/base/MainActivity.java b/app/src/main/java/se/leap/bitmaskclient/base/MainActivity.java index f56f2223..9225755e 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/MainActivity.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/MainActivity.java @@ -17,6 +17,7 @@ package se.leap.bitmaskclient.base; +import static androidx.appcompat.app.ActionBar.DISPLAY_SHOW_CUSTOM; import static se.leap.bitmaskclient.R.string.downloading_vpn_certificate_failed; import static se.leap.bitmaskclient.R.string.vpn_certificate_user_message; import static se.leap.bitmaskclient.base.models.Constants.ASK_TO_CANCEL_VPN; @@ -34,7 +35,6 @@ import static se.leap.bitmaskclient.base.models.Constants.REQUEST_CODE_LOG_IN; import static se.leap.bitmaskclient.base.models.Constants.REQUEST_CODE_SWITCH_PROVIDER; import static se.leap.bitmaskclient.base.models.Constants.SHARED_PREFERENCES; import static se.leap.bitmaskclient.base.utils.PreferenceHelper.storeProviderInPreferences; -import static se.leap.bitmaskclient.base.utils.ViewHelper.isBrightColor; import static se.leap.bitmaskclient.eip.EIP.EIPErrors.ERROR_INVALID_VPN_CERTIFICATE; import static se.leap.bitmaskclient.eip.EIP.EIPErrors.ERROR_VPN_PREPARE; import static se.leap.bitmaskclient.providersetup.ProviderAPI.ERRORID; @@ -46,17 +46,14 @@ import static se.leap.bitmaskclient.providersetup.ProviderAPI.TOR_TIMEOUT; import static se.leap.bitmaskclient.providersetup.ProviderAPI.UPDATE_INVALID_VPN_CERTIFICATE; import static se.leap.bitmaskclient.providersetup.ProviderAPI.USER_MESSAGE; +import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; -import android.graphics.drawable.ColorDrawable; -import android.os.Build; import android.os.Bundle; import android.util.Log; -import android.view.Window; -import android.view.WindowManager; +import android.view.Gravity; -import androidx.annotation.ColorRes; -import androidx.annotation.StringRes; +import androidx.annotation.ColorInt; import androidx.appcompat.app.ActionBar; import androidx.appcompat.app.AppCompatActivity; import androidx.core.content.ContextCompat; @@ -70,6 +67,7 @@ import org.json.JSONObject; import java.util.Observable; import java.util.Observer; +import se.leap.bitmaskclient.BuildConfig; import se.leap.bitmaskclient.R; import se.leap.bitmaskclient.base.fragments.EipFragment; import se.leap.bitmaskclient.base.fragments.ExcludeAppsFragment; @@ -81,7 +79,7 @@ import se.leap.bitmaskclient.base.fragments.SettingsFragment; import se.leap.bitmaskclient.base.models.Provider; import se.leap.bitmaskclient.base.models.ProviderObservable; import se.leap.bitmaskclient.base.utils.PreferenceHelper; -import se.leap.bitmaskclient.base.utils.ViewHelper; +import se.leap.bitmaskclient.base.views.ActionBarTitle; import se.leap.bitmaskclient.eip.EIP; import se.leap.bitmaskclient.eip.EipCommand; import se.leap.bitmaskclient.eip.EipSetupListener; @@ -103,8 +101,6 @@ public class MainActivity extends AppCompatActivity implements EipSetupListener, public final static String ACTION_SHOW_DIALOG_FRAGMENT = "action_show_dialog_fragment"; public final static String ACTION_SHOW_MOTD_FRAGMENT = "action_show_motd_fragment"; - private @ColorRes int actionBarTextColor = R.color.colorActionBarTitleFont; - /** * Fragment managing the behaviors, interactions and presentation of the navigation drawer. */ @@ -113,8 +109,7 @@ public class MainActivity extends AppCompatActivity implements EipSetupListener, protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.a_main); - setSupportActionBar(findViewById(R.id.toolbar)); - + setupActionBar(); navigationDrawerFragment = (NavigationDrawerFragment) getSupportFragmentManager().findFragmentById(R.id.navigation_drawer); @@ -143,7 +138,6 @@ public class MainActivity extends AppCompatActivity implements EipSetupListener, newFragment.setArguments(bundle); } fragmentManagerEnhanced.replace(R.id.main_container, newFragment, MainActivity.TAG); - hideActionBarSubTitle(); } else { super.onBackPressed(); } @@ -171,7 +165,6 @@ public class MainActivity extends AppCompatActivity implements EipSetupListener, } bundle.putParcelable(PROVIDER_KEY, provider); fragment.setArguments(bundle); - hideActionBarSubTitle(); showActionBar(); break; case ACTION_SHOW_MOTD_FRAGMENT: @@ -181,12 +174,10 @@ public class MainActivity extends AppCompatActivity implements EipSetupListener, motdBundle.putString(EXTRA_MOTD_MSG, intent.getStringExtra(EXTRA_MOTD_MSG)); } fragment.setArguments(motdBundle); - hideActionBarSubTitle(); hideActionBar(); break; case ACTION_SHOW_LOG_FRAGMENT: fragment = new LogFragment(); - setActionBarTitle(R.string.log_fragment_title); showActionBar(); break; case ACTION_SHOW_DIALOG_FRAGMENT: @@ -209,6 +200,31 @@ public class MainActivity extends AppCompatActivity implements EipSetupListener, } } + private void setupActionBar() { + setSupportActionBar(findViewById(R.id.toolbar)); + final ActionBar actionBar = getSupportActionBar(); + Context context = actionBar.getThemedContext(); + actionBar.setDisplayOptions(DISPLAY_SHOW_CUSTOM); + + ActionBarTitle actionBarTitle = new ActionBarTitle(context); + actionBarTitle.setTitleCaps(BuildConfig.actionbar_capitalize_title); + actionBarTitle.setTitle(getString(R.string.app_name)); + + @ColorInt int titleColor = ContextCompat.getColor(context, R.color.colorActionBarTitleFont); + actionBarTitle.setTitleTextColor(titleColor); + + actionBarTitle.setCentered(BuildConfig.actionbar_center_title); + if (BuildConfig.actionbar_center_title) { + ActionBar.LayoutParams params = new ActionBar.LayoutParams( + ActionBar.LayoutParams.WRAP_CONTENT, + ActionBar.LayoutParams.MATCH_PARENT, + Gravity.CENTER); + actionBar.setCustomView(actionBarTitle, params); + } else { + actionBar.setCustomView(actionBarTitle); + } + } + private void hideActionBar() { ActionBar actionBar = getSupportActionBar(); if (actionBar != null) { @@ -223,53 +239,6 @@ public class MainActivity extends AppCompatActivity implements EipSetupListener, } } - private void hideActionBarSubTitle() { - ActionBar actionBar = getSupportActionBar(); - if (actionBar != null) { - actionBar.setSubtitle(null); - } - } - private void setActionBarTitle(@StringRes int stringId) { - ActionBar actionBar = getSupportActionBar(); - if (actionBar != null) { - actionBar.setSubtitle(stringId); - } - } - - public @ColorRes int getActionBarTitleColor() { - return actionBarTextColor; - } - - public void setDefaultActivityBarColor() { - setActivityBarColor(R.color.colorPrimary, R.color.colorPrimaryDark, R.color.colorActionBarTitleFont); - } - - public void setActivityBarColor(@ColorRes int primaryColor, @ColorRes int secondaryColor, @ColorRes int textColor) { - ActionBar bar = getSupportActionBar(); - if (bar == null) { - return; - } - int color = ContextCompat.getColor(this, secondaryColor); - bar.setBackgroundDrawable(new ColorDrawable(color)); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - Window window = this.getWindow(); - window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); - window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); - window.setStatusBarColor(ContextCompat.getColor(this, primaryColor)); - } - - if (bar.getTitle() == null) { - return; - } - - if (textColor == 0) { - actionBarTextColor = isBrightColor(color) ? R.color.actionbar_connectivity_state_text_color_dark : R.color.actionbar_connectivity_state_text_color_light; - } else { - actionBarTextColor = textColor; - } - - ViewHelper.setActionBarTextColor(bar, actionBarTextColor); - } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { @@ -313,7 +282,6 @@ public class MainActivity extends AppCompatActivity implements EipSetupListener, fragment.setArguments(arguments); new FragmentManagerEnhanced(getSupportFragmentManager()) .replace(R.id.main_container, fragment, MainActivity.TAG); - hideActionBarSubTitle(); } @Override diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/AboutFragment.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/AboutFragment.java index 646637b9..e92aa703 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/AboutFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/AboutFragment.java @@ -18,7 +18,7 @@ import se.leap.bitmaskclient.R; import static android.view.View.VISIBLE; import static se.leap.bitmaskclient.R.string.about_fragment_title; -import static se.leap.bitmaskclient.base.utils.ViewHelper.setActionBarTitle; +import static se.leap.bitmaskclient.base.utils.ViewHelper.setActionBarSubtitle; public class AboutFragment extends Fragment { @@ -36,7 +36,7 @@ public class AboutFragment extends Fragment { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.f_about, container, false); unbinder = ButterKnife.bind(this, view); - setActionBarTitle(this, about_fragment_title); + setActionBarSubtitle(this, about_fragment_title); return view; } diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java index 66f976f6..409efcf0 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java @@ -75,6 +75,7 @@ import se.leap.bitmaskclient.base.MainActivity; import se.leap.bitmaskclient.base.models.Provider; import se.leap.bitmaskclient.base.models.ProviderObservable; import se.leap.bitmaskclient.base.utils.PreferenceHelper; +import se.leap.bitmaskclient.base.utils.ViewHelper; import se.leap.bitmaskclient.base.views.LocationButton; import se.leap.bitmaskclient.base.views.MainButton; import se.leap.bitmaskclient.databinding.FEipBinding; @@ -164,8 +165,6 @@ public class EipFragment extends Fragment implements Observer { } gatewaysManager = new GatewaysManager(getContext()); - - } @Override @@ -178,6 +177,7 @@ public class EipFragment extends Fragment implements Observer { mainDescription = binding.mainDescription; subDescription = binding.subDescription; stateView = binding.stateView; + ViewHelper.setActionBarTitle(this, R.string.app_name); eipStatus.addObserver(this); torStatusObservable.addObserver(this); @@ -256,10 +256,7 @@ public class EipFragment extends Fragment implements Observer { super.onDestroyView(); Log.d(TAG, "onDestroyView"); - Activity activity = getActivity(); - if (activity != null) { - ((MainActivity) activity).setDefaultActivityBarColor(); - } + ViewHelper.setDefaultActivityBarColor(getActivity()); eipStatus.deleteObserver(this); providerObservable.deleteObserver(this); torStatusObservable.deleteObserver(this); @@ -423,11 +420,7 @@ public class EipFragment extends Fragment implements Observer { } private void setActivityBarColor(@ColorRes int primaryColor, @ColorRes int secondaryColor) { - Activity activity = getActivity(); - if (activity == null) { - return; - } - ((MainActivity) getActivity()).setActivityBarColor(primaryColor, secondaryColor, R.color.actionbar_connectivity_state_text_color_dark); + ViewHelper.setActivityBarColor(getActivity(), primaryColor, secondaryColor, R.color.actionbar_connectivity_state_text_color_dark); } private void handleNewState() { diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/ExcludeAppsFragment.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/ExcludeAppsFragment.java index 1574dbb0..98c2e438 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/ExcludeAppsFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/ExcludeAppsFragment.java @@ -312,7 +312,7 @@ public class ExcludeAppsFragment extends Fragment implements AdapterView.OnItemC mListView.setOnItemClickListener(this); mListView.setEmptyView(v.findViewById(R.id.loading_container)); - ViewHelper.setActionBarTitle(this, exclude_apps_fragment_title); + ViewHelper.setActionBarSubtitle(this, exclude_apps_fragment_title); new Thread(() -> mListAdapter.populateList(getActivity())).start(); 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 00bd55ef..749ffd9f 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 @@ -52,7 +52,6 @@ import se.leap.bitmaskclient.eip.GatewaysManager; import static android.content.Context.MODE_PRIVATE; import static android.view.View.GONE; import static android.view.View.VISIBLE; -import static de.blinkt.openvpn.core.connection.Connection.TransportType.OBFS4; import static de.blinkt.openvpn.core.connection.Connection.TransportType.OPENVPN; import static de.blinkt.openvpn.core.connection.Connection.TransportType.PT; import static se.leap.bitmaskclient.base.MainActivity.ACTION_SHOW_VPN_FRAGMENT; @@ -60,7 +59,7 @@ import static se.leap.bitmaskclient.base.models.Constants.SHARED_PREFERENCES; import static se.leap.bitmaskclient.base.models.Constants.USE_BRIDGES; import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getUseBridges; import static se.leap.bitmaskclient.base.utils.PreferenceHelper.useBridges; -import static se.leap.bitmaskclient.base.utils.ViewHelper.setActionBarTitle; +import static se.leap.bitmaskclient.base.utils.ViewHelper.setActionBarSubtitle; interface LocationListSelectionListener { void onLocationManuallySelected(Location location); @@ -109,7 +108,7 @@ public class GatewaySelectionFragment extends Fragment implements Observer, Loca initRecyclerView(); initRecommendedLocationEntry(); initBridgesHint(view); - setActionBarTitle(this, R.string.gateway_selection_title); + setActionBarSubtitle(this, R.string.gateway_selection_title); } @Override diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/LogFragment.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/LogFragment.java index 6f0f29ef..8f73595d 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/LogFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/LogFragment.java @@ -5,6 +5,10 @@ package se.leap.bitmaskclient.base.fragments; +import static de.blinkt.openvpn.core.OpenVPNService.humanReadableByteCount; +import static se.leap.bitmaskclient.R.string.log_fragment_title; +import static se.leap.bitmaskclient.base.utils.ViewHelper.setActionBarSubtitle; + import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; @@ -59,10 +63,6 @@ import de.blinkt.openvpn.core.VpnStatus.StateListener; import se.leap.bitmaskclient.R; import se.leap.bitmaskclient.base.models.Constants; -import static de.blinkt.openvpn.core.OpenVPNService.humanReadableByteCount; -import static se.leap.bitmaskclient.R.string.log_fragment_title; -import static se.leap.bitmaskclient.base.utils.ViewHelper.setActionBarTitle; - public class LogFragment extends ListFragment implements StateListener, SeekBar.OnSeekBarChangeListener, RadioGroup.OnCheckedChangeListener, VpnStatus.ByteCountListener { public static final String TAG = LogFragment.class.getSimpleName(); private static final String LOGTIMEFORMAT = "logtimeformat"; @@ -533,7 +533,7 @@ public class LogFragment extends ListFragment implements StateListener, SeekBar. if (mShowOptionsLayout) mOptionsLayout.setVisibility(View.VISIBLE); - setActionBarTitle(this, log_fragment_title); + setActionBarSubtitle(this, log_fragment_title); return v; } @@ -557,7 +557,6 @@ public class LogFragment extends ListFragment implements StateListener, SeekBar. @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - } diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/NavigationDrawerFragment.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/NavigationDrawerFragment.java index 5c4e891e..68435fec 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/NavigationDrawerFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/NavigationDrawerFragment.java @@ -38,9 +38,6 @@ import android.content.res.Configuration; import android.net.Uri; import android.os.Bundle; import android.os.Handler; -import android.text.Spannable; -import android.text.SpannableString; -import android.text.style.ForegroundColorSpan; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; @@ -48,15 +45,11 @@ import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; -import androidx.annotation.ColorRes; import androidx.annotation.NonNull; -import androidx.appcompat.app.ActionBar; import androidx.appcompat.app.ActionBarDrawerToggle; import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.widget.Toolbar; -import androidx.appcompat.widget.ViewUtils; -import androidx.core.content.ContextCompat; import androidx.core.view.GravityCompat; import androidx.drawerlayout.widget.DrawerLayout; import androidx.fragment.app.Fragment; @@ -70,7 +63,6 @@ import se.leap.bitmaskclient.base.FragmentManagerEnhanced; import se.leap.bitmaskclient.base.MainActivity; import se.leap.bitmaskclient.base.models.Provider; import se.leap.bitmaskclient.base.models.ProviderObservable; -import se.leap.bitmaskclient.base.utils.ViewHelper; import se.leap.bitmaskclient.base.views.IconSwitchEntry; import se.leap.bitmaskclient.base.views.IconTextEntry; import se.leap.bitmaskclient.eip.EipStatus; @@ -179,7 +171,6 @@ public class NavigationDrawerFragment extends Fragment implements SharedPreferen this.drawerLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START); toolbar = this.drawerLayout.findViewById(R.id.toolbar); - setupActionBar(); setupEntries(); setupActionBarDrawerToggle(activity); @@ -240,7 +231,6 @@ public class NavigationDrawerFragment extends Fragment implements SharedPreferen Bundle arguments = new Bundle(); arguments.putParcelable(PROVIDER_KEY, currentProvider); fragment.setArguments(arguments); - hideActionBarSubTitle(); fragmentManager.replace(R.id.main_container, fragment, MainActivity.TAG); closeDrawer(); }); @@ -355,15 +345,7 @@ public class NavigationDrawerFragment extends Fragment implements SharedPreferen } } - private ActionBar setupActionBar() { - AppCompatActivity activity = (AppCompatActivity) getActivity(); - activity.setSupportActionBar(toolbar); - final ActionBar actionBar = activity.getSupportActionBar(); - actionBar.setDisplayHomeAsUpEnabled(true); - actionBar.setHomeButtonEnabled(true); - actionBar.setDisplayShowTitleEnabled(true); - return actionBar; - } + @NonNull private void closeDrawerWithDelay() { @@ -424,14 +406,6 @@ public class NavigationDrawerFragment extends Fragment implements SharedPreferen drawerToggle.onConfigurationChanged(newConfig); } - @Override - public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { - if (drawerLayout != null && isDrawerOpen()) { - showGlobalContextActionBar(); - } - super.onCreateOptionsMenu(menu, inflater); - } - @Override public boolean onOptionsItemSelected(MenuItem item) { if (drawerToggle.onOptionsItemSelected(item)) { @@ -446,33 +420,6 @@ public class NavigationDrawerFragment extends Fragment implements SharedPreferen preferences.unregisterOnSharedPreferenceChangeListener(this); } - /** - * Per the navigation drawer design guidelines, updates the action bar to show the global app - * 'context', rather than just what's in the current screen. - */ - private void showGlobalContextActionBar() { - ActionBar actionBar = getActionBar(); - actionBar.setDisplayShowTitleEnabled(true); - actionBar.setTitle(R.string.app_name); - Activity activity = getActivity(); - if (activity == null) { - return; - } - @ColorRes int titleColor = ((MainActivity) activity).getActionBarTitleColor(); - ViewHelper.setActionBarTextColor(actionBar, titleColor); - } - - private ActionBar getActionBar() { - return ((AppCompatActivity) getActivity()).getSupportActionBar(); - } - - private void hideActionBarSubTitle() { - ActionBar actionBar = getActionBar(); - if (actionBar != null) { - actionBar.setSubtitle(null); - } - } - public void refresh() { Provider currentProvider = ProviderObservable.getInstance().getCurrentProvider(); account.setText(currentProvider.getName()); diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/SettingsFragment.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/SettingsFragment.java index f7d20aa9..d5bbd2c5 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/SettingsFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/SettingsFragment.java @@ -24,7 +24,7 @@ import static se.leap.bitmaskclient.base.utils.PreferenceHelper.setUseObfuscatio import static se.leap.bitmaskclient.base.utils.PreferenceHelper.useBridges; import static se.leap.bitmaskclient.base.utils.PreferenceHelper.useObfuscationPinning; import static se.leap.bitmaskclient.base.utils.PreferenceHelper.useSnowflake; -import static se.leap.bitmaskclient.base.utils.ViewHelper.setActionBarTitle; +import static se.leap.bitmaskclient.base.utils.ViewHelper.setActionBarSubtitle; import android.app.AlertDialog; import android.content.Context; @@ -90,7 +90,7 @@ public class SettingsFragment extends Fragment implements SharedPreferences.OnSh initGatewayPinningEntry(view); initExperimentalTransportsEntry(view); initObfuscationPinningEntry(view); - setActionBarTitle(this, advanced_settings); + setActionBarSubtitle(this, advanced_settings); return view; } diff --git a/app/src/main/java/se/leap/bitmaskclient/base/utils/ViewHelper.java b/app/src/main/java/se/leap/bitmaskclient/base/utils/ViewHelper.java index bbd77c36..8f4d7862 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/utils/ViewHelper.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/utils/ViewHelper.java @@ -1,30 +1,63 @@ package se.leap.bitmaskclient.base.utils; +import android.app.Activity; import android.app.Notification; import android.content.Context; import android.graphics.Color; +import android.graphics.drawable.ColorDrawable; +import android.os.Build; import android.text.Spannable; import android.text.SpannableString; import android.text.style.ForegroundColorSpan; +import android.util.Log; +import android.view.View; +import android.view.Window; +import android.view.WindowManager; import androidx.annotation.ColorRes; import androidx.annotation.DimenRes; import androidx.annotation.StringRes; import androidx.appcompat.app.ActionBar; import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.widget.AppCompatTextView; import androidx.core.content.ContextCompat; import androidx.fragment.app.Fragment; +import se.leap.bitmaskclient.R; +import se.leap.bitmaskclient.base.views.ActionBarTitle; + /** * Created by cyberta on 29.06.18. */ public class ViewHelper { + private static final String TAG = ViewHelper.class.getSimpleName(); + public static int convertDimensionToPx(Context context, @DimenRes int dimension) { return context.getResources().getDimensionPixelSize(dimension); } + /** + * Sets the subtitle of an activities action bar. The activity needs to be an AppCompatActivity. + * @param fragment + * @param stringId + */ + public static void setActionBarSubtitle(Fragment fragment, @StringRes int stringId) { + AppCompatActivity appCompatActivity = (AppCompatActivity) fragment.getActivity(); + if (appCompatActivity != null) { + ActionBar actionBar = appCompatActivity.getSupportActionBar(); + if (actionBar != null) { + View customView = actionBar.getCustomView(); + if (customView instanceof ActionBarTitle) { + ActionBarTitle actionBarTitle = (ActionBarTitle) customView; + actionBarTitle.setSubtitle(stringId); + actionBarTitle.showSubtitle(true); + } + } + } + } + /** * Sets the subtitle of an activities action bar. The activity needs to be an AppCompatActivity. * @param fragment @@ -35,11 +68,56 @@ public class ViewHelper { if (appCompatActivity != null) { ActionBar actionBar = appCompatActivity.getSupportActionBar(); if (actionBar != null) { - actionBar.setSubtitle(stringId); + View customView = actionBar.getCustomView(); + if (customView instanceof ActionBarTitle) { + ActionBarTitle actionBarTitle = (ActionBarTitle) customView; + actionBarTitle.setTitle(stringId); + actionBarTitle.showSubtitle(false); + } else { + Log.e(TAG, "ActionBar has no custom action title!"); + } } } } + + public static void setDefaultActivityBarColor(Activity activity) { + setActivityBarColor(activity, R.color.colorPrimary, R.color.colorPrimaryDark, R.color.colorActionBarTitleFont); + } + + public static void setActivityBarColor(Activity activity, @ColorRes int primaryColor, @ColorRes int secondaryColor, @ColorRes int textColor) { + if (!(activity instanceof AppCompatActivity)) { + return; + } + + ActionBar bar = ((AppCompatActivity) activity).getSupportActionBar(); + if (bar == null) { + return; + } + int color = ContextCompat.getColor(activity, secondaryColor); + bar.setBackgroundDrawable(new ColorDrawable(color)); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + Window window = activity.getWindow(); + window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); + window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); + window.setStatusBarColor(ContextCompat.getColor(activity, primaryColor)); + } + + int actionBarTextColor; + if (textColor == 0) { + actionBarTextColor = isBrightColor(color) ? R.color.actionbar_connectivity_state_text_color_dark : R.color.actionbar_connectivity_state_text_color_light; + } else { + actionBarTextColor = textColor; + } + + View customView = bar.getCustomView(); + if (customView instanceof ActionBarTitle) { + ActionBarTitle actionBarTitle = (ActionBarTitle) customView; + actionBarTitle.setTitleTextColor(ContextCompat.getColor(bar.getThemedContext(), actionBarTextColor)); + } + } + + public static boolean isBrightColor(int color) { if (android.R.color.transparent == color) return true; diff --git a/app/src/main/java/se/leap/bitmaskclient/base/views/ActionBarTitle.java b/app/src/main/java/se/leap/bitmaskclient/base/views/ActionBarTitle.java new file mode 100644 index 00000000..a151305e --- /dev/null +++ b/app/src/main/java/se/leap/bitmaskclient/base/views/ActionBarTitle.java @@ -0,0 +1,96 @@ +package se.leap.bitmaskclient.base.views; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.widget.RelativeLayout; + +import androidx.annotation.ColorInt; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.StringRes; +import androidx.appcompat.widget.AppCompatTextView; +import androidx.appcompat.widget.LinearLayoutCompat; + +import se.leap.bitmaskclient.databinding.VActionbarTitleBinding; + +public class ActionBarTitle extends LinearLayoutCompat { + private AppCompatTextView actionBarTitle; + private AppCompatTextView actionBarSubtitle; + private LinearLayoutCompat container; + + public ActionBarTitle(@NonNull Context context) { + super(context); + initLayout(context); + } + + public ActionBarTitle(@NonNull Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + initLayout(context); + } + + public ActionBarTitle(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + initLayout(context); + } + + public void initLayout(Context context) { + VActionbarTitleBinding binding = VActionbarTitleBinding.inflate(LayoutInflater.from(context), this, true); + actionBarTitle = binding.actionBarTitle; + actionBarSubtitle = binding.actionBarSubtitle; + container = binding.actionBarTitleContainer; + } + + public void setTitle(CharSequence text) { + actionBarTitle.setText(text); + } + + public void setTitleCaps(boolean caps) { + actionBarTitle.setAllCaps(caps); + } + + public void setSubtitle(CharSequence text) { + actionBarSubtitle.setText(text); + } + + public void setTitle(@StringRes int resId) { + actionBarTitle.setText(resId); + } + + public void setSubtitle(@StringRes int resId) { + actionBarSubtitle.setText(resId); + } + + public void setTitleTextColor(@ColorInt int color) { + actionBarTitle.setTextColor(color); + } + + public void setSubtitleTextColor(@ColorInt int color) { + actionBarSubtitle.setTextColor(color); + } + + public void showSubtitle(boolean show) { + actionBarSubtitle.setVisibility(show ? VISIBLE : GONE); + } + + public void setCentered(boolean centered) { + LayoutParams titleLayoutParams = (LayoutParams) actionBarTitle.getLayoutParams(); + LayoutParams subtitleLayoutParams = (LayoutParams) actionBarSubtitle.getLayoutParams(); + LayoutParams containerLayoutParams = (LayoutParams) container.getLayoutParams(); + if (centered) { + titleLayoutParams.gravity = Gravity.CENTER; + subtitleLayoutParams.gravity = Gravity.CENTER; + containerLayoutParams.gravity = Gravity.CENTER; + } else { + titleLayoutParams.gravity = Gravity.NO_GRAVITY; + subtitleLayoutParams.gravity = Gravity.NO_GRAVITY; + containerLayoutParams.gravity = Gravity.NO_GRAVITY; + } + actionBarTitle.setLayoutParams(titleLayoutParams); + actionBarSubtitle.setLayoutParams(subtitleLayoutParams); + container.setLayoutParams(containerLayoutParams); + + + } +} -- cgit v1.2.3