summaryrefslogtreecommitdiff
path: root/app/src/main/java
diff options
context:
space:
mode:
Diffstat (limited to 'app/src/main/java')
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/ConfigHelper.java22
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/Constants.java1
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/DrawerSettingsAdapter.java1
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/drawer/NavigationDrawerFragment.java35
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/fragments/AlwaysOnDialog.java71
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/views/IconTextView.java96
6 files changed, 224 insertions, 2 deletions
diff --git a/app/src/main/java/se/leap/bitmaskclient/ConfigHelper.java b/app/src/main/java/se/leap/bitmaskclient/ConfigHelper.java
index f07a2a23..aaff9ebc 100644
--- a/app/src/main/java/se/leap/bitmaskclient/ConfigHelper.java
+++ b/app/src/main/java/se/leap/bitmaskclient/ConfigHelper.java
@@ -58,12 +58,14 @@ import java.util.Map;
import java.util.Set;
import static android.R.attr.name;
+import static se.leap.bitmaskclient.Constants.ALWAYS_ON_SHOW_DIALOG;
import static se.leap.bitmaskclient.Constants.DEFAULT_SHARED_PREFS_BATTERY_SAVER;
import static se.leap.bitmaskclient.Constants.PREFERENCES_APP_VERSION;
import static se.leap.bitmaskclient.Constants.PROVIDER_CONFIGURED;
import static se.leap.bitmaskclient.Constants.PROVIDER_EIP_DEFINITION;
import static se.leap.bitmaskclient.Constants.PROVIDER_PRIVATE_KEY;
import static se.leap.bitmaskclient.Constants.PROVIDER_VPN_CERTIFICATE;
+import static se.leap.bitmaskclient.Constants.SHARED_PREFERENCES;
/**
* Stores constants, and implements auxiliary methods used across all Bitmask Android classes.
@@ -417,9 +419,27 @@ public class ConfigHelper {
preferences.edit().putBoolean(DEFAULT_SHARED_PREFS_BATTERY_SAVER, isEnabled).apply();
}
- public static boolean getSaveBattery(@NonNull Context context) {
+ public static boolean getSaveBattery(Context context) {
+ if (context == null) {
+ return false;
+ }
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
return preferences.getBoolean(DEFAULT_SHARED_PREFS_BATTERY_SAVER, false);
}
+ public static void saveShowAlwaysOnDialog(Context context, boolean showAlwaysOnDialog) {
+ if (context == null) {
+ return;
+ }
+ SharedPreferences preferences = context.getSharedPreferences(SHARED_PREFERENCES, Context.MODE_PRIVATE);
+ preferences.edit().putBoolean(ALWAYS_ON_SHOW_DIALOG, showAlwaysOnDialog).apply();
+ }
+
+ public static boolean getShowAlwaysOnDialog(Context context) {
+ if (context == null) {
+ return true;
+ }
+ SharedPreferences preferences = context.getSharedPreferences(SHARED_PREFERENCES, Context.MODE_PRIVATE);
+ return preferences.getBoolean(ALWAYS_ON_SHOW_DIALOG, true);
+ }
}
diff --git a/app/src/main/java/se/leap/bitmaskclient/Constants.java b/app/src/main/java/se/leap/bitmaskclient/Constants.java
index 58145015..d719e8d3 100644
--- a/app/src/main/java/se/leap/bitmaskclient/Constants.java
+++ b/app/src/main/java/se/leap/bitmaskclient/Constants.java
@@ -8,6 +8,7 @@ public interface Constants {
String SHARED_PREFERENCES = "LEAPPreferences";
String PREFERENCES_APP_VERSION = "bitmask version";
+ String ALWAYS_ON_SHOW_DIALOG = "DIALOG.ALWAYS_ON_SHOW_DIALOG";
//////////////////////////////////////////////
diff --git a/app/src/main/java/se/leap/bitmaskclient/DrawerSettingsAdapter.java b/app/src/main/java/se/leap/bitmaskclient/DrawerSettingsAdapter.java
index 867f3d48..9b40d36f 100644
--- a/app/src/main/java/se/leap/bitmaskclient/DrawerSettingsAdapter.java
+++ b/app/src/main/java/se/leap/bitmaskclient/DrawerSettingsAdapter.java
@@ -39,6 +39,7 @@ public class DrawerSettingsAdapter extends BaseAdapter {
public static final int LOG = 1;
public static final int ABOUT = 2;
public static final int BATTERY_SAVER = 3;
+ public static final int ALWAYS_ON = 4;
//view types
public final static int VIEW_SIMPLE_TEXT = 0;
diff --git a/app/src/main/java/se/leap/bitmaskclient/drawer/NavigationDrawerFragment.java b/app/src/main/java/se/leap/bitmaskclient/drawer/NavigationDrawerFragment.java
index 6e39e9ed..6102e7e5 100644
--- a/app/src/main/java/se/leap/bitmaskclient/drawer/NavigationDrawerFragment.java
+++ b/app/src/main/java/se/leap/bitmaskclient/drawer/NavigationDrawerFragment.java
@@ -22,9 +22,12 @@ import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Configuration;
+import android.os.Build;
import android.os.Bundle;
+import android.support.v4.app.DialogFragment;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
+import android.support.v4.app.FragmentTransaction;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBar;
@@ -48,6 +51,8 @@ import android.widget.Toast;
import se.leap.bitmaskclient.ConfigHelper;
import se.leap.bitmaskclient.DrawerSettingsAdapter;
import se.leap.bitmaskclient.DrawerSettingsAdapter.DrawerSettingsItem;
+import se.leap.bitmaskclient.FragmentManagerEnhanced;
+import se.leap.bitmaskclient.fragments.AlwaysOnDialog;
import se.leap.bitmaskclient.EipFragment;
import se.leap.bitmaskclient.Provider;
import se.leap.bitmaskclient.ProviderListActivity;
@@ -58,10 +63,12 @@ import se.leap.bitmaskclient.fragments.LogFragment;
import static android.content.Context.MODE_PRIVATE;
import static se.leap.bitmaskclient.BitmaskApp.getRefWatcher;
import static se.leap.bitmaskclient.ConfigHelper.getSaveBattery;
+import static se.leap.bitmaskclient.ConfigHelper.getShowAlwaysOnDialog;
import static se.leap.bitmaskclient.Constants.PROVIDER_KEY;
import static se.leap.bitmaskclient.Constants.REQUEST_CODE_SWITCH_PROVIDER;
import static se.leap.bitmaskclient.Constants.SHARED_PREFERENCES;
import static se.leap.bitmaskclient.DrawerSettingsAdapter.ABOUT;
+import static se.leap.bitmaskclient.DrawerSettingsAdapter.ALWAYS_ON;
import static se.leap.bitmaskclient.DrawerSettingsAdapter.BATTERY_SAVER;
import static se.leap.bitmaskclient.DrawerSettingsAdapter.DrawerSettingsItem.getSimpleTextInstance;
import static se.leap.bitmaskclient.DrawerSettingsAdapter.DrawerSettingsItem.getSwitchInstance;
@@ -171,6 +178,9 @@ public class NavigationDrawerFragment extends Fragment {
}
}));
}
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+ settingsListAdapter.addItem(getSimpleTextInstance(getString(R.string.always_on_vpn), ALWAYS_ON));
+ }
settingsListAdapter.addItem(getSimpleTextInstance(getString(switch_provider_menu_option), SWITCH_PROVIDER));
settingsListAdapter.addItem(getSimpleTextInstance(getString(log_fragment_title), LOG));
settingsListAdapter.addItem(getSimpleTextInstance(getString(about_fragment_title), ABOUT));
@@ -288,7 +298,8 @@ public class NavigationDrawerFragment extends Fragment {
try {
AlertDialog.Builder alertBuilder = new AlertDialog.Builder(getActivity());
showEnableExperimentalFeature = true;
- alertDialog = alertBuilder.setTitle(activity.getString(R.string.save_battery))
+ alertDialog = alertBuilder
+ .setTitle(activity.getString(R.string.save_battery))
.setMessage(activity.getString(R.string.save_battery_message))
.setPositiveButton((android.R.string.yes), new DialogInterface.OnClickListener() {
@Override
@@ -318,6 +329,19 @@ public class NavigationDrawerFragment extends Fragment {
} catch (IllegalStateException e) {
e.printStackTrace();
}
+ }
+
+ public void showAlwaysOnDialog() {
+ try {
+
+ FragmentTransaction fragmentTransaction = new FragmentManagerEnhanced(
+ getActivity().getSupportFragmentManager()).removePreviousFragment(
+ AlwaysOnDialog.TAG);
+ DialogFragment newFragment = new AlwaysOnDialog();
+ newFragment.show(fragmentTransaction, AlwaysOnDialog.TAG);
+ } catch (IllegalStateException | NullPointerException e) {
+ e.printStackTrace();
+ }
}
@@ -422,6 +446,15 @@ public class NavigationDrawerFragment extends Fragment {
mTitle = getString(about_fragment_title);
fragment = new AboutFragment();
break;
+ case ALWAYS_ON:
+ if (getShowAlwaysOnDialog(getContext())) {
+ showAlwaysOnDialog();
+ } else {
+ Intent intent = new Intent("android.net.vpn.SETTINGS");
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ startActivity(intent);
+ }
+ break;
default:
break;
}
diff --git a/app/src/main/java/se/leap/bitmaskclient/fragments/AlwaysOnDialog.java b/app/src/main/java/se/leap/bitmaskclient/fragments/AlwaysOnDialog.java
new file mode 100644
index 00000000..4e8e3d79
--- /dev/null
+++ b/app/src/main/java/se/leap/bitmaskclient/fragments/AlwaysOnDialog.java
@@ -0,0 +1,71 @@
+package se.leap.bitmaskclient.fragments;
+
+import android.app.Dialog;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v7.app.AlertDialog;
+import android.support.v7.app.AppCompatDialogFragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.CheckBox;
+
+import butterknife.ButterKnife;
+import butterknife.InjectView;
+import se.leap.bitmaskclient.R;
+import se.leap.bitmaskclient.views.IconTextView;
+
+import static se.leap.bitmaskclient.ConfigHelper.saveShowAlwaysOnDialog;
+
+/**
+ * Created by cyberta on 25.02.18.
+ */
+
+
+
+public class AlwaysOnDialog extends AppCompatDialogFragment {
+
+ public final static String TAG = AlwaysOnDialog.class.getName();
+
+ @InjectView(R.id.do_not_show_again)
+ CheckBox doNotShowAgainCheckBox;
+
+ @InjectView(R.id.user_message)
+ IconTextView userMessage;
+
+ @Override
+ public void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ }
+
+ @NonNull
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+ LayoutInflater inflater = getActivity().getLayoutInflater();
+ View view = inflater.inflate(R.layout.checkbox_confirm_dialog, null);
+ ButterKnife.inject(this, view);
+
+ userMessage.setIcon(R.drawable.ic_settings);
+ userMessage.setText(getString(R.string.always_on_vpn_user_message));
+ builder.setView(view)
+ .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+ if (doNotShowAgainCheckBox.isChecked()) {
+ saveShowAlwaysOnDialog(getContext(), false);
+ }
+ Intent intent = new Intent("android.net.vpn.SETTINGS");
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ startActivity(intent);
+ }
+ })
+ .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+ dialog.cancel();
+ }
+ });
+ return builder.create();
+ }
+}
diff --git a/app/src/main/java/se/leap/bitmaskclient/views/IconTextView.java b/app/src/main/java/se/leap/bitmaskclient/views/IconTextView.java
new file mode 100644
index 00000000..0af33c68
--- /dev/null
+++ b/app/src/main/java/se/leap/bitmaskclient/views/IconTextView.java
@@ -0,0 +1,96 @@
+package se.leap.bitmaskclient.views;
+
+
+import android.content.Context;
+import android.graphics.PorterDuff;
+import android.graphics.drawable.Drawable;
+import android.support.v7.widget.AppCompatTextView;
+import android.text.Spannable;
+import android.text.style.ImageSpan;
+import android.util.AttributeSet;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class IconTextView extends AppCompatTextView {
+
+ private int imageResource = 0;
+ /**
+ * Regex pattern that looks for embedded images of the format: [img src=imageName/]
+ */
+ public static final String PATTERN = "\\Q[img src]\\E";
+
+ public IconTextView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ public IconTextView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public IconTextView(Context context) {
+ super(context);
+ }
+
+ @Override
+ public void setText(CharSequence text, BufferType type) {
+ final Spannable spannable = getTextWithImages(getContext(), text, getLineHeight(), getCurrentTextColor());
+ super.setText(spannable, BufferType.SPANNABLE);
+ }
+
+ public void setIcon(int imageResource) {
+ this.imageResource = imageResource;
+ }
+
+ private Spannable getTextWithImages(Context context, CharSequence text, int lineHeight, int colour) {
+ final Spannable spannable = Spannable.Factory.getInstance().newSpannable(text);
+ addImages(context, spannable, lineHeight, colour);
+ return spannable;
+ }
+
+ private void addImages(Context context, Spannable spannable, int lineHeight, int colour) {
+ final Pattern refImg = Pattern.compile(PATTERN);
+
+ final Matcher matcher = refImg.matcher(spannable);
+ while (matcher.find()) {
+ boolean set = true;
+ for (ImageSpan span : spannable.getSpans(matcher.start(), matcher.end(), ImageSpan.class)) {
+ if (spannable.getSpanStart(span) >= matcher.start()
+ && spannable.getSpanEnd(span) <= matcher.end()) {
+ spannable.removeSpan(span);
+ } else {
+ set = false;
+ break;
+ }
+ }
+ if (set && imageResource != 0) {
+ spannable.setSpan(makeImageSpan(context, imageResource, lineHeight, colour),
+ matcher.start(),
+ matcher.end(),
+ Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
+ );
+ }
+ }
+ }
+
+ /**
+ * Create an ImageSpan for the given icon drawable. This also sets the image size and colour.
+ * Works best with a white, square icon because of the colouring and resizing.
+ *
+ * @param context The Android Context.
+ * @param drawableResId A drawable resource Id.
+ * @param size The desired size (i.e. width and height) of the image icon in pixels.
+ * Use the lineHeight of the TextView to make the image inline with the
+ * surrounding text.
+ * @param colour The colour (careful: NOT a resource Id) to apply to the image.
+ * @return An ImageSpan, aligned with the bottom of the text.
+ */
+ private ImageSpan makeImageSpan(Context context, int drawableResId, int size, int colour) {
+ final Drawable drawable = context.getResources().getDrawable(drawableResId);
+ drawable.mutate();
+ drawable.setColorFilter(colour, PorterDuff.Mode.MULTIPLY);
+ drawable.setBounds(0, 0, size, size);
+ return new ImageSpan(drawable, ImageSpan.ALIGN_BOTTOM);
+ }
+
+} \ No newline at end of file