request permissions at runtime
use externalFilesDir when creating a database to make sure we don't need permissions here revert Support Design library to previous version, had issues with 23.x
This commit is contained in:
		| @@ -3,18 +3,25 @@ using System.Collections.Generic; | |||||||
| using System.Globalization; | using System.Globalization; | ||||||
| using System.IO; | using System.IO; | ||||||
| using System.Net; | using System.Net; | ||||||
| using System.Net.Security; |  | ||||||
| using System.Security; | using System.Security; | ||||||
|  | using Android; | ||||||
|  | using Android.App; | ||||||
| using Android.Content; | using Android.Content; | ||||||
|  | using Android.Content.PM; | ||||||
| using Android.OS; | using Android.OS; | ||||||
| using Java.Security.Cert; | using Java.IO; | ||||||
| using KeePassLib.Serialization; | using KeePassLib.Serialization; | ||||||
| using KeePassLib.Utility; | using KeePassLib.Utility; | ||||||
|  | using File = System.IO.File; | ||||||
|  | using FileNotFoundException = System.IO.FileNotFoundException; | ||||||
|  | using IOException = System.IO.IOException; | ||||||
|  |  | ||||||
| namespace keepass2android.Io | namespace keepass2android.Io | ||||||
| { | { | ||||||
| 	public class BuiltInFileStorage: IFileStorage | 	public class BuiltInFileStorage : IFileStorage, IPermissionRequestingFileStorage | ||||||
| 	{ | 	{ | ||||||
|  | 		private const string PermissionGrantedKey = "PermissionGranted"; | ||||||
|  |  | ||||||
| 		public enum CertificateProblem :long | 		public enum CertificateProblem :long | ||||||
| 		{ | 		{ | ||||||
| 			CertEXPIRED = 0x800B0101, | 			CertEXPIRED = 0x800B0101, | ||||||
| @@ -112,7 +119,8 @@ namespace keepass2android.Io | |||||||
|  |  | ||||||
| 		private void ConvertException(IOConnectionInfo ioc, WebException ex) | 		private void ConvertException(IOConnectionInfo ioc, WebException ex) | ||||||
| 		{ | 		{ | ||||||
| 			if ((ex.Response is HttpWebResponse) && (((HttpWebResponse) ex.Response).StatusCode == HttpStatusCode.NotFound)) | 			var response = ex.Response as HttpWebResponse; | ||||||
|  | 			if ((response != null) && (response.StatusCode == HttpStatusCode.NotFound)) | ||||||
| 			{ | 			{ | ||||||
| 				throw new FileNotFoundException(ex.Message, ioc.Path, ex); | 				throw new FileNotFoundException(ex.Message, ioc.Path, ex); | ||||||
| 			} | 			} | ||||||
| @@ -241,6 +249,26 @@ namespace keepass2android.Io | |||||||
|  |  | ||||||
| 		public void PrepareFileUsage(IFileStorageSetupInitiatorActivity activity, IOConnectionInfo ioc, int requestCode, bool alwaysReturnSuccess) | 		public void PrepareFileUsage(IFileStorageSetupInitiatorActivity activity, IOConnectionInfo ioc, int requestCode, bool alwaysReturnSuccess) | ||||||
| 		{ | 		{ | ||||||
|  | 			//check if we need to request the external-storage-permission at runtime | ||||||
|  | 			if (ioc.IsLocalFile()) | ||||||
|  | 			{ | ||||||
|  | 				bool requiresPermission = !ioc.Path.StartsWith(activity.Activity.FilesDir.CanonicalPath); | ||||||
|  | 				 | ||||||
|  | 				var extDirectory = activity.Activity.GetExternalFilesDir(null); | ||||||
|  | 				if ((extDirectory != null) && (ioc.Path.StartsWith(extDirectory.CanonicalPath))) | ||||||
|  | 					requiresPermission = false; | ||||||
|  |  | ||||||
|  | 				if (requiresPermission && (Build.VERSION.SdkInt >= BuildVersionCodes.M)) | ||||||
|  | 				{ | ||||||
|  | 					if (activity.Activity.CheckSelfPermission(Manifest.Permission.WriteExternalStorage) == | ||||||
|  | 						Permission.Denied) | ||||||
|  | 					{ | ||||||
|  | 						activity.StartFileUsageProcess(ioc, requestCode, alwaysReturnSuccess); | ||||||
|  | 						return; | ||||||
|  | 					}	 | ||||||
|  | 				} | ||||||
|  | 				 | ||||||
|  | 			} | ||||||
| 			Intent intent = new Intent(); | 			Intent intent = new Intent(); | ||||||
| 			activity.IocToIntent(intent, ioc); | 			activity.IocToIntent(intent, ioc); | ||||||
| 			activity.OnImmediateResult(requestCode, (int) FileStorageResults.FileUsagePrepared, intent); | 			activity.OnImmediateResult(requestCode, (int) FileStorageResults.FileUsagePrepared, intent); | ||||||
| @@ -251,24 +279,42 @@ namespace keepass2android.Io | |||||||
| 			//nothing to do, we're ready to go | 			//nothing to do, we're ready to go | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		public void OnCreate(IFileStorageSetupActivity activity, Bundle savedInstanceState) | 		public void OnCreate(IFileStorageSetupActivity fileStorageSetupActivity, Bundle savedInstanceState) | ||||||
| 		{ | 		{ | ||||||
| 			throw new NotImplementedException(); | 			((Activity)fileStorageSetupActivity).RequestPermissions(new[] { Manifest.Permission.WriteExternalStorage }, 0); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		public void OnResume(IFileStorageSetupActivity activity) | 		public void OnResume(IFileStorageSetupActivity activity) | ||||||
| 		{ | 		{ | ||||||
| 			throw new NotImplementedException(); | 			if (activity.State.ContainsKey(PermissionGrantedKey)) | ||||||
|  | 			{ | ||||||
|  | 				if (activity.State.GetBoolean(PermissionGrantedKey)) | ||||||
|  | 				{ | ||||||
|  | 					Intent data = new Intent(); | ||||||
|  | 					data.PutExtra(FileStorageSetupDefs.ExtraIsForSave, activity.IsForSave); | ||||||
|  | 					data.PutExtra(FileStorageSetupDefs.ExtraPath, IocToPath(activity.Ioc)); | ||||||
|  | 					((Activity) activity).SetResult((Result) FileStorageResults.FileUsagePrepared, data); | ||||||
|  | 					((Activity) activity).Finish(); | ||||||
|  | 				} | ||||||
|  | 				else | ||||||
|  | 				{ | ||||||
|  | 					Intent data = new Intent(); | ||||||
|  | 					data.PutExtra(FileStorageSetupDefs.ExtraErrorMessage, "Permission denied. Please grant file access permission for this app."); | ||||||
|  | 					((Activity)activity).SetResult(Result.Canceled, data); | ||||||
|  | 					((Activity)activity).Finish(); | ||||||
|  | 					 | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		public void OnStart(IFileStorageSetupActivity activity) | 		public void OnStart(IFileStorageSetupActivity activity) | ||||||
| 		{ | 		{ | ||||||
| 			throw new NotImplementedException(); | 			 | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		public void OnActivityResult(IFileStorageSetupActivity activity, int requestCode, int resultCode, Intent data) | 		public void OnActivityResult(IFileStorageSetupActivity activity, int requestCode, int resultCode, Intent data) | ||||||
| 		{ | 		{ | ||||||
| 			throw new NotImplementedException(); | 			 | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		public string GetDisplayName(IOConnectionInfo ioc) | 		public string GetDisplayName(IOConnectionInfo ioc) | ||||||
| @@ -310,7 +356,7 @@ namespace keepass2android.Io | |||||||
| 			{ | 			{ | ||||||
| 				//test if we can open  | 				//test if we can open  | ||||||
| 				//http://www.doubleencore.com/2014/03/android-external-storage/#comment-1294469517 | 				//http://www.doubleencore.com/2014/03/android-external-storage/#comment-1294469517 | ||||||
| 				using (var writer = new Java.IO.FileOutputStream(ioc.Path, true)) | 				using (var writer = new FileOutputStream(ioc.Path, true)) | ||||||
| 				{ | 				{ | ||||||
| 					writer.Close(); | 					writer.Close(); | ||||||
| 					return false; //we can write | 					return false; //we can write | ||||||
| @@ -358,5 +404,11 @@ namespace keepass2android.Io | |||||||
| 				return false; | 				return false; | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|  | 		public void OnRequestPermissionsResult(IFileStorageSetupActivity fileStorageSetupActivity, int requestCode, | ||||||
|  | 			string[] permissions, Permission[] grantResults) | ||||||
|  | 		{ | ||||||
|  | 			fileStorageSetupActivity.State.PutBoolean(PermissionGrantedKey, grantResults[0] == Permission.Granted); | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| @@ -5,6 +5,7 @@ using System.Net; | |||||||
| using System.Security.Cryptography; | using System.Security.Cryptography; | ||||||
| using System.Text; | using System.Text; | ||||||
| using Android.Content; | using Android.Content; | ||||||
|  | using Android.Content.PM; | ||||||
| using Android.OS; | using Android.OS; | ||||||
| using KeePassLib.Cryptography; | using KeePassLib.Cryptography; | ||||||
| using KeePassLib.Serialization; | using KeePassLib.Serialization; | ||||||
| @@ -59,7 +60,7 @@ namespace keepass2android.Io | |||||||
| 	/// Implements the IFileStorage interface as a proxy: A base storage is used as a remote storage. Local files are used to cache the | 	/// Implements the IFileStorage interface as a proxy: A base storage is used as a remote storage. Local files are used to cache the | ||||||
| 	/// files on remote. | 	/// files on remote. | ||||||
| 	/// </summary> | 	/// </summary> | ||||||
| 	public class CachingFileStorage : IFileStorage, IOfflineSwitchable | 	public class CachingFileStorage : IFileStorage, IOfflineSwitchable, IPermissionRequestingFileStorage | ||||||
| 	{ | 	{ | ||||||
| 		 | 		 | ||||||
| 		protected readonly OfflineSwitchableFileStorage _cachedStorage; | 		protected readonly OfflineSwitchableFileStorage _cachedStorage; | ||||||
| @@ -618,5 +619,11 @@ namespace keepass2android.Io | |||||||
| 			get { return _cachedStorage.IsOffline; } | 			get { return _cachedStorage.IsOffline; } | ||||||
| 			set { _cachedStorage.IsOffline = value; } | 			set { _cachedStorage.IsOffline = value; } | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|  | 		public void OnRequestPermissionsResult(IFileStorageSetupActivity fileStorageSetupActivity, int requestCode, | ||||||
|  | 			string[] permissions, Permission[] grantResults) | ||||||
|  | 		{ | ||||||
|  | 			_cachedStorage.OnRequestPermissionsResult(fileStorageSetupActivity, requestCode, permissions, grantResults); | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|   | |||||||
| @@ -2,6 +2,7 @@ using System; | |||||||
| using System.Collections.Generic; | using System.Collections.Generic; | ||||||
| using System.IO; | using System.IO; | ||||||
| using Android.Content; | using Android.Content; | ||||||
|  | using Android.Content.PM; | ||||||
| using Android.OS; | using Android.OS; | ||||||
| using KeePassLib.Serialization; | using KeePassLib.Serialization; | ||||||
|  |  | ||||||
| @@ -22,7 +23,7 @@ namespace keepass2android.Io | |||||||
|  |  | ||||||
| 		public static String ExtraProcessName = "EXTRA_PROCESS_NAME"; | 		public static String ExtraProcessName = "EXTRA_PROCESS_NAME"; | ||||||
| 		public static String ExtraAlwaysReturnSuccess = "EXTRA_ALWAYS_RETURN_SUCCESS"; | 		public static String ExtraAlwaysReturnSuccess = "EXTRA_ALWAYS_RETURN_SUCCESS"; | ||||||
| 		public static String ExtraPath = "PATH"; | 		public static String ExtraPath = "fileName"; //match KP2A PasswordActivity Ioc-Path Extra key | ||||||
| 		public static String ExtraIsForSave = "IS_FOR_SAVE"; | 		public static String ExtraIsForSave = "IS_FOR_SAVE"; | ||||||
| 		public static String ExtraErrorMessage = "EXTRA_ERROR_MESSAGE"; | 		public static String ExtraErrorMessage = "EXTRA_ERROR_MESSAGE"; | ||||||
|  |  | ||||||
| @@ -170,6 +171,11 @@ namespace keepass2android.Io | |||||||
| 		bool IsReadOnly(IOConnectionInfo ioc); | 		bool IsReadOnly(IOConnectionInfo ioc); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	public interface IPermissionRequestingFileStorage | ||||||
|  | 	{ | ||||||
|  | 		void OnRequestPermissionsResult(IFileStorageSetupActivity fileStorageSetupActivity, int requestCode, string[] permissions, Permission[] grantResults); | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	public interface IWriteTransaction: IDisposable | 	public interface IWriteTransaction: IDisposable | ||||||
| 	{ | 	{ | ||||||
| 		Stream OpenFile(); | 		Stream OpenFile(); | ||||||
|   | |||||||
| @@ -4,6 +4,7 @@ using System.IO; | |||||||
| using System.Linq; | using System.Linq; | ||||||
| using Android.App; | using Android.App; | ||||||
| using Android.Content; | using Android.Content; | ||||||
|  | using Android.Content.PM; | ||||||
| using Android.OS; | using Android.OS; | ||||||
| using KeePassLib.Serialization; | using KeePassLib.Serialization; | ||||||
| using KeePassLib.Utility; | using KeePassLib.Utility; | ||||||
| @@ -16,7 +17,7 @@ using FileNotFoundException = Java.IO.FileNotFoundException; | |||||||
| namespace keepass2android.Io | namespace keepass2android.Io | ||||||
| { | { | ||||||
| 	#if !EXCLUDE_JAVAFILESTORAGE | 	#if !EXCLUDE_JAVAFILESTORAGE | ||||||
| 	public abstract class JavaFileStorage: IFileStorage | 	public abstract class JavaFileStorage: IFileStorage, IPermissionRequestingFileStorage | ||||||
| 	{ | 	{ | ||||||
| 		protected string Protocol { get { return _jfs.ProtocolId; } } | 		protected string Protocol { get { return _jfs.ProtocolId; } } | ||||||
|  |  | ||||||
| @@ -356,6 +357,12 @@ namespace keepass2android.Io | |||||||
| 			return ioc.Path; | 			return ioc.Path; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|  | 		public void OnRequestPermissionsResult(IFileStorageSetupActivity fileStorageSetupActivity, int requestCode, | ||||||
|  | 			string[] permissions, Permission[] grantResults) | ||||||
|  | 		{ | ||||||
|  | 			_jfs.OnRequestPermissionsResult(((IJavaFileStorageFileStorageSetupActivity) fileStorageSetupActivity), requestCode, | ||||||
|  | 				permissions, grantResults.Select(p => (int)p).ToArray()); | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
| #endif | #endif | ||||||
| } | } | ||||||
| @@ -2,6 +2,7 @@ using System; | |||||||
| using System.Collections.Generic; | using System.Collections.Generic; | ||||||
| using System.IO; | using System.IO; | ||||||
| using Android.Content; | using Android.Content; | ||||||
|  | using Android.Content.PM; | ||||||
| using Android.OS; | using Android.OS; | ||||||
| using KeePassLib.Serialization; | using KeePassLib.Serialization; | ||||||
|  |  | ||||||
| @@ -16,7 +17,7 @@ namespace keepass2android.Io | |||||||
| 	/// Encapsulates another IFileStorage. Allows to switch to offline mode by throwing | 	/// Encapsulates another IFileStorage. Allows to switch to offline mode by throwing | ||||||
| 	/// an exception when trying to read or write a file. | 	/// an exception when trying to read or write a file. | ||||||
| 	/// </summary> | 	/// </summary> | ||||||
| 	public class OfflineSwitchableFileStorage : IFileStorage, IOfflineSwitchable | 	public class OfflineSwitchableFileStorage : IFileStorage, IOfflineSwitchable, IPermissionRequestingFileStorage | ||||||
| 	{ | 	{ | ||||||
| 		private readonly IFileStorage _baseStorage; | 		private readonly IFileStorage _baseStorage; | ||||||
| 		public bool IsOffline { get; set; } | 		public bool IsOffline { get; set; } | ||||||
| @@ -179,6 +180,15 @@ namespace keepass2android.Io | |||||||
| 		{ | 		{ | ||||||
| 			return _baseStorage.IsReadOnly(ioc); | 			return _baseStorage.IsReadOnly(ioc); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|  | 	public void OnRequestPermissionsResult(IFileStorageSetupActivity fileStorageSetupActivity, int requestCode, | ||||||
|  | 		string[] permissions, Permission[] grantResults) | ||||||
|  | 	{ | ||||||
|  | 		if (_baseStorage is IPermissionRequestingFileStorage) | ||||||
|  | 		{ | ||||||
|  | 			((IPermissionRequestingFileStorage)_baseStorage).OnRequestPermissionsResult(fileStorageSetupActivity, requestCode, permissions, grantResults); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	public class OfflineModeException : Exception | 	public class OfflineModeException : Exception | ||||||
|   | |||||||
| @@ -12,7 +12,8 @@ | |||||||
|     <FileAlignment>512</FileAlignment> |     <FileAlignment>512</FileAlignment> | ||||||
|     <AndroidResgenFile>Resources\Resource.Designer.cs</AndroidResgenFile> |     <AndroidResgenFile>Resources\Resource.Designer.cs</AndroidResgenFile> | ||||||
|     <GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies> |     <GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies> | ||||||
|     <TargetFrameworkVersion>v5.0</TargetFrameworkVersion> |     <TargetFrameworkVersion>v6.0</TargetFrameworkVersion> | ||||||
|  |     <AndroidUseLatestPlatformSdk>False</AndroidUseLatestPlatformSdk> | ||||||
|   </PropertyGroup> |   </PropertyGroup> | ||||||
|   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> |   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> | ||||||
|     <DebugSymbols>true</DebugSymbols> |     <DebugSymbols>true</DebugSymbols> | ||||||
|   | |||||||
| @@ -85,7 +85,7 @@ | |||||||
|       <excludeFolder url="file://$MODULE_DIR$/build/outputs" /> |       <excludeFolder url="file://$MODULE_DIR$/build/outputs" /> | ||||||
|       <excludeFolder url="file://$MODULE_DIR$/build/tmp" /> |       <excludeFolder url="file://$MODULE_DIR$/build/tmp" /> | ||||||
|     </content> |     </content> | ||||||
|     <orderEntry type="jdk" jdkName="Android API 21 Platform" jdkType="Android SDK" /> |     <orderEntry type="jdk" jdkName="Android API 23 Platform" jdkType="Android SDK" /> | ||||||
|     <orderEntry type="sourceFolder" forTests="false" /> |     <orderEntry type="sourceFolder" forTests="false" /> | ||||||
|     <orderEntry type="library" exported="" name="httpmime-4.0.3" level="project" /> |     <orderEntry type="library" exported="" name="httpmime-4.0.3" level="project" /> | ||||||
|     <orderEntry type="library" exported="" name="jsr305-1.3.9" level="project" /> |     <orderEntry type="library" exported="" name="jsr305-1.3.9" level="project" /> | ||||||
| @@ -104,8 +104,8 @@ | |||||||
|     <orderEntry type="library" exported="" name="httpcore-4.0.1" level="project" /> |     <orderEntry type="library" exported="" name="httpcore-4.0.1" level="project" /> | ||||||
|     <orderEntry type="library" exported="" name="json_simple-1.1" level="project" /> |     <orderEntry type="library" exported="" name="json_simple-1.1" level="project" /> | ||||||
|     <orderEntry type="library" exported="" name="google-http-client-android-1.16.0-rc" level="project" /> |     <orderEntry type="library" exported="" name="google-http-client-android-1.16.0-rc" level="project" /> | ||||||
|     <orderEntry type="library" exported="" name="google-http-client-gson-1.20.0" level="project" /> |  | ||||||
|     <orderEntry type="library" exported="" name="gson-2.1" level="project" /> |     <orderEntry type="library" exported="" name="gson-2.1" level="project" /> | ||||||
|  |     <orderEntry type="library" exported="" name="google-http-client-gson-1.20.0" level="project" /> | ||||||
|     <orderEntry type="library" exported="" name="google-http-client-jackson-1.16.0-rc" level="project" /> |     <orderEntry type="library" exported="" name="google-http-client-jackson-1.16.0-rc" level="project" /> | ||||||
|     <orderEntry type="library" exported="" name="commons-logging-1.1.1" level="project" /> |     <orderEntry type="library" exported="" name="commons-logging-1.1.1" level="project" /> | ||||||
|   </component> |   </component> | ||||||
|   | |||||||
| @@ -1,20 +1,20 @@ | |||||||
| apply plugin: 'com.android.library' | apply plugin: 'com.android.library' | ||||||
|  |  | ||||||
| android { | android { | ||||||
|     compileSdkVersion 21 |     compileSdkVersion 23 | ||||||
|     buildToolsVersion "21.1.2" |     buildToolsVersion '23.0.0' | ||||||
|  |  | ||||||
|     defaultConfig { |     defaultConfig { | ||||||
|         minSdkVersion 14 |         minSdkVersion 14 | ||||||
|         targetSdkVersion 21 |         targetSdkVersion 23 | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     buildTypes { |     buildTypes { | ||||||
|         release { |         release { | ||||||
|             minifyEnabled true |             minifyEnabled true | ||||||
|             proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-project.txt' |             proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-project.txt' | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |     productFlavors { | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| dependencies { | dependencies { | ||||||
|   | |||||||
										
											Binary file not shown.
										
									
								
							| @@ -27,11 +27,14 @@ import com.google.api.services.drive.model.File; | |||||||
| import com.google.api.services.drive.model.FileList; | import com.google.api.services.drive.model.FileList; | ||||||
| import com.google.api.services.drive.model.ParentReference; | import com.google.api.services.drive.model.ParentReference; | ||||||
|  |  | ||||||
|  | import android.Manifest; | ||||||
| import android.accounts.AccountManager; | import android.accounts.AccountManager; | ||||||
| import android.app.Activity; | import android.app.Activity; | ||||||
| import android.content.Context; | import android.content.Context; | ||||||
| import android.content.Intent; | import android.content.Intent; | ||||||
|  | import android.content.pm.PackageManager; | ||||||
| import android.os.AsyncTask; | import android.os.AsyncTask; | ||||||
|  | import android.os.Build; | ||||||
| import android.os.Bundle; | import android.os.Bundle; | ||||||
| import android.text.TextUtils; | import android.text.TextUtils; | ||||||
|  |  | ||||||
| @@ -43,7 +46,7 @@ public class GoogleDriveFileStorage extends JavaFileStorageBase { | |||||||
| 	static final int MAGIC_GDRIVE=2082334; | 	static final int MAGIC_GDRIVE=2082334; | ||||||
| 	static final int REQUEST_ACCOUNT_PICKER = MAGIC_GDRIVE+1; | 	static final int REQUEST_ACCOUNT_PICKER = MAGIC_GDRIVE+1; | ||||||
| 	static final int REQUEST_AUTHORIZATION = MAGIC_GDRIVE+2; | 	static final int REQUEST_AUTHORIZATION = MAGIC_GDRIVE+2; | ||||||
|  | 	private boolean mRequiresRuntimePermissions = false; | ||||||
|  |  | ||||||
|  |  | ||||||
| 	class FileSystemEntryData | 	class FileSystemEntryData | ||||||
| @@ -253,7 +256,7 @@ public class GoogleDriveFileStorage extends JavaFileStorageBase { | |||||||
| 	 | 	 | ||||||
| 	public GoogleDriveFileStorage() | 	public GoogleDriveFileStorage() | ||||||
| 	{ | 	{ | ||||||
| 		logDebug("Creating GDrive FileStorage"); | 		logDebug("Creating GDrive FileStorage."); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	@Override | 	@Override | ||||||
| @@ -370,7 +373,7 @@ public class GoogleDriveFileStorage extends JavaFileStorageBase { | |||||||
| 		GDrivePath parentGdrivePath = new GDrivePath(parentPath); | 		GDrivePath parentGdrivePath = new GDrivePath(parentPath); | ||||||
| 		 | 		 | ||||||
| 		body.setParents( | 		body.setParents( | ||||||
| 		          Arrays.asList(new ParentReference().setId(parentGdrivePath.getGDriveId()))); | 				Arrays.asList(new ParentReference().setId(parentGdrivePath.getGDriveId()))); | ||||||
| 		try | 		try | ||||||
| 		{ | 		{ | ||||||
| 			File file = getDriveService(parentGdrivePath.getAccount()).files().insert(body).execute(); | 			File file = getDriveService(parentGdrivePath.getAccount()).files().insert(body).execute(); | ||||||
| @@ -393,7 +396,7 @@ public class GoogleDriveFileStorage extends JavaFileStorageBase { | |||||||
| 		GDrivePath parentGdrivePath = new GDrivePath(parentPath); | 		GDrivePath parentGdrivePath = new GDrivePath(parentPath); | ||||||
| 		 | 		 | ||||||
| 		body.setParents( | 		body.setParents( | ||||||
| 		          Arrays.asList(new ParentReference().setId(parentGdrivePath.getGDriveId()))); | 				Arrays.asList(new ParentReference().setId(parentGdrivePath.getGDriveId()))); | ||||||
| 		try | 		try | ||||||
| 		{ | 		{ | ||||||
| 			File file = getDriveService(parentGdrivePath.getAccount()).files().insert(body).execute(); | 			File file = getDriveService(parentGdrivePath.getAccount()).files().insert(body).execute(); | ||||||
| @@ -424,7 +427,7 @@ public class GoogleDriveFileStorage extends JavaFileStorageBase { | |||||||
| 				throw new FileNotFoundException(parentPath + " is trashed!"); | 				throw new FileNotFoundException(parentPath + " is trashed!"); | ||||||
| 			logDebug("listing files in "+parentId); | 			logDebug("listing files in "+parentId); | ||||||
| 			Files.List request = driveService.files().list() | 			Files.List request = driveService.files().list() | ||||||
| 					.setQ("trashed=false and '"+parentId+"' in parents"); | 					.setQ("trashed=false and '" + parentId + "' in parents"); | ||||||
| 	 | 	 | ||||||
| 			do { | 			do { | ||||||
| 				try { | 				try { | ||||||
| @@ -505,7 +508,7 @@ public class GoogleDriveFileStorage extends JavaFileStorageBase { | |||||||
| 			FileEntry res =  convertToFileEntry( | 			FileEntry res =  convertToFileEntry( | ||||||
| 					getFileForPath(gdrivePath, getDriveService(gdrivePath.getAccount())), | 					getFileForPath(gdrivePath, getDriveService(gdrivePath.getAccount())), | ||||||
| 					filename); | 					filename); | ||||||
| 			logDebug("getFileEntry res"+res); | 			logDebug("getFileEntry res" + res); | ||||||
| 			return res; | 			return res; | ||||||
| 		} | 		} | ||||||
| 		catch (Exception e) | 		catch (Exception e) | ||||||
| @@ -551,13 +554,13 @@ public class GoogleDriveFileStorage extends JavaFileStorageBase { | |||||||
| 	{ | 	{ | ||||||
| 		logDebug("getDriveService "+accountName); | 		logDebug("getDriveService "+accountName); | ||||||
| 		AccountData accountData = mAccountData.get(accountName); | 		AccountData accountData = mAccountData.get(accountName); | ||||||
| 		logDebug("accountData "+accountData); | 		logDebug("accountData " + accountData); | ||||||
| 		return accountData.drive; | 		return accountData.drive; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	@Override | 	@Override | ||||||
| 	public void onActivityResult(final JavaFileStorage.FileStorageSetupActivity setupAct, int requestCode, int resultCode, Intent data) { | 	public void onActivityResult(final JavaFileStorage.FileStorageSetupActivity setupAct, int requestCode, int resultCode, Intent data) { | ||||||
| 		logDebug("ActivityResult: "+requestCode+"/"+resultCode); | 		logDebug("ActivityResult: " + requestCode + "/" + resultCode); | ||||||
| 		switch (requestCode) { | 		switch (requestCode) { | ||||||
| 		case REQUEST_ACCOUNT_PICKER: | 		case REQUEST_ACCOUNT_PICKER: | ||||||
| 			logDebug("ActivityResult: REQUEST_ACCOUNT_PICKER"); | 			logDebug("ActivityResult: REQUEST_ACCOUNT_PICKER"); | ||||||
| @@ -773,6 +776,38 @@ public class GoogleDriveFileStorage extends JavaFileStorageBase { | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 	@Override | ||||||
|  | 	public void onRequestPermissionsResult(FileStorageSetupActivity setupAct, int requestCode, String[] permissions, int[] grantResults) | ||||||
|  | 	{ | ||||||
|  | 		logDebug("onRequestPermissionsResult"); | ||||||
|  | 		if (grantResults[0] == PackageManager.PERMISSION_GRANTED) | ||||||
|  | 		{ | ||||||
|  | 			logDebug("granted"); | ||||||
|  | 			initFileStorage(setupAct); | ||||||
|  | 		} | ||||||
|  | 		else | ||||||
|  | 		{ | ||||||
|  | 			logDebug("denied"); | ||||||
|  | 			finishWithError(setupAct, new Exception("You must grant the requested permissions to continue.")); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	private void initFileStorage(FileStorageSetupActivity setupAct) { | ||||||
|  | 		Activity activity = (Activity)setupAct; | ||||||
|  |  | ||||||
|  | 		if (PROCESS_NAME_SELECTFILE.equals(setupAct.getProcessName())) | ||||||
|  |         { | ||||||
|  |             GoogleAccountCredential credential = createCredential(activity.getApplicationContext()); | ||||||
|  |  | ||||||
|  |             logDebug("starting REQUEST_ACCOUNT_PICKER"); | ||||||
|  |             activity.startActivityForResult(credential.newChooseAccountIntent(), REQUEST_ACCOUNT_PICKER); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  | 		if (PROCESS_NAME_FILE_USAGE_SETUP.equals(setupAct.getProcessName())) | ||||||
|  |         { | ||||||
|  |             initializeAccountOrPath(setupAct, setupAct.getPath()); | ||||||
|  |         } | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	@Override | 	@Override | ||||||
| 	public void onResume(JavaFileStorage.FileStorageSetupActivity setupAct) { | 	public void onResume(JavaFileStorage.FileStorageSetupActivity setupAct) { | ||||||
| @@ -781,22 +816,13 @@ public class GoogleDriveFileStorage extends JavaFileStorageBase { | |||||||
|  |  | ||||||
| 	@Override | 	@Override | ||||||
| 	public void onStart(final JavaFileStorage.FileStorageSetupActivity setupAct) { | 	public void onStart(final JavaFileStorage.FileStorageSetupActivity setupAct) { | ||||||
|  | 		logDebug("onStart "+mRequiresRuntimePermissions); | ||||||
| 		logDebug("onStart"); | 		if (!mRequiresRuntimePermissions) | ||||||
| 		Activity activity = (Activity)setupAct; |  | ||||||
|  |  | ||||||
| 		if (PROCESS_NAME_SELECTFILE.equals(setupAct.getProcessName())) |  | ||||||
| 		{ | 		{ | ||||||
| 			GoogleAccountCredential credential = createCredential(activity.getApplicationContext()); | 			initFileStorage(setupAct); | ||||||
|  |  | ||||||
| 			logDebug("starting REQUEST_ACCOUNT_PICKER"); |  | ||||||
| 			activity.startActivityForResult(credential.newChooseAccountIntent(), REQUEST_ACCOUNT_PICKER); |  | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		if (PROCESS_NAME_FILE_USAGE_SETUP.equals(setupAct.getProcessName())) |  | ||||||
| 		{ |  | ||||||
| 			initializeAccountOrPath(setupAct, setupAct.getPath());	 |  | ||||||
| 		} |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	private GoogleAccountCredential createCredential(Context appContext) { | 	private GoogleAccountCredential createCredential(Context appContext) { | ||||||
| @@ -816,6 +842,21 @@ public class GoogleDriveFileStorage extends JavaFileStorageBase { | |||||||
| 	public void onCreate(FileStorageSetupActivity activity, | 	public void onCreate(FileStorageSetupActivity activity, | ||||||
| 			Bundle savedInstanceState) { | 			Bundle savedInstanceState) { | ||||||
|  |  | ||||||
|  | 		logDebug("onCreate"); | ||||||
|  | 		mRequiresRuntimePermissions = false; | ||||||
|  | 		if (Build.VERSION.SDK_INT >= 23) | ||||||
|  | 		{ | ||||||
|  | 			Activity act = (Activity)activity; | ||||||
|  | 			int permissionRes = act.checkSelfPermission(Manifest.permission.GET_ACCOUNTS); | ||||||
|  | 			logDebug("permissionRes="+permissionRes); | ||||||
|  | 			if (permissionRes == PackageManager.PERMISSION_DENIED) | ||||||
|  | 			{ | ||||||
|  | 				logDebug("requestPermissions"); | ||||||
|  | 				mRequiresRuntimePermissions = true; | ||||||
|  | 				act.requestPermissions(new String[] {Manifest.permission.GET_ACCOUNTS}, 0); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
| @@ -18,7 +18,7 @@ public interface JavaFileStorage { | |||||||
| 	public static final String EXTRA_PATH = "fileName"; //match KP2A PasswordActivity Ioc-Path Extra key | 	public static final String EXTRA_PATH = "fileName"; //match KP2A PasswordActivity Ioc-Path Extra key | ||||||
| 	public static final String EXTRA_IS_FOR_SAVE = "IS_FOR_SAVE"; | 	public static final String EXTRA_IS_FOR_SAVE = "IS_FOR_SAVE"; | ||||||
| 	public static final String EXTRA_ERROR_MESSAGE = "EXTRA_ERROR_MESSAGE"; | 	public static final String EXTRA_ERROR_MESSAGE = "EXTRA_ERROR_MESSAGE"; | ||||||
| 	public static final String EXTRA_ALWAYS_RETURN_SUCCESS = "EXTRA_ALWAYS_RETURN_SUCCESS";; | 	public static final String EXTRA_ALWAYS_RETURN_SUCCESS = "EXTRA_ALWAYS_RETURN_SUCCESS"; | ||||||
|  |  | ||||||
| 	 | 	 | ||||||
| public interface FileStorageSetupInitiatorActivity | public interface FileStorageSetupInitiatorActivity | ||||||
| @@ -155,5 +155,6 @@ public class FileEntry { | |||||||
| 	public void onResume(FileStorageSetupActivity activity); | 	public void onResume(FileStorageSetupActivity activity); | ||||||
| 	public void onStart(FileStorageSetupActivity activity); | 	public void onStart(FileStorageSetupActivity activity); | ||||||
| 	public void onActivityResult(FileStorageSetupActivity activity, int requestCode, int resultCode, Intent data); | 	public void onActivityResult(FileStorageSetupActivity activity, int requestCode, int resultCode, Intent data); | ||||||
|  | 	public void onRequestPermissionsResult(FileStorageSetupActivity activity, int requestCode, String[] permissions, int[] grantResults); | ||||||
| 	 | 	 | ||||||
| } | } | ||||||
| @@ -147,5 +147,10 @@ public abstract class JavaFileStorageBase implements JavaFileStorage{ | |||||||
|  |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	public void onRequestPermissionsResult(FileStorageSetupActivity activity, int requestCode, String[] permissions, int[] grantResults) | ||||||
|  | 	{ | ||||||
|  |  | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -287,13 +287,20 @@ namespace keepass2android | |||||||
|  |  | ||||||
| 		private void SetDefaultIoc() | 		private void SetDefaultIoc() | ||||||
| 		{ | 		{ | ||||||
| 			var sdDir = SdDir; | 			File directory = GetExternalFilesDir(null); | ||||||
| 			string filename = sdDir + "keepass.kdbx"; | 			if (directory == null) | ||||||
|  | 				directory = FilesDir; | ||||||
|  |  | ||||||
|  | 			string strDir = directory.CanonicalPath; | ||||||
|  | 			if (!strDir.EndsWith(File.Separator)) | ||||||
|  | 				strDir += File.Separator; | ||||||
|  |  | ||||||
|  | 			string filename = strDir + "keepass.kdbx"; | ||||||
| 			filename = ConvertFilenameToIocPath(filename); | 			filename = ConvertFilenameToIocPath(filename); | ||||||
| 			int count = 2; | 			int count = 2; | ||||||
| 			while (new File(filename).Exists()) | 			while (new File(filename).Exists()) | ||||||
| 			{ | 			{ | ||||||
| 				filename = ConvertFilenameToIocPath(sdDir + "keepass" + count + ".kdbx"); | 				filename = ConvertFilenameToIocPath(strDir + "keepass" + count + ".kdbx"); | ||||||
| 				count++; | 				count++; | ||||||
| 			} | 			} | ||||||
| 			 | 			 | ||||||
|   | |||||||
| @@ -71,7 +71,8 @@ namespace keepass2android | |||||||
| 		LaunchMode = LaunchMode.SingleInstance, | 		LaunchMode = LaunchMode.SingleInstance, | ||||||
| 		WindowSoftInputMode = SoftInput.AdjustResize, | 		WindowSoftInputMode = SoftInput.AdjustResize, | ||||||
| 		Theme = "@style/MyTheme_Blue")] /*caution: also contained in AndroidManifest.xml*/ | 		Theme = "@style/MyTheme_Blue")] /*caution: also contained in AndroidManifest.xml*/ | ||||||
|     public class PasswordActivity : LockingActivity, IFingerprintAuthCallback | 	[IntentFilter(new[] { "kp2a.action.PasswordActivity" }, Categories = new[] { Intent.CategoryDefault })] | ||||||
|  | 	public class PasswordActivity : LockingActivity, IFingerprintAuthCallback | ||||||
| 	{ | 	{ | ||||||
|  |  | ||||||
| 		enum KeyProviders | 		enum KeyProviders | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| <?xml version="1.0" encoding="utf-8"?> | <?xml version="1.0" encoding="utf-8"?> | ||||||
| <manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="46" android:versionName="0.9.3-release-3" package="keepass2android.keepass2android_debug" android:installLocation="auto"> | <manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="46" android:versionName="0.9.3-release-3" package="keepass2android.keepass2android_debug" android:installLocation="auto"> | ||||||
| 	<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="21" /> | 	<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="23" /> | ||||||
| 	<permission android:description="@string/permission_desc" android:icon="@drawable/ic_launcher" android:label="KP2A internal file browsing" android:name="keepass2android.keepass2android_debug.permission.KP2aInternalFileBrowsing" android:protectionLevel="signature" /> | 	<permission android:description="@string/permission_desc" android:icon="@drawable/ic_launcher" android:label="KP2A internal file browsing" android:name="keepass2android.keepass2android_debug.permission.KP2aInternalFileBrowsing" android:protectionLevel="signature" /> | ||||||
| 	<application android:label="keepass2android" android:icon="@drawable/ic_launcher"> | 	<application android:label="keepass2android" android:icon="@drawable/ic_launcher"> | ||||||
| 		 | 		 | ||||||
|   | |||||||
| @@ -4,7 +4,7 @@ | |||||||
| 			android:versionName="1.0.0 preview 2"  | 			android:versionName="1.0.0 preview 2"  | ||||||
| 			package="keepass2android.keepass2android"  | 			package="keepass2android.keepass2android"  | ||||||
| 			android:installLocation="auto"> | 			android:installLocation="auto"> | ||||||
| 	<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="21" /> | 	<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="23" /> | ||||||
| 	<permission android:description="@string/permission_desc" android:icon="@drawable/ic_launcher_online" android:label="KP2A internal file browsing" android:name="keepass2android.keepass2android.permission.KP2aInternalFileBrowsing" android:protectionLevel="signature" /> | 	<permission android:description="@string/permission_desc" android:icon="@drawable/ic_launcher_online" android:label="KP2A internal file browsing" android:name="keepass2android.keepass2android.permission.KP2aInternalFileBrowsing" android:protectionLevel="signature" /> | ||||||
| 	<application android:label="keepass2android" android:icon="@drawable/ic_launcher_online"> | 	<application android:label="keepass2android" android:icon="@drawable/ic_launcher_online"> | ||||||
| 		<activity android:name="com.dropbox.client2.android.AuthActivity" android:launchMode="singleTask" android:configChanges="orientation|keyboard"> | 		<activity android:name="com.dropbox.client2.android.AuthActivity" android:launchMode="singleTask" android:configChanges="orientation|keyboard"> | ||||||
|   | |||||||
| @@ -4,7 +4,7 @@ | |||||||
| 			android:versionName="0.9.8b"  | 			android:versionName="0.9.8b"  | ||||||
| 			package="keepass2android.keepass2android_nonet" | 			package="keepass2android.keepass2android_nonet" | ||||||
| 			android:installLocation="auto"> | 			android:installLocation="auto"> | ||||||
| 	<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="21" /> | 	<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="23" /> | ||||||
| 	<application android:label="keepass2android" android:icon="@drawable/ic_launcher_offline"> | 	<application android:label="keepass2android" android:icon="@drawable/ic_launcher_offline"> | ||||||
| 		<provider android:name="group.pals.android.lib.ui.filechooser.providers.localfile.LocalFileProvider" android:authorities="keepass2android.keepass2android_nonet.android-filechooser.localfile" android:exported="false" /> | 		<provider android:name="group.pals.android.lib.ui.filechooser.providers.localfile.LocalFileProvider" android:authorities="keepass2android.keepass2android_nonet.android-filechooser.localfile" android:exported="false" /> | ||||||
| 		<provider android:name="group.pals.android.lib.ui.filechooser.providers.history.HistoryProvider" android:authorities="keepass2android.keepass2android_nonet.android-filechooser.history" android:exported="false" /> | 		<provider android:name="group.pals.android.lib.ui.filechooser.providers.history.HistoryProvider" android:authorities="keepass2android.keepass2android_nonet.android-filechooser.history" android:exported="false" /> | ||||||
|   | |||||||
| @@ -1,4 +0,0 @@ | |||||||
| <?xml version="1.0" encoding="utf-8"?> |  | ||||||
| <!--Generated by crowdin.com--> |  | ||||||
| <!--Generated by crowdin.net--> |  | ||||||
| <resources/> |  | ||||||
| @@ -594,11 +594,13 @@ | |||||||
|   </string> |   </string> | ||||||
|  |  | ||||||
|   <string name="ChangeLog_1_0_0"> |   <string name="ChangeLog_1_0_0"> | ||||||
|     Version 1.0.0 - preview 1\n |     Version 1.0.0 - preview 2\n | ||||||
|  |     * Fingerprint Unlock (requires Android 6.0 or later)\n | ||||||
|     * Added "work offline" mode\n |     * Added "work offline" mode\n | ||||||
|     * Allow to copy entries\n |     * Allow to copy entries\n | ||||||
|     * Auto-complete mode for field names\n |     * Auto-complete mode for field names\n | ||||||
|     * Allow to remove items from recent files list\n |     * Allow to remove items from recent files list\n | ||||||
|  |     * Request permissions at runtime in Android 6.0\n | ||||||
|     * more to come...\n |     * more to come...\n | ||||||
|   </string> |   </string> | ||||||
| 	 | 	 | ||||||
|   | |||||||
| @@ -87,7 +87,18 @@ namespace keepass2android.fileselect | |||||||
| 			App.Kp2a.GetFileStorage(Ioc).OnActivityResult(this, requestCode, (int) resultCode, data); | 			App.Kp2a.GetFileStorage(Ioc).OnActivityResult(this, requestCode, (int) resultCode, data); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		protected override void OnSaveInstanceState(Bundle outState) | 	    public override void OnRequestPermissionsResult(int requestCode, string[] permissions, Permission[] grantResults) | ||||||
|  | 	    { | ||||||
|  | 		    base.OnRequestPermissionsResult(requestCode, permissions, grantResults); | ||||||
|  | 		    var fileStorage = App.Kp2a.GetFileStorage(Ioc); | ||||||
|  | 		    if (fileStorage is IPermissionRequestingFileStorage) | ||||||
|  | 		    { | ||||||
|  | 				((IPermissionRequestingFileStorage)fileStorage).OnRequestPermissionsResult(this, requestCode, permissions, grantResults);     | ||||||
|  | 		    } | ||||||
|  | 		     | ||||||
|  | 	    } | ||||||
|  |  | ||||||
|  | 	    protected override void OnSaveInstanceState(Bundle outState) | ||||||
| 		{ | 		{ | ||||||
| 			base.OnSaveInstanceState(outState); | 			base.OnSaveInstanceState(outState); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -86,17 +86,17 @@ | |||||||
|     <Reference Include="System.Xml" /> |     <Reference Include="System.Xml" /> | ||||||
|     <Reference Include="System.Core" /> |     <Reference Include="System.Core" /> | ||||||
|     <Reference Include="Mono.Android" /> |     <Reference Include="Mono.Android" /> | ||||||
|  |     <Reference Include="Xamarin.Android.Support.v7.MediaRouter"> | ||||||
|  |       <HintPath>..\packages\Xamarin.Android.Support.v7.MediaRouter.21.0.3.0\lib\MonoAndroid403\Xamarin.Android.Support.v7.MediaRouter.dll</HintPath> | ||||||
|  |     </Reference> | ||||||
|     <Reference Include="Xamarin.Android.Support.v4"> |     <Reference Include="Xamarin.Android.Support.v4"> | ||||||
|       <HintPath>..\packages\Xamarin.Android.Support.v4.23.1.1.0\lib\MonoAndroid403\Xamarin.Android.Support.v4.dll</HintPath> |       <HintPath>..\packages\Xamarin.Android.Support.v4.22.2.1.0\lib\MonoAndroid403\Xamarin.Android.Support.v4.dll</HintPath> | ||||||
|     </Reference> |     </Reference> | ||||||
|     <Reference Include="Xamarin.Android.Support.v7.AppCompat"> |     <Reference Include="Xamarin.Android.Support.v7.AppCompat"> | ||||||
|       <HintPath>..\packages\Xamarin.Android.Support.v7.AppCompat.23.1.1.0\lib\MonoAndroid403\Xamarin.Android.Support.v7.AppCompat.dll</HintPath> |       <HintPath>..\packages\Xamarin.Android.Support.v7.AppCompat.22.2.1.0\lib\MonoAndroid403\Xamarin.Android.Support.v7.AppCompat.dll</HintPath> | ||||||
|     </Reference> |  | ||||||
|     <Reference Include="Xamarin.Android.Support.v7.RecyclerView"> |  | ||||||
|       <HintPath>..\packages\Xamarin.Android.Support.v7.RecyclerView.23.1.1.0\lib\MonoAndroid403\Xamarin.Android.Support.v7.RecyclerView.dll</HintPath> |  | ||||||
|     </Reference> |     </Reference> | ||||||
|     <Reference Include="Xamarin.Android.Support.Design"> |     <Reference Include="Xamarin.Android.Support.Design"> | ||||||
|       <HintPath>..\packages\Xamarin.Android.Support.Design.23.1.1.0\lib\MonoAndroid403\Xamarin.Android.Support.Design.dll</HintPath> |       <HintPath>..\packages\Xamarin.Android.Support.Design.22.2.1.0\lib\MonoAndroid403\Xamarin.Android.Support.Design.dll</HintPath> | ||||||
|     </Reference> |     </Reference> | ||||||
|     <Reference Include="Xamarin.GooglePlayServices.Base"> |     <Reference Include="Xamarin.GooglePlayServices.Base"> | ||||||
|       <HintPath>..\packages\Xamarin.GooglePlayServices.Base.27.0.0.0\lib\MonoAndroid41\Xamarin.GooglePlayServices.Base.dll</HintPath> |       <HintPath>..\packages\Xamarin.GooglePlayServices.Base.27.0.0.0\lib\MonoAndroid41\Xamarin.GooglePlayServices.Base.dll</HintPath> | ||||||
| @@ -671,7 +671,6 @@ | |||||||
|     <AndroidResource Include="Resources\values-el\strings.xml" /> |     <AndroidResource Include="Resources\values-el\strings.xml" /> | ||||||
|     <AndroidResource Include="Resources\values-fi\strings.xml" /> |     <AndroidResource Include="Resources\values-fi\strings.xml" /> | ||||||
|     <AndroidResource Include="Resources\values-in\strings.xml" /> |     <AndroidResource Include="Resources\values-in\strings.xml" /> | ||||||
|     <AndroidResource Include="Resources\values-iw\strings.xml" /> |  | ||||||
|     <AndroidResource Include="Resources\values-ko\strings.xml" /> |     <AndroidResource Include="Resources\values-ko\strings.xml" /> | ||||||
|     <AndroidResource Include="Resources\values-no\strings.xml" /> |     <AndroidResource Include="Resources\values-no\strings.xml" /> | ||||||
|     <AndroidResource Include="Resources\values-pt-rPT\strings.xml" /> |     <AndroidResource Include="Resources\values-pt-rPT\strings.xml" /> | ||||||
| @@ -729,7 +728,6 @@ | |||||||
|     <Folder Include="Resources\drawable-hdpi\" /> |     <Folder Include="Resources\drawable-hdpi\" /> | ||||||
|     <Folder Include="Resources\drawable-ldpi\" /> |     <Folder Include="Resources\drawable-ldpi\" /> | ||||||
|     <Folder Include="Resources\drawable-xxhdpi\" /> |     <Folder Include="Resources\drawable-xxhdpi\" /> | ||||||
|     <Folder Include="Resources\values-iw\" /> |  | ||||||
|     <Folder Include="SupportLib\" /> |     <Folder Include="SupportLib\" /> | ||||||
|   </ItemGroup> |   </ItemGroup> | ||||||
|   <ItemGroup> |   <ItemGroup> | ||||||
| @@ -847,6 +845,12 @@ | |||||||
|       <SubType>Designer</SubType> |       <SubType>Designer</SubType> | ||||||
|     </AndroidResource> |     </AndroidResource> | ||||||
|   </ItemGroup> |   </ItemGroup> | ||||||
|  |   <ItemGroup> | ||||||
|  |     <XamarinComponentReference Include="xamandroidsupportdesign"> | ||||||
|  |       <Version>22.2.0.0</Version> | ||||||
|  |       <Visible>False</Visible> | ||||||
|  |     </XamarinComponentReference> | ||||||
|  |   </ItemGroup> | ||||||
|   <ItemGroup> |   <ItemGroup> | ||||||
|     <AndroidAsset Include="Assets\LICENSE_SourceCodePro.txt" /> |     <AndroidAsset Include="Assets\LICENSE_SourceCodePro.txt" /> | ||||||
|   </ItemGroup> |   </ItemGroup> | ||||||
| @@ -1643,12 +1647,6 @@ | |||||||
|   <ItemGroup> |   <ItemGroup> | ||||||
|     <AndroidResource Include="Resources\layout\image_list_preference_row.xml" /> |     <AndroidResource Include="Resources\layout\image_list_preference_row.xml" /> | ||||||
|   </ItemGroup> |   </ItemGroup> | ||||||
|   <ItemGroup> |  | ||||||
|     <XamarinComponentReference Include="xamandroidsupportdesign"> |  | ||||||
|       <Visible>False</Visible> |  | ||||||
|       <Version>23.0.1.3</Version> |  | ||||||
|     </XamarinComponentReference> |  | ||||||
|   </ItemGroup> |  | ||||||
|   <ItemGroup> |   <ItemGroup> | ||||||
|     <AndroidResource Include="Resources\drawable\ic_fingerprint_error.xml" /> |     <AndroidResource Include="Resources\drawable\ic_fingerprint_error.xml" /> | ||||||
|   </ItemGroup> |   </ItemGroup> | ||||||
|   | |||||||
| @@ -1,9 +1,9 @@ | |||||||
| <?xml version="1.0" encoding="utf-8"?> | <?xml version="1.0" encoding="utf-8"?> | ||||||
| <packages> | <packages> | ||||||
|   <package id="Xamarin.Android.Support.Design" version="23.1.1.0" targetFramework="MonoAndroid50" /> |   <package id="Xamarin.Android.Support.Design" version="22.2.1.0" targetFramework="MonoAndroid50" /> | ||||||
|   <package id="Xamarin.Android.Support.v4" version="23.1.1.0" targetFramework="MonoAndroid50" /> |   <package id="Xamarin.Android.Support.v4" version="22.2.1.0" targetFramework="MonoAndroid50" /> | ||||||
|   <package id="Xamarin.Android.Support.v7.AppCompat" version="23.1.1.0" targetFramework="MonoAndroid50" /> |   <package id="Xamarin.Android.Support.v7.AppCompat" version="22.2.1.0" targetFramework="MonoAndroid50" /> | ||||||
|   <package id="Xamarin.Android.Support.v7.RecyclerView" version="23.1.1.0" targetFramework="MonoAndroid50" /> |   <package id="Xamarin.Android.Support.v7.MediaRouter" version="21.0.3.0" targetFramework="MonoAndroid50" /> | ||||||
|   <package id="Xamarin.GooglePlayServices.Base" version="27.0.0.0" targetFramework="MonoAndroid50" /> |   <package id="Xamarin.GooglePlayServices.Base" version="27.0.0.0" targetFramework="MonoAndroid50" /> | ||||||
|   <package id="Xamarin.GooglePlayServices.Basement" version="27.0.0.0" targetFramework="MonoAndroid50" /> |   <package id="Xamarin.GooglePlayServices.Basement" version="27.0.0.0" targetFramework="MonoAndroid50" /> | ||||||
|   <package id="Xamarin.GooglePlayServices.Drive" version="27.0.0.0" targetFramework="MonoAndroid50" /> |   <package id="Xamarin.GooglePlayServices.Drive" version="27.0.0.0" targetFramework="MonoAndroid50" /> | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Philipp Crocoll
					Philipp Crocoll