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