android: Use a local broadcast to notify about profile changes

This allows other components to modify the profiles and notify about
changes.
This commit is contained in:
Tobias Brunner
2017-01-20 11:01:32 +01:00
parent c4ab9af74e
commit cf6110f152
3 changed files with 107 additions and 47 deletions
@@ -26,6 +26,7 @@ import android.os.Bundle;
import android.security.KeyChain; import android.security.KeyChain;
import android.security.KeyChainAliasCallback; import android.security.KeyChainAliasCallback;
import android.security.KeyChainException; import android.security.KeyChainException;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v7.app.AlertDialog; import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity; import android.support.v7.app.AppCompatActivity;
import android.support.v7.app.AppCompatDialogFragment; import android.support.v7.app.AppCompatDialogFragment;
@@ -63,6 +64,7 @@ import org.strongswan.android.logic.TrustedCertificateManager;
import org.strongswan.android.security.TrustedCertificateEntry; import org.strongswan.android.security.TrustedCertificateEntry;
import org.strongswan.android.ui.adapter.CertificateIdentitiesAdapter; import org.strongswan.android.ui.adapter.CertificateIdentitiesAdapter;
import org.strongswan.android.ui.widget.TextInputLayoutHelper; import org.strongswan.android.ui.widget.TextInputLayoutHelper;
import org.strongswan.android.utils.Constants;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
import java.util.UUID; import java.util.UUID;
@@ -70,8 +72,6 @@ import java.util.UUID;
public class VpnProfileDetailActivity extends AppCompatActivity public class VpnProfileDetailActivity extends AppCompatActivity
{ {
private static final int SELECT_TRUSTED_CERTIFICATE = 0; private static final int SELECT_TRUSTED_CERTIFICATE = 0;
private static final int MTU_MIN = 1280;
private static final int MTU_MAX = 1500;
private VpnProfileDataSource mDataSource; private VpnProfileDataSource mDataSource;
private Long mId; private Long mId;
@@ -466,6 +466,10 @@ public class VpnProfileDetailActivity extends AppCompatActivity
updateProfileData(); updateProfileData();
mDataSource.insertProfile(mProfile); mDataSource.insertProfile(mProfile);
} }
Intent intent = new Intent(Constants.VPN_PROFILES_CHANGED);
intent.putExtra(Constants.VPN_PROFILES_SINGLE, mProfile.getId());
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
setResult(RESULT_OK, new Intent().putExtra(VpnProfileDataSource.KEY_ID, mProfile.getId())); setResult(RESULT_OK, new Intent().putExtra(VpnProfileDataSource.KEY_ID, mProfile.getId()));
finish(); finish();
} }
@@ -501,9 +505,9 @@ public class VpnProfileDetailActivity extends AppCompatActivity
showCertificateAlert(); showCertificateAlert();
valid = false; valid = false;
} }
if (!validateInteger(mMTU, MTU_MIN, MTU_MAX)) if (!validateInteger(mMTU, Constants.MTU_MIN, Constants.MTU_MAX))
{ {
mMTUWrap.setError(String.format(getString(R.string.alert_text_out_of_range), MTU_MIN, MTU_MAX)); mMTUWrap.setError(String.format(getString(R.string.alert_text_out_of_range), Constants.MTU_MIN, Constants.MTU_MAX));
valid = false; valid = false;
} }
if (!validateInteger(mPort, 1, 65535)) if (!validateInteger(mPort, 1, 65535))
@@ -572,8 +576,8 @@ public class VpnProfileDetailActivity extends AppCompatActivity
mRemoteId.setText(mProfile.getRemoteId()); mRemoteId.setText(mProfile.getRemoteId());
mMTU.setText(mProfile.getMTU() != null ? mProfile.getMTU().toString() : null); mMTU.setText(mProfile.getMTU() != null ? mProfile.getMTU().toString() : null);
mPort.setText(mProfile.getPort() != null ? mProfile.getPort().toString() : null); mPort.setText(mProfile.getPort() != null ? mProfile.getPort().toString() : null);
mBlockIPv4.setChecked(mProfile.getSplitTunneling() != null ? (mProfile.getSplitTunneling() & VpnProfile.SPLIT_TUNNELING_BLOCK_IPV4) != 0 : false); mBlockIPv4.setChecked(mProfile.getSplitTunneling() != null && (mProfile.getSplitTunneling() & VpnProfile.SPLIT_TUNNELING_BLOCK_IPV4) != 0);
mBlockIPv6.setChecked(mProfile.getSplitTunneling() != null ? (mProfile.getSplitTunneling() & VpnProfile.SPLIT_TUNNELING_BLOCK_IPV6) != 0 : false); mBlockIPv6.setChecked(mProfile.getSplitTunneling() != null && (mProfile.getSplitTunneling() & VpnProfile.SPLIT_TUNNELING_BLOCK_IPV6) != 0);
useralias = mProfile.getUserCertificateAlias(); useralias = mProfile.getUserCertificateAlias();
local_id = mProfile.getLocalId(); local_id = mProfile.getLocalId();
alias = mProfile.getCertificateAlias(); alias = mProfile.getCertificateAlias();
@@ -691,11 +695,7 @@ public class VpnProfileDetailActivity extends AppCompatActivity
} }
}); });
} }
catch (KeyChainException e) catch (KeyChainException | InterruptedException e)
{
e.printStackTrace();
}
catch (InterruptedException e)
{ {
e.printStackTrace(); e.printStackTrace();
} }
@@ -727,11 +727,7 @@ public class VpnProfileDetailActivity extends AppCompatActivity
{ {
chain = KeyChain.getCertificateChain(mContext, mAlias); chain = KeyChain.getCertificateChain(mContext, mAlias);
} }
catch (KeyChainException e) catch (KeyChainException | InterruptedException e)
{
e.printStackTrace();
}
catch (InterruptedException e)
{ {
e.printStackTrace(); e.printStackTrace();
} }
@@ -17,12 +17,14 @@
package org.strongswan.android.ui; package org.strongswan.android.ui;
import android.app.Activity; import android.content.BroadcastReceiver;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.TypedArray; import android.content.res.TypedArray;
import android.os.Bundle; import android.os.Bundle;
import android.support.v4.app.Fragment; import android.support.v4.app.Fragment;
import android.support.v4.content.LocalBroadcastManager;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.view.ActionMode; import android.view.ActionMode;
import android.view.LayoutInflater; import android.view.LayoutInflater;
@@ -41,9 +43,11 @@ import org.strongswan.android.R;
import org.strongswan.android.data.VpnProfile; import org.strongswan.android.data.VpnProfile;
import org.strongswan.android.data.VpnProfileDataSource; import org.strongswan.android.data.VpnProfileDataSource;
import org.strongswan.android.ui.adapter.VpnProfileAdapter; import org.strongswan.android.ui.adapter.VpnProfileAdapter;
import org.strongswan.android.utils.Constants;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator;
import java.util.List; import java.util.List;
public class VpnProfileListFragment extends Fragment public class VpnProfileListFragment extends Fragment
@@ -58,11 +62,47 @@ public class VpnProfileListFragment extends Fragment
private OnVpnProfileSelectedListener mListener; private OnVpnProfileSelectedListener mListener;
private boolean mReadOnly; private boolean mReadOnly;
private BroadcastReceiver mProfilesChanged = new BroadcastReceiver()
{
@Override
public void onReceive(Context context, Intent intent)
{
long id, ids[];
if ((id = intent.getLongExtra(Constants.VPN_PROFILES_SINGLE, 0)) > 0)
{
VpnProfile profile = mDataSource.getVpnProfile(id);
if (profile != null)
{ /* in case this was an edit, we remove it first */
mVpnProfiles.remove(profile);
mVpnProfiles.add(profile);
mListAdapter.notifyDataSetChanged();
}
}
else if ((ids = intent.getLongArrayExtra(Constants.VPN_PROFILES_MULTIPLE)) != null)
{
for (long i : ids)
{
Iterator<VpnProfile> profiles = mVpnProfiles.iterator();
while (profiles.hasNext())
{
VpnProfile profile = profiles.next();
if (profile.getId() == i)
{
profiles.remove();
break;
}
}
}
mListAdapter.notifyDataSetChanged();
}
}
};
/** /**
* The activity containing this fragment should implement this interface * The activity containing this fragment should implement this interface
*/ */
public interface OnVpnProfileSelectedListener { public interface OnVpnProfileSelectedListener {
public void onVpnProfileSelected(VpnProfile profile); void onVpnProfileSelected(VpnProfile profile);
} }
@Override @Override
@@ -116,6 +156,9 @@ public class VpnProfileListFragment extends Fragment
mVpnProfiles = mDataSource.getAllVpnProfiles(); mVpnProfiles = mDataSource.getAllVpnProfiles();
mListAdapter = new VpnProfileAdapter(getActivity(), R.layout.profile_list_item, mVpnProfiles); mListAdapter = new VpnProfileAdapter(getActivity(), R.layout.profile_list_item, mVpnProfiles);
IntentFilter profileChangesFilter = new IntentFilter(Constants.VPN_PROFILES_CHANGED);
LocalBroadcastManager.getInstance(getActivity()).registerReceiver(mProfilesChanged, profileChangesFilter);
} }
@Override @Override
@@ -123,6 +166,7 @@ public class VpnProfileListFragment extends Fragment
{ {
super.onDestroy(); super.onDestroy();
mDataSource.close(); mDataSource.close();
LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(mProfilesChanged);
} }
@Override @Override
@@ -157,30 +201,6 @@ public class VpnProfileListFragment extends Fragment
} }
} }
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data)
{
switch (requestCode)
{
case ADD_REQUEST:
case EDIT_REQUEST:
if (resultCode != Activity.RESULT_OK)
{
return;
}
long id = data.getLongExtra(VpnProfileDataSource.KEY_ID, 0);
VpnProfile profile = mDataSource.getVpnProfile(id);
if (profile != null)
{ /* in case this was an edit, we remove it first */
mVpnProfiles.remove(profile);
mVpnProfiles.add(profile);
mListAdapter.notifyDataSetChanged();
}
return;
}
super.onActivityResult(requestCode, resultCode, data);
}
private final OnItemClickListener mVpnProfileClicked = new OnItemClickListener() { private final OnItemClickListener mVpnProfileClicked = new OnItemClickListener() {
@Override @Override
public void onItemClick(AdapterView<?> a, View v, int position, long id) public void onItemClick(AdapterView<?> a, View v, int position, long id)
@@ -213,7 +233,7 @@ public class VpnProfileListFragment extends Fragment
MenuInflater inflater = mode.getMenuInflater(); MenuInflater inflater = mode.getMenuInflater();
inflater.inflate(R.menu.profile_list_context, menu); inflater.inflate(R.menu.profile_list_context, menu);
mEditProfile = menu.findItem(R.id.edit_profile); mEditProfile = menu.findItem(R.id.edit_profile);
mSelected = new HashSet<Integer>(); mSelected = new HashSet<>();
mode.setTitle(R.string.select_profiles); mode.setTitle(R.string.select_profiles);
return true; return true;
} }
@@ -234,17 +254,21 @@ public class VpnProfileListFragment extends Fragment
} }
case R.id.delete_profile: case R.id.delete_profile:
{ {
ArrayList<VpnProfile> profiles = new ArrayList<VpnProfile>(); ArrayList<VpnProfile> profiles = new ArrayList<>();
for (int position : mSelected) for (int position : mSelected)
{ {
profiles.add((VpnProfile)mListView.getItemAtPosition(position)); profiles.add((VpnProfile)mListView.getItemAtPosition(position));
} }
for (VpnProfile profile : profiles) long ids[] = new long[profiles.size()];
for (int i = 0; i < profiles.size(); i++)
{ {
VpnProfile profile = profiles.get(i);
ids[i] = profile.getId();
mDataSource.deleteVpnProfile(profile); mDataSource.deleteVpnProfile(profile);
mVpnProfiles.remove(profile);
} }
mListAdapter.notifyDataSetChanged(); Intent intent = new Intent(Constants.VPN_PROFILES_CHANGED);
intent.putExtra(Constants.VPN_PROFILES_MULTIPLE, ids);
LocalBroadcastManager.getInstance(getActivity()).sendBroadcast(intent);
Toast.makeText(VpnProfileListFragment.this.getActivity(), Toast.makeText(VpnProfileListFragment.this.getActivity(),
R.string.profiles_deleted, Toast.LENGTH_SHORT).show(); R.string.profiles_deleted, Toast.LENGTH_SHORT).show();
break; break;
@@ -0,0 +1,40 @@
/*
* Copyright (C) 2016 Tobias Brunner
* Hochschule fuer Technik Rapperswil
*
* 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 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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.
*/
package org.strongswan.android.utils;
public final class Constants
{
/**
* Intent action used to notify about changes to the VPN profiles
*/
public static final String VPN_PROFILES_CHANGED = "org.strongswan.android.VPN_PROFILES_CHANGED";
/**
* Used in the intent above to notify about edits or inserts of a VPN profile (long)
*/
public static final String VPN_PROFILES_SINGLE = "org.strongswan.android.VPN_PROFILES_SINGLE";
/**
* Used in the intent above to notify about the deletion of multiple VPN profiles (array of longs)
*/
public static final String VPN_PROFILES_MULTIPLE = "org.strongswan.android.VPN_PROFILES_MULTIPLE";
/**
* Limits for MTU
*/
public static final int MTU_MAX = 1500;
public static final int MTU_MIN = 1280;
}