diff options
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.java | 176 |
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()) { |