summaryrefslogtreecommitdiff
path: root/main/src/main/java/de/blinkt/openvpn/fragments/VPNProfileList.java
diff options
context:
space:
mode:
Diffstat (limited to 'main/src/main/java/de/blinkt/openvpn/fragments/VPNProfileList.java')
-rw-r--r--main/src/main/java/de/blinkt/openvpn/fragments/VPNProfileList.java176
1 files changed, 170 insertions, 6 deletions
diff --git a/main/src/main/java/de/blinkt/openvpn/fragments/VPNProfileList.java b/main/src/main/java/de/blinkt/openvpn/fragments/VPNProfileList.java
index 2aaf81c6..3c79a278 100644
--- a/main/src/main/java/de/blinkt/openvpn/fragments/VPNProfileList.java
+++ b/main/src/main/java/de/blinkt/openvpn/fragments/VPNProfileList.java
@@ -12,21 +12,40 @@ import android.app.ListFragment;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.pm.ShortcutInfo;
+import android.content.pm.ShortcutManager;
import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Icon;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
+import android.preference.PreferenceManager;
+import android.support.annotation.RequiresApi;
import android.text.Html;
import android.text.Html.ImageGetter;
-import android.view.*;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
import android.view.View.OnClickListener;
+import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.TextView;
import android.widget.Toast;
-import de.blinkt.openvpn.*;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.TreeSet;
+
+import de.blinkt.openvpn.LaunchVPN;
+import de.blinkt.openvpn.R;
+import de.blinkt.openvpn.VpnProfile;
import de.blinkt.openvpn.activities.ConfigConverter;
import de.blinkt.openvpn.activities.DisconnectVPN;
import de.blinkt.openvpn.activities.FileSelect;
@@ -35,9 +54,7 @@ import de.blinkt.openvpn.core.ConnectionStatus;
import de.blinkt.openvpn.core.ProfileManager;
import de.blinkt.openvpn.core.VpnStatus;
-import java.util.Collection;
-import java.util.Comparator;
-import java.util.TreeSet;
+import static de.blinkt.openvpn.core.OpenVPNService.DISCONNECT_VPN;
public class VPNProfileList extends ListFragment implements OnClickListener, VpnStatus.StateListener {
@@ -53,6 +70,8 @@ public class VPNProfileList extends ListFragment implements OnClickListener, Vpn
private static final int FILE_PICKER_RESULT_KITKAT = 392;
private static final int MENU_IMPORT_PROFILE = Menu.FIRST + 1;
+ private static final int MENU_CHANGE_SORTING = Menu.FIRST + 2;
+ private static final String PREF_SORT_BY_LRU = "sortProfilesByLRU";
private String mLastStatusMessage;
@Override
@@ -134,9 +153,96 @@ public class VPNProfileList extends ListFragment implements OnClickListener, Vpn
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
+ }
+
+
+ @RequiresApi(api = Build.VERSION_CODES.N_MR1)
+ void updateDynamicShortcuts() {
+
+ ShortcutManager shortcutManager = getContext().getSystemService(ShortcutManager.class);
+ if (shortcutManager.isRateLimitingActive())
+ return;
+
+ List<ShortcutInfo> shortcuts = shortcutManager.getDynamicShortcuts();
+ int maxvpn = shortcutManager.getMaxShortcutCountPerActivity() - 1;
+
+ ShortcutInfo disconnectShortcut = new ShortcutInfo.Builder(getContext(), "disconnectVPN")
+ .setShortLabel("Disconnect")
+ .setLongLabel("Disconnect VPN")
+ .setIntent(new Intent(getContext(), DisconnectVPN.class).setAction(DISCONNECT_VPN))
+ .setIcon(Icon.createWithResource(getContext(), R.drawable.ic_menu_close_clear_cancel))
+ .build();
+
+ LinkedList<ShortcutInfo> newShortcuts = new LinkedList<>();
+ LinkedList<String> removeShortcuts = new LinkedList<>();
+ LinkedList<String> disableShortcuts = new LinkedList<>();
+
+ boolean addDisconnect = true;
+
+
+ TreeSet<VpnProfile> sortedProfilesLRU = new TreeSet<VpnProfile>(new VpnProfileLRUComparator());
+ ProfileManager profileManager = ProfileManager.getInstance(getContext());
+ sortedProfilesLRU.addAll(profileManager.getProfiles());
+
+ LinkedList<VpnProfile> LRUProfiles = new LinkedList<>();
+
+ for (int i = 0; i < maxvpn; i++) {
+ LRUProfiles.add(sortedProfilesLRU.pollFirst());
+ }
+
+ for (ShortcutInfo shortcut : shortcuts) {
+ if (shortcut.getId().equals("disconnectVPN")) {
+ addDisconnect = false;
+ } else {
+ VpnProfile p = ProfileManager.get(getContext(), shortcut.getId());
+ if (p == null || p.profileDeleted) {
+ if (shortcut.isEnabled()) {
+ disableShortcuts.add(shortcut.getId());
+ removeShortcuts.add(shortcut.getId());
+ }
+ if (!shortcut.isPinned())
+ removeShortcuts.add(shortcut.getId());
+ } else {
+
+ if (LRUProfiles.contains(p))
+ LRUProfiles.remove(p);
+ else
+ removeShortcuts.add(p.getUUIDString());
+ //}
+ // XXX: Update Shortcut
+ }
+
+ }
+
+ }
+ if (addDisconnect)
+ newShortcuts.add(disconnectShortcut);
+ for (VpnProfile p : LRUProfiles)
+ newShortcuts.add(createShortcut(p));
+
+ if (removeShortcuts.size() > 0)
+ shortcutManager.removeDynamicShortcuts(removeShortcuts);
+ if (newShortcuts.size() > 0)
+ shortcutManager.addDynamicShortcuts(newShortcuts);
+ if (disableShortcuts.size() > 0)
+ shortcutManager.disableShortcuts(disableShortcuts, "VpnProfile does not exist anymore.");
}
+ @RequiresApi(Build.VERSION_CODES.N_MR1)
+ ShortcutInfo createShortcut(VpnProfile profile) {
+ Intent shortcutIntent = new Intent(Intent.ACTION_MAIN);
+ shortcutIntent.setClass(getActivity(), LaunchVPN.class);
+ shortcutIntent.putExtra(LaunchVPN.EXTRA_KEY, profile.getUUID().toString());
+ shortcutIntent.setAction(Intent.ACTION_MAIN);
+
+ return new ShortcutInfo.Builder(getContext(), profile.getUUIDString())
+ .setShortLabel(profile.getName())
+ .setLongLabel(getString(R.string.qs_connect, profile.getName()))
+ .setIcon(Icon.createWithResource(getContext(), R.mipmap.ic_launcher))
+ .setIntent(shortcutIntent)
+ .build();
+ }
class MiniImageGetter implements ImageGetter {
@@ -164,6 +270,9 @@ public class VPNProfileList extends ListFragment implements OnClickListener, Vpn
public void onResume() {
super.onResume();
setListAdapter();
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
+ updateDynamicShortcuts();
+ }
VpnStatus.addStateListener(this);
}
@@ -225,13 +334,43 @@ public class VPNProfileList extends ListFragment implements OnClickListener, Vpn
}
+ static class VpnProfileLRUComparator implements Comparator<VpnProfile> {
+
+ @Override
+ public int compare(VpnProfile lhs, VpnProfile rhs) {
+ if (lhs == rhs)
+ // Catches also both null
+ return 0;
+
+ if (lhs == null)
+ return -1;
+ if (rhs == null)
+ return 1;
+
+ // Copied from Long.compare
+ return (lhs.mLastUsed < rhs.mLastUsed) ? -1 : ((lhs.mLastUsed == rhs.mLastUsed) ? 0 : 1);
+ }
+
+ }
+
+
private void setListAdapter() {
if (mArrayadapter == null) {
mArrayadapter = new VPNArrayAdapter(getActivity(), R.layout.vpn_list_item, R.id.vpn_item_title);
}
+ populateVpnList();
+ }
+
+ private void populateVpnList() {
+ boolean sortByLRU = PreferenceManager.getDefaultSharedPreferences(getActivity()).getBoolean(PREF_SORT_BY_LRU, false);
Collection<VpnProfile> allvpn = getPM().getProfiles();
- TreeSet<VpnProfile> sortedset = new TreeSet<VpnProfile>(new VpnProfileNameComparator());
+ TreeSet<VpnProfile> sortedset;
+ if (sortByLRU)
+ sortedset= new TreeSet<>(new VpnProfileLRUComparator());
+ else
+ sortedset = new TreeSet<>(new VpnProfileNameComparator());
+
sortedset.addAll(allvpn);
mArrayadapter.clear();
mArrayadapter.addAll(sortedset);
@@ -254,6 +393,13 @@ public class VPNProfileList extends ListFragment implements OnClickListener, Vpn
.setAlphabeticShortcut('i')
.setTitleCondensed(getActivity().getString(R.string.menu_import_short))
.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
+
+ menu.add(0, MENU_CHANGE_SORTING, 0, R.string.change_sorting)
+ .setIcon(R.drawable.ic_sort)
+ .setAlphabeticShortcut('s')
+ .setTitleCondensed(getString(R.string.sort))
+ .setShowAsActionFlags(MenuItem.SHOW_AS_ACTION_ALWAYS);
+
}
@@ -265,11 +411,29 @@ public class VPNProfileList extends ListFragment implements OnClickListener, Vpn
return true;
} else if (itemId == MENU_IMPORT_PROFILE) {
return startImportConfigFilePicker();
+ } else if (itemId == MENU_CHANGE_SORTING){
+ return changeSorting();
} else {
return super.onOptionsItemSelected(item);
}
}
+ private boolean changeSorting() {
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getActivity());
+ boolean oldValue = prefs.getBoolean(PREF_SORT_BY_LRU, false);
+ SharedPreferences.Editor prefsedit = prefs.edit();
+ if (oldValue) {
+ Toast.makeText(getActivity(), R.string.sorted_az, Toast.LENGTH_SHORT).show();
+ prefsedit.putBoolean(PREF_SORT_BY_LRU, false);
+ } else {
+ prefsedit.putBoolean(PREF_SORT_BY_LRU, true);
+ Toast.makeText(getActivity(), R.string.sorted_lru, Toast.LENGTH_SHORT).show();
+ }
+ prefsedit.apply();
+ populateVpnList();
+ return true;
+ }
+
@Override
public void onClick(View v) {
switch (v.getId()) {