2 * Copyright (C) 2012-2015 Tobias Brunner
4 * Copyright (C) secunet Security Networks AG
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>.
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
17 package org.strongswan.android.ui;
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;
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;
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;
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;
55 public class TrustedCertificateListFragment extends ListFragment implements MenuProvider, LoaderCallbacks<List<TrustedCertificateEntry>>, OnQueryTextListener
57 public static final String EXTRA_CERTIFICATE_SOURCE = "certificate_source";
58 private OnTrustedCertificateSelectedListener mListener;
59 private TrustedCertificateAdapter mAdapter;
60 private TrustedCertificateSource mSource = TrustedCertificateSource.SYSTEM;
63 * The activity containing this fragment should implement this interface
65 public interface OnTrustedCertificateSelectedListener
67 public void onTrustedCertificateSelected(TrustedCertificateEntry selected);
71 public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState)
73 super.onViewCreated(view, savedInstanceState);
74 requireActivity().addMenuProvider(this, getViewLifecycleOwner(), Lifecycle.State.RESUMED);
76 setEmptyText(getString(R.string.no_certificates));
78 mAdapter = new TrustedCertificateAdapter(getActivity());
79 setListAdapter(mAdapter);
83 Bundle arguments = getArguments();
84 if (arguments != null)
86 mSource = (TrustedCertificateSource)arguments.getSerializable(EXTRA_CERTIFICATE_SOURCE);
89 LoaderManager.getInstance(this).initLoader(0, null, this);
93 public void onDestroy()
99 public void onAttach(Context context)
101 super.onAttach(context);
103 if (context instanceof OnTrustedCertificateSelectedListener)
105 mListener = (OnTrustedCertificateSelectedListener)context;
110 public void onCreateMenu(@NonNull Menu menu, @NonNull MenuInflater menuInflater)
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);
116 SearchView sv = new SearchView(getActivity());
117 sv.setOnQueryTextListener(this);
118 item.setActionView(sv);
122 public boolean onMenuItemSelected(@NonNull MenuItem menuItem)
128 public boolean onQueryTextSubmit(String query)
129 { /* already handled when the text changes */
134 public boolean onQueryTextChange(String newText)
136 String search = TextUtils.isEmpty(newText) ? null : newText;
137 mAdapter.getFilter().filter(search);
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);
148 public void onLoadFinished(Loader<List<TrustedCertificateEntry>> loader, List<TrustedCertificateEntry> data)
150 mAdapter.setData(data);
158 setListShownNoAnimation(true);
163 public void onLoaderReset(Loader<List<TrustedCertificateEntry>> loader)
165 mAdapter.setData(null);
169 public void onListItemClick(ListView l, View v, int position, long id)
171 if (mListener != null)
173 mListener.onTrustedCertificateSelected(mAdapter.getItem(position));
177 public static class CertificateListLoader extends AsyncTaskLoader<List<TrustedCertificateEntry>>
179 private List<TrustedCertificateEntry> mData;
180 private final TrustedCertificateSource mSource;
181 private TrustedCertificateManagerObserver mObserver;
183 public CertificateListLoader(Context context, TrustedCertificateSource source)
190 public List<TrustedCertificateEntry> loadInBackground()
192 TrustedCertificateManager certman = TrustedCertificateManager.getInstance().load();
193 Hashtable<String, X509Certificate> certificates = certman.getCACertificates(mSource);
194 List<TrustedCertificateEntry> selected;
196 selected = new ArrayList<TrustedCertificateEntry>();
197 for (Entry<String, X509Certificate> entry : certificates.entrySet())
199 selected.add(new TrustedCertificateEntry(entry.getKey(), entry.getValue()));
201 Collections.sort(selected);
206 protected void onStartLoading()
209 { /* if we have data ready, deliver it directly */
210 deliverResult(mData);
212 if (takeContentChanged() || mData == null)
219 public void deliverResult(List<TrustedCertificateEntry> data)
227 { /* if it is started we deliver the data directly,
228 * otherwise this is handled in onStartLoading */
229 if (mObserver == null)
231 mObserver = new TrustedCertificateManagerObserver();
232 TrustedCertificateManager.getInstance().addObserver(mObserver);
234 super.deliverResult(data);
239 protected void onReset()
241 if (mObserver != null)
243 TrustedCertificateManager.getInstance().deleteObserver(mObserver);
251 protected void onAbandon()
253 if (mObserver != null)
255 TrustedCertificateManager.getInstance().deleteObserver(mObserver);
260 private class TrustedCertificateManagerObserver implements PropertyChangeListener
262 private ForceLoadContentObserver mContentObserver = new ForceLoadContentObserver();
265 public void propertyChange(PropertyChangeEvent evt)
267 mContentObserver.onChange(false);