context: /*
  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 <http://www.gnu.org/licenses/>.
    */
  
  using Android.App;
  using Android.Content;
  using Android.Widget;
  using Android.OS;
  using Android.Preferences;
  using Android.Content.PM;
  using Android.Text;
  using Android.Text.Method;
  using Java.Lang;
  using Java.Lang.Reflect;
  using KeePassLib.Serialization;
  using Exception = System.Exception;
  using String = System.String;
  /**
   * General documentation
   * 
   * Activity stack and activity results
   * ===================================
   * 
   * Keepass2Android comprises quite a number of different activities and entry points: The app can be started 
   * using the launcher icon (-> Activity "Keepass"), or by sending a URL (-> FileSelect), opening a .kdb(x)-file (->Password),
   * swiping a YubikeyNEO (NfcOtpActivity).
   * While the database is closed, there is only one activity on the stack: Keepass -> FileSelect <-> Password.
   * After opening an database (in Password), Password is always the root of the stack (exception: after creating a database, 
   * FileSelect is the root without Password being open). 
   * Another exception: QueryCredentialsActivity is root of the stack if an external app is querying credentials.
   * QueryCredentialsActivity checks the plugin access permissions, then launches FileSelectActivity (which starts
   * the normal stack.)
   * 
   * Some possible stacks:
   * Password -> Group ( -> Group (subgroups) ... ) -> EntryView -> EntryEdit
   *                         (AdvancedSearch Menu)  -> Search -> SearchResults -> EntryView -> EntryEdit
   *                         (SearchWidget)         -> SearchResults -> EntryView -> EntryEdit
   * Password -> ShareUrlResults -> EntryView
   * FileSelect -> Group (after Create DB)
   * 
   * 
   * In each of these activities, an AppTask may be present and must be passed to started activities and ActivityResults
   * must be returned. Therefore, if any Activity calls { StartActivity(newActivity);Finish(); }, it must specify FLAG_ACTIVITY_FORWARD_RESULT.
   * 
   * Further sub-activities may be opened (e.g. Settings -> ExportDb, ...), but these are not necesarrily
   * part of the AppTask. Then, neither the task has to be passed nor must the sub-activity return an ActivityResult.
   * 
   * Activities with AppTasks should check if they get a new AppTask in OnActivityResult.
   * 
   * Note: Chrome fires the ActionSend (Share URL) intent with NEW_TASK (i.e. KP2A appears in a separate task, either a new one,
   * or, if it was running before, in the KP2A task), whereas Firefox doesn't specify that flag and KP2A appears "inside" Firefox.
   * This means that the AppTask must be cleared for use in Chrome after finding an entry or pressing back button in ShareUrlResults.
   * This would not be necessary for Firefox where the (Android) Task of standalone KP2A is not affected by the search.
   */
  
  namespace keepass2android
  {
  	/// <summary>
  	/// Launcher activity of Keepass2Android. This activity usually forwards to FileSelect but may show the revision dialog after installation or updates.
  	/// </summary>
  	[Activity (Label = AppNames.AppName, MainLauncher = true, Theme="@style/Base")]
  	public class KeePass : LifecycleDebugActivity
  	{
  		public const Result ExitNormal = Result.FirstUser;
  		public const Result ExitLock = Result.FirstUser+1;
  		public const Result ExitRefresh = Result.FirstUser+2;
  		public const Result ExitRefreshTitle = Result.FirstUser+3;
  		public const Result ExitCloseAfterTaskComplete = Result.FirstUser+4;
  		public const Result TaskComplete = Result.FirstUser + 5;
  		public const Result ExitReloadDb = Result.FirstUser+6;
  		public const Result ExitClose = Result.FirstUser + 7;
  		public const Result ExitFileStorageSelectionOk = Result.FirstUser + 8;
  		public const Result ResultOkPasswordGenerator = Result.FirstUser + 9;
  
  		AppTask _appTask;
  		private ActivityDesign _design;
  
  		protected override void OnCreate(Bundle savedInstanceState)
  		{
  			base.OnCreate(savedInstanceState);
  			_design.ApplyTheme();
  			//see comment to this in PasswordActivity.
  			//Note that this activity is affected even though it's finished when the app is closed because it
  			//seems that the "app launch intent" is re-delivered, so this might end up here.
  			if ((_appTask == null) && (Intent.Flags.HasFlag(ActivityFlags.LaunchedFromHistory)))
  			{
  				_appTask = new NullTask();
  			}
  			else
  			{
  				_appTask = AppTask.GetTaskInOnCreate(savedInstanceState, Intent);
  			}
  
  
  			Kp2aLog.Log("KeePass.OnCreate");
  		}
  
  		protected override void OnResume()
  		{
  			base.OnResume();
  			Kp2aLog.Log("KeePass.OnResume");
  			_design.ReapplyTheme();
  
  		}
  
  
  		protected override void OnStart()
  		{
  			base.OnStart();
  			Kp2aLog.Log("KeePass.OnStart");
  
  			ISharedPreferences prefs = PreferenceManager.GetDefaultSharedPreferences(this);
  			/*if (GetCurrentRuntimeValue().StartsWith("ART"))
  			{
  				
  				if (!prefs.GetBoolean("ART_WARNING", false))
  				{
  
  					ISharedPreferencesEditor edit = prefs.Edit();
  					edit.PutBoolean("ART_WARNING", true);
  					EditorCompat.Apply(edit);
  
  					new AlertDialog.Builder(this)
  					.SetTitle("Warning")
  					.SetMessage(
  						//"It looks like you are running ART (Android Runtime). Please note: At the time of this app's release, Google says ART is experimental. And indeed, the early releases of ART (e.g. in Android 4.4, 4.4.1 and 4.4.2) contain a bug which causes crashes in Mono for Android apps including Keepass2Android. This bug was fixed after the 4.4.2 release so if you have a later Android release, you might be able to use this app. If not, please switch to Dalvik. Please do not downrate Keepass2Android for this problem, it's not our bug :-). Thanks! See our website (keepass2android.codeplex.com) for more information on this issue.")
  						"It looks like you are running ART (Android Runtime). Please note: At the time of this app's release, this app does not run completely stable with ART. I am waiting for more fixes regarding ART from the makers of Mono for Android. As ART is still not yet meant for every-day use, please do not down rate KP2A for this. Thanks.")
  					.SetPositiveButton("OK", (sender, args) => LaunchNextActivity())
  					.Create()
  					.Show();
  
  					return;
  				}
  				
  			}*/
  
  			
  			bool showChangeLog = false;
  			try
  			{
  				PackageInfo packageInfo = PackageManager.GetPackageInfo(PackageName, 0);
  				int lastInfoVersionCode = prefs.GetInt(GetString(Resource.String.LastInfoVersionCode_key), 0);
  				if (packageInfo.VersionCode > lastInfoVersionCode)
  				{
  					showChangeLog = true;
  
  					ISharedPreferencesEditor edit = prefs.Edit();
  					edit.PutInt(GetString(Resource.String.LastInfoVersionCode_key), packageInfo.VersionCode);
  					EditorCompat.Apply(edit);
  				}
  
  			}
  			catch (PackageManager.NameNotFoundException)
  			{
  
  			}
  
  			if (showChangeLog)
  			{
  				ChangeLog.ShowChangeLog(this, LaunchNextActivity);
  			}
  			else
  			{
  				LaunchNextActivity();
  			}
  
  		}
  
  
  
  
  
  		private static String SELECT_RUNTIME_PROPERTY = "persist.sys.dalvik.vm.lib";
  		private static String LIB_DALVIK = "libdvm.so";
  		private static String LIB_ART = "libart.so";
  		private static String LIB_ART_D = "libartd.so";
  		public static string StartWithTask = "keepass2android.ACTION_START_WITH_TASK";
  
  		public KeePass()
  		{
  			_design = new ActivityDesign(this);
  		}
  
  		private String GetCurrentRuntimeValue()
  		{
  			try
  			{
  				Class systemProperties = Class.ForName("android.os.SystemProperties");
  				try
  				{
  					Method get = systemProperties.GetMethod("get",
  					                                        Class.FromType(typeof (Java.Lang.String)),
  					                                        Class.FromType(typeof (Java.Lang.String)));
  					if (get == null)
  					{
  						return "WTF?!";
  					}
  					try
  					{
  
gt: 						String value = (String) get.Invoke(