/* This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll. This file is based on Keepassdroid, Copyright Brian Pellin. Keepass2Android 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 3 of the License, or (at your option) any later version. Keepass2Android 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. You should have received a copy of the GNU General Public License along with Keepass2Android. If not, see . */ using System; using System.Linq; using Android.App; using Android.Content; using Android.Content.PM; using Android.OS; using Android.Preferences; using Android.Views; using Android.Widget; using keepass2android.view; using keepass2android; using KeePassLib; namespace keepass2android.search { /// /// Activity to show search results /// [Activity(Label = "@string/app_name", Theme = "@style/Kp2aTheme_ActionBar", LaunchMode = Android.Content.PM.LaunchMode.SingleTop, Permission="keepass2android."+AppNames.PackagePart+".permission.KP2aInternalSearch", ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.Keyboard | ConfigChanges.KeyboardHidden, Exported = true)] #if NoNet [MetaData("android.app.searchable", Resource = "@xml/searchable_offline")] #else #if DEBUG [MetaData("android.app.searchable", Resource = "@xml/searchable_debug")] #else [MetaData("android.app.searchable", Resource = "@xml/searchable")] #endif #endif [MetaData("android.app.default_searchable", Value = "keepass2android.search.SearchResults")] [IntentFilter(new[]{Intent.ActionSearch}, Categories=new[]{Intent.CategoryDefault})] public class SearchResults : GroupBaseActivity { protected override void OnCreate (Bundle bundle) { base.OnCreate (bundle); if ( IsFinishing ) { return; } SetResult(KeePass.ExitNormal); ProcessIntent(Intent); } public override bool EntriesBelongToCurrentDatabaseOnly { get { return false; } } public override ElementAndDatabaseId FullGroupId { get { return null; } } protected override void OnNewIntent(Intent intent) { ProcessIntent(intent); } private void ProcessIntent(Intent intent) { // Likely the app has been killed exit the activity if (!App.Kp2a.DatabaseIsUnlocked) { Finish(); } if (intent.Action == Intent.ActionView) { var entryIntent = new Intent(this, typeof(EntryActivity)); ElementAndDatabaseId id; try { id = new ElementAndDatabaseId(intent.Data.LastPathSegment); } catch (Exception e) { Kp2aLog.Log("Failed to transform " + intent.Data.LastPathSegment + " to an ElementAndDatabaseId object. "); App.Kp2a.ShowMessage(this, "Bad path passed. Please provide database and element ID.", MessageSeverity.Error); Finish(); return; } entryIntent.PutExtra(EntryActivity.KeyEntry, id.FullId); entryIntent.AddFlags(ActivityFlags.ForwardResult); Finish(); // Close this activity so that the entry activity is navigated to from the main activity, not this one. StartActivity(entryIntent); } else { // Action may either by ActionSearch (from search widget) or null (if called from SearchActivity directly) Query(getSearch(intent)); } } private void Query(SearchParameters searchParams) { //kind of an easter egg: if the user types this exact string into the search, it immediately allows to disable the donation options if (searchParams.SearchString == "allow disable donation") { ISharedPreferences prefs = PreferenceManager.GetDefaultSharedPreferences(this); ISharedPreferencesEditor edit = prefs.Edit(); edit.PutLong(GetString(Resource.String.UsageCount_key), 1000); edit.PutBoolean("DismissedDonateReminder", true); edit.Commit(); App.Kp2a.ShowMessage(this, "Please go to Settings - App - Display to disable donation requests.", MessageSeverity.Error); } Group = null; try { foreach (var db in App.Kp2a.OpenDatabases) { PwGroup resultsForThisDb = db.Search(searchParams, null); if (Group == null) Group = resultsForThisDb; else { foreach (var entry in resultsForThisDb.Entries) { Group.AddEntry(entry, false); } } } } catch (Exception e) { Kp2aLog.LogUnexpectedError(e); App.Kp2a.ShowMessage(this, Util.GetErrorMessage(e), MessageSeverity.Error); Finish(); return; } if ( Group == null || (!Group.Entries.Any()) ) { SetContentView(Resource.Layout.group_empty); } SetGroupTitle(); FragmentManager.FindFragmentById(Resource.Id.list_fragment).ListAdapter = new PwGroupListAdapter(this, Group); } private SearchParameters getSearch(Intent queryIntent) { // get and process search query here SearchParameters sp = new SearchParameters(); sp.SearchString = queryIntent.GetStringExtra(SearchManager.Query); sp.SearchInTitles = queryIntent.GetBooleanExtra("SearchInTitles", sp.SearchInTitles); sp.SearchInUrls = queryIntent.GetBooleanExtra("SearchInUrls", sp.SearchInUrls); sp.SearchInPasswords = queryIntent.GetBooleanExtra("SearchInPasswords", sp.SearchInPasswords); sp.SearchInUserNames = queryIntent.GetBooleanExtra("SearchInUserNames", sp.SearchInUserNames); sp.SearchInNotes = queryIntent.GetBooleanExtra("SearchInNotes", sp.SearchInNotes); sp.SearchInGroupNames = queryIntent.GetBooleanExtra("SearchInGroupNames", sp.SearchInGroupNames); sp.SearchInOther = queryIntent.GetBooleanExtra("SearchInOther", sp.SearchInOther); sp.SearchInTags = queryIntent.GetBooleanExtra("SearchInTags", sp.SearchInTags); sp.RegularExpression = queryIntent.GetBooleanExtra("RegularExpression", sp.RegularExpression); sp.ExcludeExpired = queryIntent.GetBooleanExtra("ExcludeExpired", sp.ExcludeExpired); sp.ComparisonMode = queryIntent.GetBooleanExtra("CaseSensitive", false) ? StringComparison.InvariantCulture : StringComparison.InvariantCultureIgnoreCase; return sp; } public override void OnCreateContextMenu(IContextMenu menu, View v, IContextMenuContextMenuInfo menuInfo) { AdapterView.AdapterContextMenuInfo acmi = (AdapterView.AdapterContextMenuInfo) menuInfo; ClickView cv = (ClickView) acmi.TargetView; cv.OnCreateMenu(menu, menuInfo); } public override bool OnContextItemSelected(IMenuItem item) { AdapterView.AdapterContextMenuInfo acmi = (AdapterView.AdapterContextMenuInfo)item.MenuInfo; ClickView cv = (ClickView) acmi.TargetView; bool result; return cv.OnContextItemSelected(item); } public override bool OnSearchRequested() { Intent i = new Intent(this, typeof(SearchActivity)); this.AppTask.ToIntent(i); i.SetFlags(ActivityFlags.ForwardResult); StartActivity(i); return true; } public override bool IsSearchResult { get { return true; } } } }