android: Automatically reload certificates if manager is reset
[strongswan.git] / src / frontends / android / app / src / main / java / org / strongswan / android / ui / TrustedCertificateListFragment.java
1 /*
2 * Copyright (C) 2012-2015 Tobias Brunner
3 * Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 package org.strongswan.android.ui;
17
18 import android.content.Context;
19 import android.os.Bundle;
20 import android.support.v4.app.ListFragment;
21 import android.support.v4.app.LoaderManager.LoaderCallbacks;
22 import android.support.v4.content.AsyncTaskLoader;
23 import android.support.v4.content.Loader;
24 import android.text.TextUtils;
25 import android.view.Menu;
26 import android.view.MenuInflater;
27 import android.view.MenuItem;
28 import android.view.View;
29 import android.widget.ListView;
30 import android.widget.SearchView;
31 import android.widget.SearchView.OnQueryTextListener;
32
33 import org.strongswan.android.R;
34 import org.strongswan.android.logic.TrustedCertificateManager;
35 import org.strongswan.android.logic.TrustedCertificateManager.TrustedCertificateSource;
36 import org.strongswan.android.security.TrustedCertificateEntry;
37 import org.strongswan.android.ui.adapter.TrustedCertificateAdapter;
38
39 import java.security.cert.X509Certificate;
40 import java.util.ArrayList;
41 import java.util.Collections;
42 import java.util.Hashtable;
43 import java.util.List;
44 import java.util.Map.Entry;
45 import java.util.Observable;
46 import java.util.Observer;
47
48 public class TrustedCertificateListFragment extends ListFragment implements LoaderCallbacks<List<TrustedCertificateEntry>>, OnQueryTextListener
49 {
50 public static final String EXTRA_CERTIFICATE_SOURCE = "certificate_source";
51 private OnTrustedCertificateSelectedListener mListener;
52 private TrustedCertificateAdapter mAdapter;
53 private TrustedCertificateSource mSource = TrustedCertificateSource.SYSTEM;
54
55 /**
56 * The activity containing this fragment should implement this interface
57 */
58 public interface OnTrustedCertificateSelectedListener
59 {
60 public void onTrustedCertificateSelected(TrustedCertificateEntry selected);
61 }
62
63 @Override
64 public void onActivityCreated(Bundle savedInstanceState)
65 {
66 super.onActivityCreated(savedInstanceState);
67 setHasOptionsMenu(true);
68
69 setEmptyText(getString(R.string.no_certificates));
70
71 mAdapter = new TrustedCertificateAdapter(getActivity());
72 setListAdapter(mAdapter);
73
74 setListShown(false);
75
76 Bundle arguments = getArguments();
77 if (arguments != null)
78 {
79 mSource = (TrustedCertificateSource)arguments.getSerializable(EXTRA_CERTIFICATE_SOURCE);
80 }
81
82 getLoaderManager().initLoader(0, null, this);
83 }
84
85 @Override
86 public void onDestroy()
87 {
88 super.onDestroy();
89 }
90
91 @Override
92 public void onAttach(Context context)
93 {
94 super.onAttach(context);
95
96 if (context instanceof OnTrustedCertificateSelectedListener)
97 {
98 mListener = (OnTrustedCertificateSelectedListener)context;
99 }
100 }
101
102 @Override
103 public void onCreateOptionsMenu(Menu menu, MenuInflater inflater)
104 {
105 MenuItem item = menu.add(R.string.search);
106 item.setIcon(android.R.drawable.ic_menu_search);
107 item.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
108
109 SearchView sv = new SearchView(getActivity());
110 sv.setOnQueryTextListener(this);
111 item.setActionView(sv);
112 }
113
114 @Override
115 public boolean onQueryTextSubmit(String query)
116 { /* already handled when the text changes */
117 return true;
118 }
119
120 @Override
121 public boolean onQueryTextChange(String newText)
122 {
123 String search = TextUtils.isEmpty(newText) ? null : newText;
124 mAdapter.getFilter().filter(search);
125 return true;
126 }
127
128 @Override
129 public Loader<List<TrustedCertificateEntry>> onCreateLoader(int id, Bundle args)
130 { /* we don't need the id as we have only one loader */
131 return new CertificateListLoader(getActivity(), mSource);
132 }
133
134 @Override
135 public void onLoadFinished(Loader<List<TrustedCertificateEntry>> loader, List<TrustedCertificateEntry> data)
136 {
137 mAdapter.setData(data);
138
139 if (isResumed())
140 {
141 setListShown(true);
142 }
143 else
144 {
145 setListShownNoAnimation(true);
146 }
147 }
148
149 @Override
150 public void onLoaderReset(Loader<List<TrustedCertificateEntry>> loader)
151 {
152 mAdapter.setData(null);
153 }
154
155 @Override
156 public void onListItemClick(ListView l, View v, int position, long id)
157 {
158 if (mListener != null)
159 {
160 mListener.onTrustedCertificateSelected(mAdapter.getItem(position));
161 }
162 }
163
164 public static class CertificateListLoader extends AsyncTaskLoader<List<TrustedCertificateEntry>>
165 {
166 private List<TrustedCertificateEntry> mData;
167 private final TrustedCertificateSource mSource;
168 private TrustedCertificateManagerObserver mObserver;
169
170 public CertificateListLoader(Context context, TrustedCertificateSource source)
171 {
172 super(context);
173 mSource = source;
174 }
175
176 @Override
177 public List<TrustedCertificateEntry> loadInBackground()
178 {
179 TrustedCertificateManager certman = TrustedCertificateManager.getInstance().load();
180 Hashtable<String, X509Certificate> certificates = certman.getCACertificates(mSource);
181 List<TrustedCertificateEntry> selected;
182
183 selected = new ArrayList<TrustedCertificateEntry>();
184 for (Entry<String, X509Certificate> entry : certificates.entrySet())
185 {
186 selected.add(new TrustedCertificateEntry(entry.getKey(), entry.getValue()));
187 }
188 Collections.sort(selected);
189 return selected;
190 }
191
192 @Override
193 protected void onStartLoading()
194 {
195 if (mData != null)
196 { /* if we have data ready, deliver it directly */
197 deliverResult(mData);
198 }
199 if (takeContentChanged() || mData == null)
200 {
201 forceLoad();
202 }
203 }
204
205 @Override
206 public void deliverResult(List<TrustedCertificateEntry> data)
207 {
208 if (isReset())
209 {
210 return;
211 }
212 mData = data;
213 if (isStarted())
214 { /* if it is started we deliver the data directly,
215 * otherwise this is handled in onStartLoading */
216 if (mObserver == null)
217 {
218 mObserver = new TrustedCertificateManagerObserver();
219 TrustedCertificateManager.getInstance().addObserver(mObserver);
220 }
221 super.deliverResult(data);
222 }
223 }
224
225 @Override
226 protected void onReset()
227 {
228 if (mObserver != null)
229 {
230 TrustedCertificateManager.getInstance().deleteObserver(mObserver);
231 mObserver = null;
232 }
233 mData = null;
234 super.onReset();
235 }
236
237 @Override
238 protected void onAbandon()
239 {
240 if (mObserver != null)
241 {
242 TrustedCertificateManager.getInstance().deleteObserver(mObserver);
243 mObserver = null;
244 }
245 }
246
247 private class TrustedCertificateManagerObserver implements Observer
248 {
249 private ForceLoadContentObserver mContentObserver = new ForceLoadContentObserver();
250
251 @Override
252 public void update(Observable observable, Object data)
253 {
254 mContentObserver.onChange(false);
255 }
256 }
257 }
258 }