2013-02-23 11:43:42 -05:00
/ *
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
2014-01-26 08:27:27 -05:00
the Free Software Foundation , either version 3 of the License , or
2013-02-23 11:43:42 -05:00
( 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 < http : //www.gnu.org/licenses/>.
* /
using System ;
2015-08-19 01:03:12 -04:00
using System.Collections ;
2014-12-23 14:29:27 -05:00
using System.Collections.Generic ;
using System.Linq ;
2013-02-23 11:43:42 -05:00
using Android.App ;
using Android.Content ;
using Android.OS ;
using Android.Runtime ;
using Android.Views ;
using Android.Widget ;
using KeePassLib ;
using Android.Preferences ;
2013-08-28 08:00:54 -04:00
using KeePassLib.Interfaces ;
2013-11-20 13:14:57 -05:00
using KeePassLib.Serialization ;
2013-08-28 08:00:54 -04:00
using KeePassLib.Utility ;
2013-08-14 00:05:25 -04:00
using keepass2android.Io ;
2013-08-28 08:00:54 -04:00
using keepass2android.database.edit ;
2013-02-23 11:43:42 -05:00
using keepass2android.view ;
2013-04-12 23:28:15 -04:00
using Android.Graphics.Drawables ;
2015-08-10 02:07:42 -04:00
using Android.Support.V4.View ;
using CursorAdapter = Android . Support . V4 . Widget . CursorAdapter ;
using Object = Java . Lang . Object ;
2013-02-23 11:43:42 -05:00
namespace keepass2android
{
2015-08-10 02:07:42 -04:00
public abstract class GroupBaseActivity : LockCloseActivity {
2013-06-15 06:40:01 -04:00
public const String KeyEntry = "entry" ;
public const String KeyMode = "mode" ;
2013-02-23 11:43:42 -05:00
2013-06-15 06:40:01 -04:00
public virtual void LaunchActivityForEntry ( PwEntry pwEntry , int pos )
2013-02-23 11:43:42 -05:00
{
2013-06-15 06:40:01 -04:00
EntryActivity . Launch ( this , pwEntry , pos , AppTask ) ;
2013-02-23 11:43:42 -05:00
}
2013-06-15 06:40:01 -04:00
protected GroupBaseActivity ( )
2013-02-23 11:43:42 -05:00
{
}
2013-06-15 06:40:01 -04:00
protected GroupBaseActivity ( IntPtr javaReference , JniHandleOwnership transfer )
2013-02-23 11:43:42 -05:00
: base ( javaReference , transfer )
{
}
2013-05-30 00:54:25 -04:00
protected override void OnSaveInstanceState ( Bundle outState )
{
base . OnSaveInstanceState ( outState ) ;
2013-06-15 06:40:01 -04:00
AppTask . ToBundle ( outState ) ;
2013-05-30 00:54:25 -04:00
}
2013-06-01 09:51:54 -04:00
2013-08-28 08:00:54 -04:00
public virtual void SetupNormalButtons ( )
{
2015-08-10 02:07:42 -04:00
SetNormalButtonVisibility ( AddGroupEnabled , AddEntryEnabled ) ;
2013-08-28 08:00:54 -04:00
}
2015-08-10 02:07:42 -04:00
protected virtual bool AddGroupEnabled
{
get { return App . Kp2a . GetDb ( ) . CanWrite ; }
}
protected virtual bool AddEntryEnabled
{
get { return App . Kp2a . GetDb ( ) . CanWrite ; }
}
public void SetNormalButtonVisibility ( bool showAddGroup , bool showAddEntry )
{
2015-09-17 00:01:45 -04:00
//check for null in the following because the "empty" layouts may not have all views
2015-08-10 02:07:42 -04:00
2015-09-17 00:01:45 -04:00
if ( FindViewById ( Resource . Id . bottom_bar ) ! = null )
FindViewById ( Resource . Id . bottom_bar ) . Visibility = BottomBarAlwaysVisible ? ViewStates . Visible : ViewStates . Gone ;
2015-08-10 02:07:42 -04:00
2015-09-17 00:01:45 -04:00
if ( FindViewById ( Resource . Id . divider2 ) ! = null )
FindViewById ( Resource . Id . divider2 ) . Visibility = BottomBarAlwaysVisible ? ViewStates . Visible : ViewStates . Gone ;
if ( FindViewById ( Resource . Id . fabCancelAddNew ) ! = null )
{
FindViewById ( Resource . Id . fabCancelAddNew ) . Visibility = ViewStates . Gone ;
FindViewById ( Resource . Id . fabAddNewGroup ) . Visibility = ViewStates . Gone ;
FindViewById ( Resource . Id . fabAddNewEntry ) . Visibility = ViewStates . Gone ;
FindViewById ( Resource . Id . fabAddNew ) . Visibility = ( showAddGroup | | showAddEntry ) ? ViewStates . Visible : ViewStates . Gone ;
}
2015-08-10 02:07:42 -04:00
}
2015-09-17 00:01:45 -04:00
public virtual bool BottomBarAlwaysVisible
{
get { return false ; }
}
2013-06-01 09:51:54 -04:00
protected override void OnActivityResult ( int requestCode , Result resultCode , Intent data )
{
base . OnActivityResult ( requestCode , resultCode , data ) ;
2014-05-16 11:15:43 -04:00
if ( AppTask . TryGetFromActivityResult ( data , ref AppTask ) )
{
//make sure the app task is passed to the calling activity
AppTask . SetActivityResult ( this , KeePass . ExitNormal ) ;
2014-05-28 11:24:43 -04:00
2014-05-16 11:15:43 -04:00
}
2013-08-28 08:00:54 -04:00
2013-09-03 16:58:15 -04:00
if ( resultCode = = Result . Ok )
{
String groupName = data . Extras . GetString ( GroupEditActivity . KeyName ) ;
int groupIconId = data . Extras . GetInt ( GroupEditActivity . KeyIconId ) ;
PwUuid groupCustomIconId =
new PwUuid ( MemUtil . HexStringToByteArray ( data . Extras . GetString ( GroupEditActivity . KeyCustomIconId ) ) ) ;
String strGroupUuid = data . Extras . GetString ( GroupEditActivity . KeyGroupUuid ) ;
GroupBaseActivity act = this ;
Handler handler = new Handler ( ) ;
RunnableOnFinish task ;
if ( strGroupUuid = = null )
{
2015-09-30 14:43:38 -04:00
task = AddGroup . GetInstance ( this , App . Kp2a , groupName , groupIconId , groupCustomIconId , Group , new RefreshTask ( handler , this ) , false ) ;
2013-09-03 16:58:15 -04:00
}
else
{
PwUuid groupUuid = new PwUuid ( MemUtil . HexStringToByteArray ( strGroupUuid ) ) ;
task = new EditGroup ( this , App . Kp2a , groupName , ( PwIcon ) groupIconId , groupCustomIconId , App . Kp2a . GetDb ( ) . Groups [ groupUuid ] ,
new RefreshTask ( handler , this ) ) ;
}
ProgressTask pt = new ProgressTask ( App . Kp2a , act , task ) ;
pt . Run ( ) ;
}
2013-06-15 06:40:01 -04:00
if ( resultCode = = KeePass . ExitCloseAfterTaskComplete )
2013-06-01 09:51:54 -04:00
{
2013-08-28 08:00:54 -04:00
AppTask . SetActivityResult ( this , KeePass . ExitCloseAfterTaskComplete ) ;
2013-06-01 09:51:54 -04:00
Finish ( ) ;
}
2014-03-23 10:40:28 -04:00
if ( resultCode = = KeePass . ExitReloadDb )
{
AppTask . SetActivityResult ( this , KeePass . ExitReloadDb ) ;
Finish ( ) ;
}
2013-06-01 09:51:54 -04:00
}
2013-02-23 11:43:42 -05:00
2013-06-15 06:40:01 -04:00
private ISharedPreferences _prefs ;
2013-02-23 11:43:42 -05:00
2013-06-15 06:40:01 -04:00
protected PwGroup Group ;
2013-05-30 00:54:25 -04:00
2013-06-15 06:40:01 -04:00
internal AppTask AppTask ;
2015-09-16 23:26:13 -04:00
2014-05-25 14:09:06 -04:00
private String strCachedGroupUuid = null ;
2015-08-10 09:39:34 -04:00
2015-08-19 01:03:12 -04:00
2015-08-10 09:39:34 -04:00
public String UuidGroup {
2014-05-25 14:09:06 -04:00
get {
if ( strCachedGroupUuid = = null ) {
strCachedGroupUuid = MemUtil . ByteArrayToHexString ( Group . Uuid . UuidBytes ) ;
}
return strCachedGroupUuid ;
}
}
2013-02-23 11:43:42 -05:00
protected override void OnResume ( ) {
base . OnResume ( ) ;
2014-05-28 11:24:43 -04:00
AppTask . StartInGroupActivity ( this ) ;
2013-08-28 08:00:54 -04:00
AppTask . SetupGroupBaseActivityButtons ( this ) ;
2013-02-23 11:43:42 -05:00
2013-06-15 06:40:01 -04:00
RefreshIfDirty ( ) ;
2013-02-23 11:43:42 -05:00
}
public override bool OnSearchRequested ( )
{
2014-05-14 01:23:31 -04:00
Intent i = new Intent ( this , typeof ( SearchActivity ) ) ;
AppTask . ToIntent ( i ) ;
StartActivityForResult ( i , 0 ) ;
2013-02-23 11:43:42 -05:00
return true ;
}
2013-06-15 06:40:01 -04:00
public void RefreshIfDirty ( ) {
2013-06-14 00:14:50 -04:00
Database db = App . Kp2a . GetDb ( ) ;
2013-06-15 06:40:01 -04:00
if ( db . Dirty . Contains ( Group ) ) {
db . Dirty . Remove ( Group ) ;
2015-08-10 09:39:34 -04:00
ListAdapter . NotifyDataSetChanged ( ) ;
2013-02-23 11:43:42 -05:00
}
}
2015-08-10 09:39:34 -04:00
public BaseAdapter ListAdapter
{
get { return ( BaseAdapter ) FragmentManager . FindFragmentById < GroupListFragment > ( Resource . Id . list_fragment ) . ListAdapter ; }
}
2015-08-19 01:03:12 -04:00
public virtual bool IsSearchResult
{
get { return false ; }
}
2015-09-16 23:26:13 -04:00
protected override void OnCreate ( Bundle savedInstanceState ) {
2013-02-23 11:43:42 -05:00
base . OnCreate ( savedInstanceState ) ;
2015-08-19 01:03:12 -04:00
Android . Util . Log . Debug ( "KP2A" , "Creating GBA" ) ;
2013-06-15 06:40:01 -04:00
AppTask = AppTask . GetTaskInOnCreate ( savedInstanceState , Intent ) ;
2013-02-23 11:43:42 -05:00
// Likely the app has been killed exit the activity
2013-06-14 00:14:50 -04:00
if ( ! App . Kp2a . GetDb ( ) . Loaded ) {
2013-02-23 11:43:42 -05:00
Finish ( ) ;
return ;
}
2013-06-15 06:40:01 -04:00
_prefs = PreferenceManager . GetDefaultSharedPreferences ( this ) ;
2013-08-16 08:26:06 -04:00
2015-08-10 02:07:42 -04:00
2015-09-17 00:01:45 -04:00
SetContentView ( ContentResourceId ) ;
2015-08-10 02:07:42 -04:00
2015-09-17 00:01:45 -04:00
if ( FindViewById ( Resource . Id . fabCancelAddNew ) ! = null )
2015-08-10 02:07:42 -04:00
{
2015-09-17 00:01:45 -04:00
FindViewById ( Resource . Id . fabAddNew ) . Click + = ( sender , args ) = >
{
FindViewById ( Resource . Id . fabCancelAddNew ) . Visibility = ViewStates . Visible ;
FindViewById ( Resource . Id . fabAddNewGroup ) . Visibility = AddGroupEnabled ? ViewStates . Visible : ViewStates . Gone ;
FindViewById ( Resource . Id . fabAddNewEntry ) . Visibility = AddEntryEnabled ? ViewStates . Visible : ViewStates . Gone ;
FindViewById ( Resource . Id . fabAddNew ) . Visibility = ViewStates . Gone ;
} ;
2015-08-10 02:07:42 -04:00
2015-09-17 00:01:45 -04:00
FindViewById ( Resource . Id . fabCancelAddNew ) . Click + = ( sender , args ) = >
{
FindViewById ( Resource . Id . fabCancelAddNew ) . Visibility = ViewStates . Gone ;
FindViewById ( Resource . Id . fabAddNewGroup ) . Visibility = ViewStates . Gone ;
FindViewById ( Resource . Id . fabAddNewEntry ) . Visibility = ViewStates . Gone ;
FindViewById ( Resource . Id . fabAddNew ) . Visibility = ViewStates . Visible ;
} ;
2015-08-10 02:07:42 -04:00
2015-09-17 00:01:45 -04:00
}
2015-08-10 02:07:42 -04:00
2015-09-17 00:01:45 -04:00
if ( FindViewById ( Resource . Id . cancel_insert_element ) ! = null )
{
FindViewById ( Resource . Id . cancel_insert_element ) . Click + = ( sender , args ) = > StopMovingElements ( ) ;
FindViewById ( Resource . Id . insert_element ) . Click + = ( sender , args ) = > InsertElements ( ) ;
}
2015-08-10 02:07:42 -04:00
SetResult ( KeePass . ExitNormal ) ;
2013-02-23 11:43:42 -05:00
}
2013-08-28 08:00:54 -04:00
2015-09-17 00:01:45 -04:00
protected virtual int ContentResourceId
{
get { return Resource . Layout . group ; }
}
2015-08-19 01:03:12 -04:00
private void InsertElements ( )
2013-08-28 08:00:54 -04:00
{
2015-08-19 01:03:12 -04:00
MoveElementsTask moveElementsTask = ( MoveElementsTask ) AppTask ;
IEnumerable < IStructureItem > elementsToMove =
moveElementsTask . Uuids . Select ( uuid = > App . Kp2a . GetDb ( ) . KpDatabase . RootGroup . FindObject ( uuid , true , null ) ) ;
2013-08-28 08:00:54 -04:00
2015-08-19 01:03:12 -04:00
var moveElement = new MoveElements ( elementsToMove . ToList ( ) , Group , this , App . Kp2a , new ActionOnFinish ( ( success , message ) = > { StopMovingElements ( ) ; if ( ! String . IsNullOrEmpty ( message ) ) Toast . MakeText ( this , message , ToastLength . Long ) . Show ( ) ; } ) ) ;
2013-08-28 08:00:54 -04:00
var progressTask = new ProgressTask ( App . Kp2a , this , moveElement ) ;
progressTask . Run ( ) ;
}
2013-02-23 11:43:42 -05:00
2013-06-15 06:40:01 -04:00
protected void SetGroupTitle ( )
2013-02-23 11:43:42 -05:00
{
2013-06-15 06:40:01 -04:00
String name = Group . Name ;
2013-04-12 23:28:15 -04:00
String titleText ;
2013-06-15 06:40:01 -04:00
bool clickable = ( Group ! = null ) & & ( Group . IsVirtual = = false ) & & ( Group . ParentGroup ! = null ) ;
2013-04-12 23:28:15 -04:00
if ( ! String . IsNullOrEmpty ( name ) )
{
titleText = name ;
} else
{
titleText = GetText ( Resource . String . root ) ;
}
2015-08-10 02:07:42 -04:00
SupportActionBar . Title = titleText ;
if ( clickable )
{
SupportActionBar . SetHomeButtonEnabled ( true ) ;
SupportActionBar . SetDisplayHomeAsUpEnabled ( true ) ;
SupportActionBar . SetDisplayShowHomeEnabled ( true ) ;
}
2013-02-23 11:43:42 -05:00
}
2013-06-15 06:40:01 -04:00
protected void SetGroupIcon ( ) {
if ( Group ! = null ) {
2015-09-13 06:33:24 -04:00
Drawable drawable = App . Kp2a . GetDb ( ) . DrawableFactory . GetIconDrawable ( Resources , App . Kp2a . GetDb ( ) . KpDatabase , Group . IconId , Group . CustomIconUuid , true ) ;
2015-08-10 02:07:42 -04:00
SupportActionBar . SetDisplayShowHomeEnabled ( true ) ;
//SupportActionBar.SetIcon(drawable);
2013-02-23 11:43:42 -05:00
}
}
2014-05-14 01:23:31 -04:00
2015-08-10 02:07:42 -04:00
class SuggestionListener : Java . Lang . Object , SearchView . IOnSuggestionListener , Android . Support . V7 . Widget . SearchView . IOnSuggestionListener
2014-05-14 01:23:31 -04:00
{
private readonly CursorAdapter _suggestionsAdapter ;
2014-05-16 11:15:43 -04:00
private readonly GroupBaseActivity _activity ;
private readonly IMenuItem _searchItem ;
2014-05-14 01:23:31 -04:00
2015-08-10 02:07:42 -04:00
public SuggestionListener ( Android . Support . V4 . Widget . CursorAdapter suggestionsAdapter , GroupBaseActivity activity , IMenuItem searchItem )
2014-05-14 01:23:31 -04:00
{
_suggestionsAdapter = suggestionsAdapter ;
2014-05-16 11:15:43 -04:00
_activity = activity ;
_searchItem = searchItem ;
2014-05-14 01:23:31 -04:00
}
public bool OnSuggestionClick ( int position )
{
var cursor = _suggestionsAdapter . Cursor ;
cursor . MoveToPosition ( position ) ;
2014-05-16 11:15:43 -04:00
string entryIdAsHexString = cursor . GetString ( cursor . GetColumnIndexOrThrow ( SearchManager . SuggestColumnIntentDataId ) ) ;
EntryActivity . Launch ( _activity , App . Kp2a . GetDb ( ) . Entries [ new PwUuid ( MemUtil . HexStringToByteArray ( entryIdAsHexString ) ) ] , - 1 , _activity . AppTask ) ;
2014-05-14 01:23:31 -04:00
return true ;
}
public bool OnSuggestionSelect ( int position )
{
return false ;
}
}
2014-05-16 11:15:43 -04:00
2015-08-10 02:07:42 -04:00
class OnQueryTextListener : Java . Lang . Object , Android . Support . V7 . Widget . SearchView . IOnQueryTextListener
2014-05-16 11:15:43 -04:00
{
private readonly GroupBaseActivity _activity ;
public OnQueryTextListener ( GroupBaseActivity activity )
{
_activity = activity ;
}
public bool OnQueryTextChange ( string newText )
{
return false ;
}
public bool OnQueryTextSubmit ( string query )
{
if ( String . IsNullOrEmpty ( query ) )
return false ; //let the default happen
Intent searchIntent = new Intent ( _activity , typeof ( search . SearchResults ) ) ;
searchIntent . SetAction ( Intent . ActionSearch ) ; //currently not necessary to set because SearchResults doesn't care, but let's be as close to the default as possible
searchIntent . PutExtra ( SearchManager . Query , query ) ;
//forward appTask:
_activity . AppTask . ToIntent ( searchIntent ) ;
_activity . StartActivityForResult ( searchIntent , 0 ) ;
return true ;
}
}
2015-09-01 00:13:55 -04:00
2015-08-19 01:03:12 -04:00
public override bool OnCreateOptionsMenu ( IMenu menu ) {
2015-09-01 00:13:55 -04:00
2015-08-19 01:03:12 -04:00
MenuInflater inflater = MenuInflater ;
inflater . Inflate ( Resource . Menu . group , menu ) ;
2015-08-26 15:01:49 -04:00
var searchManager = ( SearchManager ) GetSystemService ( Context . SearchService ) ;
2015-08-19 01:03:12 -04:00
IMenuItem searchItem = menu . FindItem ( Resource . Id . menu_search ) ;
var view = MenuItemCompat . GetActionView ( searchItem ) ;
var searchView = view . JavaCast < Android . Support . V7 . Widget . SearchView > ( ) ;
2015-08-26 15:01:49 -04:00
searchView . SetSearchableInfo ( searchManager . GetSearchableInfo ( ComponentName ) ) ;
2015-08-19 01:03:12 -04:00
searchView . SetOnSuggestionListener ( new SuggestionListener ( searchView . SuggestionsAdapter , this , searchItem ) ) ;
searchView . SetOnQueryTextListener ( new OnQueryTextListener ( this ) ) ;
2015-09-04 02:12:32 -04:00
2015-10-29 15:31:34 -04:00
ActionBar . LayoutParams lparams = new ActionBar . LayoutParams ( ActionBar . LayoutParams . MatchParent , ActionBar . LayoutParams . MatchParent ) ;
searchView . LayoutParameters = lparams ;
2015-08-10 02:07:42 -04:00
2015-08-19 01:03:12 -04:00
var item = menu . FindItem ( Resource . Id . menu_sync ) ;
if ( item ! = null )
{
if ( App . Kp2a . GetDb ( ) . Ioc . IsLocalFile ( ) )
item . SetVisible ( false ) ;
else
item . SetVisible ( true ) ;
}
2015-09-01 00:13:55 -04:00
return base . OnCreateOptionsMenu ( menu ) ;
2013-08-14 00:05:25 -04:00
}
2015-09-01 00:13:55 -04:00
2015-08-19 01:03:12 -04:00
2014-05-18 12:01:17 -04:00
2013-02-23 11:43:42 -05:00
public override bool OnPrepareOptionsMenu ( IMenu menu ) {
if ( ! base . OnPrepareOptionsMenu ( menu ) ) {
return false ;
}
2014-05-18 12:01:17 -04:00
Util . PrepareDonateOptionMenu ( menu , this ) ;
2014-12-23 14:29:27 -05:00
2013-02-23 11:43:42 -05:00
return true ;
}
public override bool OnOptionsItemSelected ( IMenuItem item ) {
switch ( item . ItemId ) {
2013-04-06 14:26:16 -04:00
case Resource . Id . menu_donate :
2014-05-18 12:01:17 -04:00
return Util . GotoDonateUrl ( this ) ;
2013-02-23 11:43:42 -05:00
case Resource . Id . menu_lock :
2013-07-25 08:47:05 -04:00
App . Kp2a . LockDatabase ( ) ;
2013-02-23 11:43:42 -05:00
return true ;
2013-06-19 13:44:35 -04:00
2013-02-23 11:43:42 -05:00
case Resource . Id . menu_search :
2013-06-19 13:44:35 -04:00
case Resource . Id . menu_search_advanced :
2013-02-23 11:43:42 -05:00
OnSearchRequested ( ) ;
return true ;
case Resource . Id . menu_app_settings :
2013-07-26 15:10:03 -04:00
DatabaseSettingsActivity . Launch ( this ) ;
2013-02-23 11:43:42 -05:00
return true ;
2013-08-14 00:05:25 -04:00
case Resource . Id . menu_sync :
Synchronize ( ) ;
return true ;
2013-02-23 11:43:42 -05:00
case Resource . Id . menu_sort :
2014-12-23 14:29:27 -05:00
ChangeSort ( ) ;
2013-02-23 11:43:42 -05:00
return true ;
2013-04-12 23:28:15 -04:00
case Android . Resource . Id . Home :
//Currently the action bar only displays the home button when we come from a previous activity.
//So we can simply Finish. See this page for information on how to do this in more general (future?) cases:
//http://developer.android.com/training/implementing-navigation/ancestral.html
2013-08-28 08:00:54 -04:00
AppTask . SetActivityResult ( this , KeePass . ExitNormal ) ;
2013-04-12 23:28:15 -04:00
Finish ( ) ;
2015-09-23 14:29:52 -04:00
//OverridePendingTransition(Resource.Animation.anim_enter_back, Resource.Animation.anim_leave_back);
2013-05-17 00:53:58 -04:00
2013-04-12 23:28:15 -04:00
return true ;
2013-02-23 11:43:42 -05:00
}
return base . OnOptionsItemSelected ( item ) ;
}
2013-08-14 00:05:25 -04:00
2013-11-22 15:47:13 -05:00
public class SyncOtpAuxFile : RunnableOnFinish
2013-11-20 13:14:57 -05:00
{
private readonly IOConnectionInfo _ioc ;
2013-11-22 15:47:13 -05:00
public SyncOtpAuxFile ( IOConnectionInfo ioc ) : base ( null )
2013-11-20 13:14:57 -05:00
{
_ioc = ioc ;
}
public override void Run ( )
{
2013-11-22 15:47:13 -05:00
StatusLogger . UpdateMessage ( UiStringKey . SynchronizingOtpAuxFile ) ;
try
2013-11-20 13:14:57 -05:00
{
2013-11-22 15:47:13 -05:00
//simply open the file. The file storage does a complete sync.
using ( App . Kp2a . GetOtpAuxFileStorage ( _ioc ) . OpenFileForRead ( _ioc ) )
{
}
2013-11-20 13:14:57 -05:00
2013-11-22 15:47:13 -05:00
Finish ( true ) ;
}
catch ( Exception e )
2013-11-20 13:14:57 -05:00
{
2013-11-22 15:47:13 -05:00
Finish ( false , e . Message ) ;
2013-11-20 13:14:57 -05:00
}
2013-11-22 15:47:13 -05:00
2013-11-20 13:14:57 -05:00
}
2013-11-22 15:47:13 -05:00
2013-11-20 13:14:57 -05:00
}
2013-08-14 00:05:25 -04:00
private void Synchronize ( )
{
var filestorage = App . Kp2a . GetFileStorage ( App . Kp2a . GetDb ( ) . Ioc ) ;
RunnableOnFinish task ;
2013-11-22 15:47:13 -05:00
OnFinish onFinish = new ActionOnFinish ( ( success , message ) = >
2013-08-14 00:05:25 -04:00
{
if ( ! String . IsNullOrEmpty ( message ) )
Toast . MakeText ( this , message , ToastLength . Long ) . Show ( ) ;
2013-11-22 15:47:13 -05:00
2015-08-10 09:39:34 -04:00
// Tell the adapter to refresh it's list
2014-03-23 10:40:28 -04:00
BaseAdapter adapter = ( BaseAdapter ) ListAdapter ;
adapter . NotifyDataSetChanged ( ) ;
2015-08-10 09:39:34 -04:00
if ( App . Kp2a . GetDb ( ) . OtpAuxFileIoc ! = null )
2013-11-22 15:47:13 -05:00
{
var task2 = new SyncOtpAuxFile ( App . Kp2a . GetDb ( ) . OtpAuxFileIoc ) ;
new ProgressTask ( App . Kp2a , this , task2 ) . Run ( ) ;
}
2013-08-14 00:05:25 -04:00
} ) ;
2013-11-22 15:47:13 -05:00
2013-08-14 00:05:25 -04:00
if ( filestorage is CachingFileStorage )
{
2013-11-22 15:47:13 -05:00
task = new SynchronizeCachedDatabase ( this , App . Kp2a , onFinish ) ;
2013-08-14 00:05:25 -04:00
}
else
{
2013-11-22 15:47:13 -05:00
task = new CheckDatabaseForChanges ( this , App . Kp2a , onFinish ) ;
2013-08-14 00:05:25 -04:00
}
2013-11-22 15:47:13 -05:00
2013-08-14 00:05:25 -04:00
var progressTask = new ProgressTask ( App . Kp2a , this , task ) ;
progressTask . Run ( ) ;
}
2013-08-28 08:00:54 -04:00
public override void OnBackPressed ( )
{
AppTask . SetActivityResult ( this , KeePass . ExitNormal ) ;
base . OnBackPressed ( ) ;
}
2014-12-23 14:29:27 -05:00
private void ChangeSort ( )
{
var sortOrderManager = new GroupViewSortOrderManager ( this ) ;
IEnumerable < string > sortOptions = sortOrderManager . SortOrders . Select (
o = > GetString ( o . ResourceId )
) ;
int selectedBefore = sortOrderManager . GetCurrentSortOrderIndex ( ) ;
new AlertDialog . Builder ( this )
. SetSingleChoiceItems ( sortOptions . ToArray ( ) , selectedBefore , ( sender , args ) = >
{
int selectedAfter = args . Which ;
sortOrderManager . SetNewSortOrder ( selectedAfter ) ;
// Refresh menu titles
ActivityCompat . InvalidateOptionsMenu ( this ) ;
// Mark all groups as dirty now to refresh them on load
Database db = App . Kp2a . GetDb ( ) ;
db . MarkAllGroupsAsDirty ( ) ;
// We'll manually refresh this group so we can remove it
db . Dirty . Remove ( Group ) ;
// Tell the adapter to refresh it's list
2015-08-10 09:39:34 -04:00
2014-12-23 14:29:27 -05:00
BaseAdapter adapter = ( BaseAdapter ) ListAdapter ;
adapter . NotifyDataSetChanged ( ) ;
2015-08-10 09:39:34 -04:00
2013-02-23 11:43:42 -05:00
2014-12-23 14:29:27 -05:00
} )
. SetPositiveButton ( Android . Resource . String . Ok , ( sender , args ) = > ( ( Dialog ) sender ) . Dismiss ( ) )
. Show ( ) ;
2013-02-23 11:43:42 -05:00
}
2014-05-18 12:01:17 -04:00
public class RefreshTask : OnFinish {
2013-06-15 06:40:01 -04:00
readonly GroupBaseActivity _act ;
2013-02-23 11:43:42 -05:00
public RefreshTask ( Handler handler , GroupBaseActivity act ) : base ( handler ) {
2013-06-15 06:40:01 -04:00
_act = act ;
2013-02-23 11:43:42 -05:00
}
2013-06-15 06:40:01 -04:00
public override void Run ( ) {
if ( Success ) {
_act . RefreshIfDirty ( ) ;
2013-02-23 11:43:42 -05:00
} else {
2013-06-15 06:40:01 -04:00
DisplayMessage ( _act ) ;
2013-02-23 11:43:42 -05:00
}
}
}
public class AfterDeleteGroup : OnFinish {
2013-06-15 06:40:01 -04:00
readonly GroupBaseActivity _act ;
2013-02-23 11:43:42 -05:00
public AfterDeleteGroup ( Handler handler , GroupBaseActivity act ) : base ( handler ) {
2013-06-15 06:40:01 -04:00
_act = act ;
2013-02-23 11:43:42 -05:00
}
2013-06-15 06:40:01 -04:00
public override void Run ( ) {
if ( Success ) {
_act . RefreshIfDirty ( ) ;
2013-02-23 11:43:42 -05:00
} else {
2013-06-15 06:40:01 -04:00
Handler . Post ( ( ) = > {
Toast . MakeText ( _act , "Unrecoverable error: " + Message , ToastLength . Long ) . Show ( ) ;
2013-02-23 11:43:42 -05:00
} ) ;
2013-08-09 15:25:54 -04:00
App . Kp2a . LockDatabase ( false ) ;
2013-02-23 11:43:42 -05:00
}
}
}
2013-08-28 08:00:54 -04:00
public bool IsBeingMoved ( PwUuid uuid )
{
2015-08-19 01:03:12 -04:00
MoveElementsTask moveElementsTask = AppTask as MoveElementsTask ;
if ( moveElementsTask ! = null )
2013-08-28 08:00:54 -04:00
{
2015-08-19 01:03:12 -04:00
if ( moveElementsTask . Uuids . Any ( uuidMoved = > uuidMoved . Equals ( uuid ) ) )
2013-08-28 08:00:54 -04:00
return true ;
}
return false ;
}
public void StartTask ( AppTask task )
{
AppTask = task ;
task . StartInGroupActivity ( this ) ;
}
2015-08-19 01:03:12 -04:00
public void StartMovingElements ( )
2013-08-28 08:00:54 -04:00
{
2015-08-10 02:07:42 -04:00
2015-08-19 01:03:12 -04:00
ShowInsertElementsButtons ( ) ;
2015-08-10 02:07:42 -04:00
BaseAdapter adapter = ( BaseAdapter ) ListAdapter ;
2015-08-10 09:39:34 -04:00
adapter . NotifyDataSetChanged ( ) ;
2013-08-28 08:00:54 -04:00
}
2015-08-19 01:03:12 -04:00
public void ShowInsertElementsButtons ( )
2013-08-28 08:00:54 -04:00
{
2015-08-10 02:07:42 -04:00
FindViewById ( Resource . Id . fabCancelAddNew ) . Visibility = ViewStates . Gone ;
FindViewById ( Resource . Id . fabAddNewGroup ) . Visibility = ViewStates . Gone ;
FindViewById ( Resource . Id . fabAddNewEntry ) . Visibility = ViewStates . Gone ;
FindViewById ( Resource . Id . fabAddNew ) . Visibility = ViewStates . Gone ;
FindViewById ( Resource . Id . bottom_bar ) . Visibility = ViewStates . Visible ;
FindViewById ( Resource . Id . divider2 ) . Visibility = ViewStates . Visible ;
2013-08-28 08:00:54 -04:00
}
2015-08-19 01:03:12 -04:00
public void StopMovingElements ( )
2013-08-28 08:00:54 -04:00
{
try
{
2015-08-19 01:03:12 -04:00
MoveElementsTask moveElementsTask = ( MoveElementsTask ) AppTask ;
foreach ( var uuid in moveElementsTask . Uuids )
{
IStructureItem elementToMove = App . Kp2a . GetDb ( ) . KpDatabase . RootGroup . FindObject ( uuid , true , null ) ;
if ( elementToMove . ParentGroup ! = Group )
App . Kp2a . GetDb ( ) . Dirty . Add ( elementToMove . ParentGroup ) ;
}
2013-08-28 08:00:54 -04:00
}
catch ( Exception e )
{
//don't crash if adding to dirty fails but log the exception:
Kp2aLog . Log ( e . ToString ( ) ) ;
}
AppTask = new NullTask ( ) ;
AppTask . SetupGroupBaseActivityButtons ( this ) ;
BaseAdapter adapter = ( BaseAdapter ) ListAdapter ;
2015-08-10 09:39:34 -04:00
adapter . NotifyDataSetChanged ( ) ;
2013-08-28 08:00:54 -04:00
}
2013-09-03 16:58:15 -04:00
public void EditGroup ( PwGroup pwGroup )
{
GroupEditActivity . Launch ( this , pwGroup . ParentGroup , pwGroup ) ;
}
2013-02-23 11:43:42 -05:00
}
2015-08-10 02:07:42 -04:00
public class GroupListFragment : ListFragment , AbsListView . IMultiChoiceModeListener
{
2015-08-19 01:03:12 -04:00
private ActionMode _mode ;
public override void OnActivityCreated ( Bundle savedInstanceState )
2015-08-10 02:07:42 -04:00
{
base . OnActivityCreated ( savedInstanceState ) ;
if ( App . Kp2a . GetDb ( ) . CanWrite )
{
ListView . ChoiceMode = ChoiceMode . MultipleModal ;
ListView . SetMultiChoiceModeListener ( this ) ;
ListView . ItemLongClick + = delegate ( object sender , AdapterView . ItemLongClickEventArgs args )
{
ListView . SetItemChecked ( args . Position , true ) ;
} ;
}
ListView . ItemClick + = ( sender , args ) = > ( ( GroupListItemView ) args . View ) . OnClick ( ) ;
2015-09-15 00:25:17 -04:00
StyleListView ( ) ;
2015-08-10 02:07:42 -04:00
}
2015-09-15 00:25:17 -04:00
protected void StyleListView ( )
2015-08-10 02:07:42 -04:00
{
ListView lv = ListView ;
lv . ScrollBarStyle = ScrollbarStyles . InsideInset ;
lv . TextFilterEnabled = true ;
2015-09-15 00:25:17 -04:00
lv . Divider = null ;
2015-08-10 02:07:42 -04:00
}
public bool OnActionItemClicked ( ActionMode mode , IMenuItem item )
{
2015-08-19 01:03:12 -04:00
var listView = FragmentManager . FindFragmentById < GroupListFragment > ( Resource . Id . list_fragment ) . ListView ;
var checkedItemPositions = listView . CheckedItemPositions ;
List < IStructureItem > checkedItems = new List < IStructureItem > ( ) ;
for ( int i = 0 ; i < checkedItemPositions . Size ( ) ; i + + )
{
if ( checkedItemPositions . ValueAt ( i ) )
{
checkedItems . Add ( ( ( PwGroupListAdapter ) ListAdapter ) . GetItemAtPosition ( checkedItemPositions . KeyAt ( i ) ) ) ;
}
}
//shouldn't happen, just in case...
if ( ! checkedItems . Any ( ) )
{
return false ;
}
2015-08-10 02:07:42 -04:00
switch ( item . ItemId )
{
case Resource . Id . menu_delete :
2015-08-19 01:03:12 -04:00
Handler handler = new Handler ( ) ;
DeleteMultipleItems task = new DeleteMultipleItems ( ( GroupBaseActivity ) Activity , App . Kp2a . GetDb ( ) , checkedItems ,
new GroupBaseActivity . RefreshTask ( handler , ( ( GroupBaseActivity ) Activity ) ) , App . Kp2a ) ;
task . Start ( ) ;
break ;
2015-08-10 02:07:42 -04:00
case Resource . Id . menu_move :
2015-08-19 01:03:12 -04:00
var navMove = new NavigateToFolderAndLaunchMoveElementTask ( checkedItems . First ( ) . ParentGroup , checkedItems . Select ( i = > i . Uuid ) . ToList ( ) , ( ( GroupBaseActivity ) Activity ) . IsSearchResult ) ;
( ( GroupBaseActivity ) Activity ) . StartTask ( navMove ) ;
break ;
2015-09-16 23:26:13 -04:00
case Resource . Id . menu_navigate :
NavigateToFolder navNavigate = new NavigateToFolder ( checkedItems . First ( ) . ParentGroup , true ) ;
2015-08-19 01:03:12 -04:00
( ( GroupBaseActivity ) Activity ) . StartTask ( navNavigate ) ;
2015-09-16 23:26:13 -04:00
break ;
case Resource . Id . menu_edit :
GroupEditActivity . Launch ( Activity , checkedItems . First ( ) . ParentGroup , ( PwGroup ) checkedItems . First ( ) ) ;
break ;
2015-08-19 01:03:12 -04:00
default :
return false ;
2015-08-10 02:07:42 -04:00
}
2015-08-19 01:03:12 -04:00
listView . ClearChoices ( ) ;
( ( BaseAdapter ) ListAdapter ) . NotifyDataSetChanged ( ) ;
if ( _mode ! = null )
mode . Finish ( ) ;
return true ;
2015-08-10 02:07:42 -04:00
}
public bool OnCreateActionMode ( ActionMode mode , IMenu menu )
{
MenuInflater inflater = Activity . MenuInflater ;
inflater . Inflate ( Resource . Menu . group_entriesselected , menu ) ;
//mode.Title = "Select Items";
Android . Util . Log . Debug ( "KP2A" , "Create action mode" + mode ) ;
2015-09-16 23:26:13 -04:00
( ( PwGroupListAdapter ) ListView . Adapter ) . InActionMode = true ;
2015-08-10 02:07:42 -04:00
( ( PwGroupListAdapter ) ListView . Adapter ) . NotifyDataSetChanged ( ) ;
2015-08-19 01:03:12 -04:00
_mode = mode ;
2015-08-10 02:07:42 -04:00
return true ;
}
public void OnDestroyActionMode ( ActionMode mode )
{
Android . Util . Log . Debug ( "KP2A" , "Destroy action mode" + mode ) ;
2015-09-16 23:26:13 -04:00
( ( PwGroupListAdapter ) ListView . Adapter ) . InActionMode = true ;
2015-08-10 02:07:42 -04:00
( ( PwGroupListAdapter ) ListView . Adapter ) . NotifyDataSetChanged ( ) ;
2015-08-19 01:03:12 -04:00
_mode = null ;
2015-08-10 02:07:42 -04:00
}
public bool OnPrepareActionMode ( ActionMode mode , IMenu menu )
{
Android . Util . Log . Debug ( "KP2A" , "Prepare action mode" + mode ) ;
2015-09-16 23:26:13 -04:00
( ( PwGroupListAdapter ) ListView . Adapter ) . InActionMode = mode ! = null ;
2015-08-10 02:07:42 -04:00
( ( PwGroupListAdapter ) ListView . Adapter ) . NotifyDataSetChanged ( ) ;
return true ;
}
public void OnItemCheckedStateChanged ( ActionMode mode , int position , long id , bool @checked )
{
var menuItem = mode . Menu . FindItem ( Resource . Id . menu_edit ) ;
if ( menuItem ! = null )
{
menuItem . SetVisible ( IsOnlyOneGroupChecked ( ) ) ;
}
2015-09-16 23:26:13 -04:00
menuItem = mode . Menu . FindItem ( Resource . Id . menu_navigate ) ;
if ( menuItem ! = null )
{
menuItem . SetVisible ( ( ( GroupBaseActivity ) Activity ) . IsSearchResult & & IsOnlyOneItemChecked ( ) ) ;
}
2015-08-10 02:07:42 -04:00
}
private bool IsOnlyOneGroupChecked ( )
{
var checkedItems = ListView . CheckedItemPositions ;
bool hadCheckedGroup = false ;
if ( checkedItems ! = null )
{
for ( int i = 0 ; i < checkedItems . Size ( ) ; i + + )
{
if ( checkedItems . ValueAt ( i ) )
{
if ( hadCheckedGroup )
{
return false ;
}
if ( ( ( PwGroupListAdapter ) ListAdapter ) . IsGroupAtPosition ( checkedItems . KeyAt ( i ) ) )
{
hadCheckedGroup = true ;
}
else
{
return false ;
}
}
}
}
return hadCheckedGroup ;
}
2015-09-16 23:26:13 -04:00
private bool IsOnlyOneItemChecked ( )
{
var checkedItems = ListView . CheckedItemPositions ;
bool hadCheckedItem = false ;
if ( checkedItems ! = null )
{
for ( int i = 0 ; i < checkedItems . Size ( ) ; i + + )
{
if ( checkedItems . ValueAt ( i ) )
{
if ( hadCheckedItem )
{
return false ;
}
hadCheckedItem = true ;
}
}
}
return hadCheckedItem ;
}
2015-08-10 02:07:42 -04:00
}
2013-02-23 11:43:42 -05:00
}