Refactoring: Introduced "AppTask" concept for simple integration of further features

This commit is contained in:
Philipp Crocoll 2013-05-30 06:54:25 +02:00
parent 7c292ebd57
commit f080f13b20
10 changed files with 343 additions and 53 deletions

View File

@ -49,11 +49,8 @@ namespace keepass2android
public const String KEY_REFRESH_POS = "refresh_pos";
public const String KEY_CLOSE_AFTER_CREATE = "close_after_create";
public static void Launch(Activity act, PwEntry pw, int pos) {
Launch(act, pw, pos, false);
}
public static void Launch(Activity act, PwEntry pw, int pos, bool closeAfterCreate) {
public static void Launch(Activity act, PwEntry pw, int pos, IAppTask appTask) {
Intent i;
i = new Intent(act, typeof(EntryActivity));
@ -61,7 +58,8 @@ namespace keepass2android
i.PutExtra(KEY_ENTRY, pw.Uuid.ToHexString());
i.PutExtra(KEY_REFRESH_POS, pos);
i.PutExtra(KEY_CLOSE_AFTER_CREATE, closeAfterCreate);
appTask.ToIntent(i);
act.StartActivityForResult(i,0);
}
@ -71,6 +69,7 @@ namespace keepass2android
private bool mShowPassword;
private int mPos;
IAppTask mAppTask;
protected void setEntryView() {
@ -116,12 +115,12 @@ namespace keepass2android
PwUuid uuid = new PwUuid(MemUtil.HexStringToByteArray(i.GetStringExtra(KEY_ENTRY)));
mPos = i.GetIntExtra(KEY_REFRESH_POS, -1);
bool closeAfterCreate = i.GetBooleanExtra(KEY_CLOSE_AFTER_CREATE, false);
mAppTask = AppTask.GetTaskInOnCreate(savedInstanceState, Intent);
bool closeAfterCreate = mAppTask.CloseEntryActivityAfterCreate;
mEntry = db.entries [uuid];
// Refresh Menu contents in case onCreateMenuOptions was called before mEntry was set
ActivityCompat.invalidateOptionsMenu(this);

View File

@ -45,11 +45,11 @@ namespace keepass2android
private const String TAG = "Group Activity:";
public static void Launch(Activity act) {
Launch(act, null);
public static void Launch(Activity act, IAppTask appTask) {
Launch(act, null, appTask);
}
public static void Launch (Activity act, PwGroup g)
public static void Launch (Activity act, PwGroup g, IAppTask appTask)
{
Intent i;

View File

@ -40,7 +40,7 @@ namespace keepass2android
public virtual void LaunchActivityForEntry(KeePassLib.PwEntry pwEntry, int pos)
{
EntryActivity.Launch(this, pwEntry, pos, false);
EntryActivity.Launch(this, pwEntry, pos, mAppTask);
}
public GroupBaseActivity ()
{
@ -52,10 +52,18 @@ namespace keepass2android
{
}
protected override void OnSaveInstanceState(Bundle outState)
{
base.OnSaveInstanceState(outState);
mAppTask.ToBundle(outState);
}
private ISharedPreferences prefs;
protected PwGroup mGroup;
internal IAppTask mAppTask;
protected override void OnResume() {
base.OnResume();
@ -90,6 +98,8 @@ namespace keepass2android
protected override void OnCreate(Bundle savedInstanceState) {
base.OnCreate(savedInstanceState);
mAppTask = AppTask.GetTaskInOnCreate(savedInstanceState, Intent);
// Likely the app has been killed exit the activity
if ( ! App.getDB().Loaded ) {

View File

@ -69,6 +69,7 @@ namespace keepass2android
{
base.OnCreate(bundle);
Android.Util.Log.Debug("DEBUG",ClassName+".OnCreate");
Android.Util.Log.Debug("DEBUG", ClassName+":apptask="+Intent.GetStringExtra("KP2A_APP_TASK_TYPE"));
}
protected override void OnDestroy()

View File

@ -87,7 +87,7 @@ namespace keepass2android
ioc.CredSaveMode = (IOCredSaveMode)i.GetIntExtra(KEY_SERVERCREDMODE, (int) IOCredSaveMode.NoSave);
}
public static void Launch(Activity act, String fileName, String urlToSearchFor) {
public static void Launch(Activity act, String fileName, IAppTask appTask) {
Java.IO.File dbFile = new Java.IO.File(fileName);
if ( ! dbFile.Exists() ) {
throw new Java.IO.FileNotFoundException();
@ -96,7 +96,7 @@ namespace keepass2android
Intent i = new Intent(act, typeof(PasswordActivity));
i.PutExtra(KEY_FILENAME, fileName);
i.PutExtra(FileSelectActivity.UrlToSearch_key, urlToSearchFor);
appTask.ToIntent(i);
act.StartActivityForResult(i, 0);
}
@ -108,18 +108,18 @@ namespace keepass2android
}
public static void Launch(Activity act, IOConnectionInfo ioc, String urlToSearchFor)
public static void Launch(Activity act, IOConnectionInfo ioc, IAppTask appTask)
{
if (ioc.IsLocalFile())
{
Launch(act, ioc.Path, urlToSearchFor);
Launch(act, ioc.Path, appTask);
return;
}
Intent i = new Intent(act, typeof(PasswordActivity));
PutIoConnectionToIntent(ioc, i);
i.PutExtra(FileSelectActivity.UrlToSearch_key, urlToSearchFor);
appTask.ToIntent(i);
act.StartActivityForResult(i, 0);
@ -127,13 +127,8 @@ namespace keepass2android
public void LaunchNextActivity()
{
mAppTask.AfterUnlockDatabase(this);
if (String.IsNullOrEmpty(mUrlToSearchFor))
GroupActivity.Launch(this);
else
{
ShareUrlResults.Launch(this, mUrlToSearchFor);
}
}
void unloadDatabase()
@ -284,7 +279,7 @@ namespace keepass2android
}
internal string mUrlToSearchFor;
internal IAppTask mAppTask;
protected override void OnCreate(Bundle savedInstanceState)
{
@ -342,7 +337,7 @@ namespace keepass2android
}
}
this.mUrlToSearchFor = i.GetStringExtra(FileSelectActivity.UrlToSearch_key);
mAppTask = AppTask.GetTaskInOnCreate(savedInstanceState, Intent);
SetContentView(Resource.Layout.password);
populateView();
@ -449,6 +444,12 @@ namespace keepass2android
}
protected override void OnSaveInstanceState(Bundle outState)
{
base.OnSaveInstanceState(outState);
mAppTask.ToBundle(outState);
}
protected override void OnResume() {
base.OnResume();

View File

@ -46,39 +46,38 @@ namespace keepass2android
{
}
public static void Launch(Activity act, string urlToSearchFor)
public static void Launch(Activity act, SearchUrlTask task)
{
Intent i = new Intent(act, typeof(ShareUrlResults));
i.PutExtra(Intent.ExtraText, urlToSearchFor);
task.ToIntent(i);
act.StartActivityForResult(i, 0);
}
private Database mDb;
protected override void OnCreate(Bundle bundle)
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(bundle);
base.OnCreate(savedInstanceState);
SetResult(KeePass.EXIT_CLOSE_AFTER_SEARCH);
mDb = App.getDB();
String searchUrl = getSearchUrl(Intent);
String searchUrl = ((SearchUrlTask)mAppTask).UrlToSearchFor;
if (!mDb.Loaded)
{
Intent intent = new Intent(this, typeof(FileSelectActivity));
intent.PutExtra(FileSelectActivity.UrlToSearch_key, searchUrl);
mAppTask.ToIntent(intent);
StartActivityForResult(intent, 0);
Finish();
}
else if (mDb.Locked)
{
PasswordActivity.Launch(this,mDb.mIoc, searchUrl);
PasswordActivity.Launch(this,mDb.mIoc, mAppTask);
Finish();
}
else
@ -88,9 +87,15 @@ namespace keepass2android
}
protected override void OnSaveInstanceState(Bundle outState)
{
base.OnSaveInstanceState(outState);
mAppTask.ToBundle(outState);
}
public override void LaunchActivityForEntry(KeePassLib.PwEntry pwEntry, int pos)
{
EntryActivity.Launch(this, pwEntry, pos, true);
base.LaunchActivityForEntry(pwEntry, pos);
Finish();
}
@ -133,7 +138,7 @@ namespace keepass2android
}
}
//show results:
if (mGroup == null || (mGroup.Entries.Count() < 1))
{
SetContentView(new GroupEmptyView(this));
@ -146,6 +151,7 @@ namespace keepass2android
ListAdapter = new PwGroupListAdapter(this, mGroup);
//if there is exactly one match: open the entry
if (mGroup.Entries.Count() == 1)
{
LaunchActivityForEntry(mGroup.Entries.Single(),0);

View File

@ -0,0 +1,268 @@
// Copyright (c) 2013 Philipp Crocoll
//
// This program 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 2 of the License, or
// (at your option) any later version.
//
// This program 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 this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
using System;
using Android.App;
using Android.Content;
using Android.OS;
using System.Collections.Generic;
namespace keepass2android
{
/// <summary>
/// Interface for data stored in an intent or bundle as extra string
/// </summary>
public interface IExtra
{
/// <summary>
/// put data to a bundle by calling one of the PutXX methods
/// </summary>
void ToBundle(Bundle b);
/// <summary>
/// Put data to an intent by calling PutExtra
/// </summary>
void ToIntent(Intent i);
}
/// <summary>
/// represents data stored in an intent or bundle as extra string
/// </summary>
public class StringExtra: IExtra
{
public string Key { get; set; }
public string Value{ get; set; }
#region IExtra implementation
public void ToBundle(Bundle b)
{
b.PutString(Key, Value);
}
public void ToIntent(Intent i)
{
i.PutExtra(Key, Value);
}
#endregion
}
/// <summary>
/// interface for "tasks": this are things the user wants to do and which require several activities
/// </summary>
public interface IAppTask
{
/// <summary>
/// Loads the parameters of the task from the given bundle
/// </summary>
void Setup(Bundle b);
/// <summary>
/// Returns the parameters of the task for storage in a bundle or intent
/// </summary>
/// <value>The extras.</value>
IEnumerable<IExtra> Extras { get;}
void AfterUnlockDatabase(PasswordActivity act);
bool CloseEntryActivityAfterCreate
{
get;
}
}
/// <summary>
/// Implementation of IAppTask for "no task currently active" (Null pattern)
/// </summary>
public class NullTask: IAppTask
{
public void Setup(Bundle b)
{
}
public IEnumerable<IExtra> Extras
{
get
{
yield break;
}
}
public void AfterUnlockDatabase(PasswordActivity act)
{
GroupActivity.Launch(act, this);
}
public bool CloseEntryActivityAfterCreate
{
get { return false;}
}
}
/// <summary>
/// User is about to search an entry for a given URL
/// </summary>
public class SearchUrlTask: IAppTask
{
public const String UrlToSearch_key = "UrlToSearch";
public string UrlToSearchFor
{
get;
set;
}
public void Setup(Bundle b)
{
UrlToSearchFor = b.GetString(UrlToSearch_key);
}
public IEnumerable<IExtra> Extras
{
get
{
yield return new StringExtra() { Key=UrlToSearch_key, Value = UrlToSearchFor };
}
}
public void AfterUnlockDatabase(PasswordActivity act)
{
ShareUrlResults.Launch(act, this);
}
public bool CloseEntryActivityAfterCreate
{
get { return true;}
}
}
/// <summary>
/// User is about to select an entry for use in another app
/// </summary>
public class SelectEntryTask: IAppTask
{
public void Setup(Bundle b)
{
}
public IEnumerable<IExtra> Extras
{
get
{
yield break;
}
}
public void AfterUnlockDatabase(PasswordActivity act)
{
GroupActivity.Launch(act, this);
}
public bool CloseEntryActivityAfterCreate
{
//keypoint here: close the app after selecting the entry
get { return true;}
}
}
/// <summary>
///
/// </summary>
public static class AppTask
{
public const String AppTask_key = "KP2A_APPTASK";
/// <summary>
/// Should be used in OnCreate to (re)create a task
/// if savedInstanceState is not null, the task is recreated from there. Otherwise it's taken from the intent.
/// </summary>
public static IAppTask GetTaskInOnCreate(Bundle savedInstanceState, Intent intent)
{
if (savedInstanceState != null)
{
return AppTask.CreateFromBundle(savedInstanceState);
}
else
{
return AppTask.CreateFromIntent(intent);
}
}
public static IAppTask CreateFromIntent(Intent i)
{
return CreateFromBundle(i.Extras);
}
public static IAppTask CreateFromBundle(Bundle b)
{
if (b == null)
return new NullTask();
string taskType = b.GetString("KP2A_APP_TASK_TYPE");
if (string.IsNullOrEmpty(taskType))
return new NullTask();
Type[] types = {typeof(SearchUrlTask), typeof(NullTask)};
foreach (Type type in types)
{
if (taskType == type.Name)
{
IAppTask task = (IAppTask)Activator.CreateInstance(type);
task.Setup(b);
return task;
}
}
return new NullTask();
}
/// <summary>
/// Adds the extras of the task to the intent
/// </summary>
public static void ToIntent(this IAppTask task, Intent intent)
{
AppTask.GetTypeExtra(task.GetType()).ToIntent(intent);
foreach (IExtra extra in task.Extras)
{
extra.ToIntent(intent);
}
}
/// <summary>
/// Adds the extras of the task to the bundle
/// </summary>
public static void ToBundle(this IAppTask task, Bundle bundle)
{
AppTask.GetTypeExtra(task.GetType()).ToBundle(bundle);
foreach (IExtra extra in task.Extras)
{
extra.ToBundle(bundle);
}
}
/// <summary>
/// Returns an IExtra which must be part of the Extras of a task to describe the type
/// </summary>
static IExtra GetTypeExtra(Type type)
{
return new StringExtra() { Key="KP2A_APP_TASK_TYPE", Value=type.Name};
}
}
}

View File

@ -56,17 +56,16 @@ namespace keepass2android
private const int CMENU_CLEAR = Menu.First;
public const String UrlToSearch_key = "UrlToSearch";
const String BundleKey_UrlToSearchFor = "UrlToSearch";
const string BundleKey_RecentMode = "RecentMode";
private FileDbHelper mDbHelper;
private String mUrlToSearch;
private bool recentMode = false;
view.FileSelectButtons fileSelectButtons;
bool createdWithActivityResult = false;
internal IAppTask mAppTask;
IOConnectionInfo loadIoc(string defaultFileName)
{
return mDbHelper.cursorToIoc(mDbHelper.fetchFileByName(defaultFileName));
@ -205,11 +204,16 @@ namespace keepass2android
base.OnCreate(savedInstanceState);
Android.Util.Log.Debug("DEBUG", "FileSelect.OnCreate");
Android.Util.Log.Debug("DEBUG", "FileSelect:apptask="+Intent.GetStringExtra("KP2A_APP_TASK_TYPE"));
if (Intent.Action == Intent.ActionSend)
mUrlToSearch = Intent.GetStringExtra(Intent.ExtraText);
{
mAppTask = new SearchUrlTask() { UrlToSearchFor = Intent.GetStringExtra(Intent.ExtraText) };
}
else
mUrlToSearch = Intent.GetStringExtra(UrlToSearch_key);
{
mAppTask = AppTask.CreateFromIntent(Intent);
}
mDbHelper = App.fileDbHelper;
@ -283,7 +287,7 @@ namespace keepass2android
if (savedInstanceState != null)
{
mUrlToSearch = savedInstanceState.GetString(BundleKey_UrlToSearchFor, null);
mAppTask = AppTask.CreateFromBundle(savedInstanceState);
recentMode = savedInstanceState.GetBoolean(BundleKey_RecentMode, recentMode);
@ -295,18 +299,18 @@ namespace keepass2android
protected override void OnSaveInstanceState(Bundle outState)
{
base.OnSaveInstanceState(outState);
outState.PutString(BundleKey_UrlToSearchFor, mUrlToSearch);
mAppTask.ToBundle(outState);
outState.PutBoolean(BundleKey_RecentMode, recentMode);
}
private class LaunchGroupActivity : FileOnFinish {
FileSelectActivity activty;
FileSelectActivity activity;
private IOConnectionInfo mIoc;
public LaunchGroupActivity(IOConnectionInfo ioc, FileSelectActivity activty): base(null) {
public LaunchGroupActivity(IOConnectionInfo ioc, FileSelectActivity activity): base(null) {
this.activty = activty;
this.activity = activity;
mIoc = ioc;
}
@ -318,7 +322,7 @@ namespace keepass2android
//TODO: getFilename always returns "" -> bug?
dbHelper.createFile(mIoc, getFilename());
GroupActivity.Launch(activty);
GroupActivity.Launch(activity, activity.mAppTask);
} else {
IOConnection.DeleteFile(mIoc);
@ -380,7 +384,7 @@ namespace keepass2android
ioc.UserName = username;
ioc.Password = password;
ioc.CredSaveMode = (IOCredSaveMode)credentialRememberMode;
PasswordActivity.Launch(this, ioc, mUrlToSearch);
PasswordActivity.Launch(this, ioc, mAppTask);
}));
builder.SetView(LayoutInflater.Inflate(Resource.Layout.url_credentials, null));
builder.SetNeutralButton(GetString(Android.Resource.String.Cancel),
@ -395,7 +399,7 @@ namespace keepass2android
{
try
{
PasswordActivity.Launch(this, ioc, mUrlToSearch);
PasswordActivity.Launch(this, ioc, mAppTask);
} catch (Java.IO.FileNotFoundException)
{
Toast.MakeText(this, Resource.String.FileNotFound, ToastLength.Long).Show();
@ -482,7 +486,7 @@ namespace keepass2android
{
if ((Intent.Action == Intent.ActionSend) && (App.getDB().Loaded))
{
PasswordActivity.Launch(this, App.getDB().mIoc , mUrlToSearch);
PasswordActivity.Launch(this, App.getDB().mIoc , mAppTask);
} else
{
@ -498,7 +502,7 @@ namespace keepass2android
{
try
{
PasswordActivity.Launch(this, loadIoc(defaultFileName), mUrlToSearch);
PasswordActivity.Launch(this, loadIoc(defaultFileName), mAppTask);
} catch (Exception e)
{
Toast.MakeText(this, e.Message, ToastLength.Long);

View File

@ -160,6 +160,7 @@
<Compile Include="views\FileSelectButtons.cs" />
<Compile Include="EntryEditActivityState.cs" />
<Compile Include="AttachmentContentProvider.cs" />
<Compile Include="app\AppTask.cs" />
</ItemGroup>
<ItemGroup>
<None Include="Resources\AboutResources.txt" />

View File

@ -89,7 +89,7 @@ namespace keepass2android.view
}
private void launchGroup() {
GroupActivity.Launch(mAct, mPw);
GroupActivity.Launch(mAct, mPw, mAct.mAppTask);
mAct.OverridePendingTransition(Resource.Animation.anim_enter, Resource.Animation.anim_leave);
}