Compare commits
4 Commits
feature/de
...
fdroid
Author | SHA1 | Date | |
---|---|---|---|
![]() |
c94019abb2 | ||
![]() |
e0754d2b90 | ||
![]() |
c724b93eb4 | ||
![]() |
d6f1b593da |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -107,58 +107,10 @@
|
||||
<ItemGroup>
|
||||
<EmbeddedReferenceJar Include="Jars\adal-1.1.19\classes-adal.jar" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedReferenceJar Include="Jars\gdrive\commons-logging-1.1.1.jar" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedReferenceJar Include="Jars\gdrive\google-api-client-1.16.0-rc.jar" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedReferenceJar Include="Jars\gdrive\google-api-client-android-1.16.0-rc.jar" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedReferenceJar Include="Jars\gdrive\google-api-services-drive-v2-rev102-1.16.0-rc.jar" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedReferenceJar Include="Jars\gdrive\google-http-client-1.16.0-rc.jar" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedReferenceJar Include="Jars\gdrive\google-http-client-android-1.16.0-rc.jar" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedReferenceJar Include="Jars\gdrive\google-http-client-jackson-1.16.0-rc.jar" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedReferenceJar Include="Jars\gdrive\google-http-client-jackson2-1.16.0-rc.jar" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedReferenceJar Include="Jars\gdrive\google-oauth-client-1.16.0-rc.jar" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedReferenceJar Include="Jars\gdrive\httpclient-4.0.3.jar" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedReferenceJar Include="Jars\gdrive\httpcore-4.0.1.jar" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedReferenceJar Include="Jars\gdrive\httpmime-4.0.3.jar" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedReferenceJar Include="Jars\gdrive\json_simple-1.1.jar" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedReferenceJar Include="Jars\gdrive\jsr305-1.3.9.jar" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedReferenceJar Include="Jars\gdrive\google-http-client-gson-1.16.0-rc.jar" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedReferenceJar Include="Jars\jackson-core-2.7.4.jar" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedReferenceJar Include="Jars\okio-1.9.0.jar" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedJar Include="Jars\dropbox-core-sdk-3.0.3.jar" />
|
||||
</ItemGroup>
|
||||
</Project>
|
@@ -1,27 +0,0 @@
|
||||
using Android.Content;
|
||||
#if !EXCLUDE_JAVAFILESTORAGE
|
||||
|
||||
namespace keepass2android.Io
|
||||
{
|
||||
public partial class DropboxFileStorage: JavaFileStorage
|
||||
{
|
||||
public DropboxFileStorage(Context ctx, IKp2aApp app) :
|
||||
base(new Keepass2android.Javafilestorage.DropboxV2Storage(ctx, AppKey, AppSecret), app)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public partial class DropboxAppFolderFileStorage: JavaFileStorage
|
||||
{
|
||||
public DropboxAppFolderFileStorage(Context ctx, IKp2aApp app) :
|
||||
base(new Keepass2android.Javafilestorage.DropboxV2AppFolderStorage(ctx, AppKey, AppSecret), app)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
@@ -1,27 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
using Android.App;
|
||||
using Android.Content;
|
||||
using Android.OS;
|
||||
using Android.Runtime;
|
||||
using Android.Views;
|
||||
using Android.Widget;
|
||||
using KeePassLib.Serialization;
|
||||
#if !EXCLUDE_JAVAFILESTORAGE
|
||||
namespace keepass2android.Io
|
||||
{
|
||||
public class GoogleDriveFileStorage : JavaFileStorage
|
||||
{
|
||||
public GoogleDriveFileStorage(Context ctx, IKp2aApp app) :
|
||||
base(new Keepass2android.Javafilestorage.GoogleDriveFileStorage(), app)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
@@ -75,12 +75,9 @@
|
||||
<Compile Include="Io\AndroidContentStorage.cs" />
|
||||
<Compile Include="Io\BuiltInFileStorage.cs" />
|
||||
<Compile Include="Io\CachingFileStorage.cs" />
|
||||
<Compile Include="Io\DropboxFileStorage.cs" />
|
||||
<Compile Include="Io\DropboxFileStorageKeys.cs" />
|
||||
<Compile Include="Io\FileDescription.cs" />
|
||||
<Compile Include="Io\FileStorageSetupActivity.cs" />
|
||||
<Compile Include="Io\FileStorageSetupInitiatorActivity.cs" />
|
||||
<Compile Include="Io\GDriveFileStorage.cs" />
|
||||
<Compile Include="Io\IFileStorage.cs" />
|
||||
<Compile Include="Io\IoUtil.cs" />
|
||||
<Compile Include="Io\JavaFileStorage.cs" />
|
||||
|
@@ -33,18 +33,9 @@ dependencies {
|
||||
compile 'com.squareup.okhttp3:okhttp:3.4.1'
|
||||
compile 'com.burgstaller:okhttp-digest:1.7'
|
||||
// compile files('libs/dropbox-android-sdk-1.6.2.jar')
|
||||
compile 'com.google.android.gms:play-services:4.0.30'
|
||||
/* compile('com.google.api-client:google-api-client-xml:1.16.0-rc') {
|
||||
exclude group: 'com.google.android.google-play-services'
|
||||
}*/
|
||||
compile 'com.google.http-client:google-http-client-gson:1.16.0-rc'
|
||||
compile('com.google.api-client:google-api-client-android:1.16.0-rc') {
|
||||
exclude group: 'com.google.android.google-play-services'
|
||||
}
|
||||
compile 'com.google.apis:google-api-services-drive:v2-rev102-1.16.0-rc'
|
||||
//compile 'com.dropbox.core:dropbox-core-sdk:2.0.1'
|
||||
//compile group: 'com.dropbox.core', name: 'dropbox-core-sdk', version: '0-SNAPSHOT', changing: true
|
||||
compile 'com.dropbox.core:dropbox-core-sdk:3.0.3'
|
||||
//onedrive:
|
||||
compile('com.onedrive.sdk:onedrive-sdk-android:1.2+') {
|
||||
transitive = false
|
||||
|
@@ -1,30 +0,0 @@
|
||||
package keepass2android.javafilestorage;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
/**
|
||||
* Created by Philipp on 22.11.2016.
|
||||
*/
|
||||
public class DropboxV2AppFolderStorage extends DropboxV2Storage{
|
||||
|
||||
public DropboxV2AppFolderStorage(Context ctx, String _appKey,
|
||||
String _appSecret) {
|
||||
super(ctx, _appKey, _appSecret, false, AccessType.AppFolder);
|
||||
|
||||
|
||||
}
|
||||
|
||||
public DropboxV2AppFolderStorage(Context ctx, String _appKey, String _appSecret, boolean clearKeysOnStart)
|
||||
{
|
||||
super(ctx, _appKey, _appSecret, clearKeysOnStart, AccessType.AppFolder);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getProtocolId() {
|
||||
return "dropboxKP2A";
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1,612 +0,0 @@
|
||||
package keepass2android.javafilestorage;
|
||||
|
||||
import com.dropbox.core.DbxAppInfo;
|
||||
import com.dropbox.core.DbxException;
|
||||
import com.dropbox.core.DbxOAuth1AccessToken;
|
||||
import com.dropbox.core.DbxOAuth1Upgrader;
|
||||
import com.dropbox.core.DbxRequestConfig;
|
||||
import com.dropbox.core.InvalidAccessTokenException;
|
||||
import com.dropbox.core.android.Auth;
|
||||
import com.dropbox.core.v2.DbxClientV2;
|
||||
import com.dropbox.core.http.OkHttp3Requestor;
|
||||
import com.dropbox.core.v2.files.DeleteErrorException;
|
||||
import com.dropbox.core.v2.files.DeletedMetadata;
|
||||
import com.dropbox.core.v2.files.DownloadErrorException;
|
||||
import com.dropbox.core.v2.files.FileMetadata;
|
||||
import com.dropbox.core.v2.files.FolderMetadata;
|
||||
import com.dropbox.core.v2.files.GetMetadataErrorException;
|
||||
import com.dropbox.core.v2.files.ListFolderErrorException;
|
||||
import com.dropbox.core.v2.files.ListFolderResult;
|
||||
import com.dropbox.core.v2.files.Metadata;
|
||||
import com.dropbox.core.v2.files.WriteMode;
|
||||
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.SharedPreferences.Editor;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
|
||||
|
||||
/**
|
||||
* Created by Philipp on 18.11.2016.
|
||||
*/
|
||||
public class DropboxV2Storage extends JavaFileStorageBase
|
||||
{
|
||||
private DbxAppInfo appInfo;
|
||||
|
||||
public void bla()
|
||||
{
|
||||
|
||||
}
|
||||
DbxRequestConfig requestConfig = DbxRequestConfig.newBuilder("kp2a")
|
||||
.withHttpRequestor(new OkHttp3Requestor(OkHttp3Requestor.defaultOkHttpClient()))
|
||||
.build();
|
||||
|
||||
final static private String TAG = "KP2AJ";
|
||||
|
||||
final static private String ACCOUNT_PREFS_NAME = "prefs";
|
||||
final static private String ACCESS_KEY_V1_NAME = "ACCESS_KEY";
|
||||
final static private String ACCESS_SECRET_V1_NAME = "ACCESS_SECRET";
|
||||
final static private String ACCESS_TOKEN_NAME = "ACCESS_TOKEN_V2";
|
||||
|
||||
private boolean mLoggedIn = false;
|
||||
private Context mContext;
|
||||
|
||||
public FileEntry getRootFileEntry() {
|
||||
|
||||
FileEntry rootEntry = new FileEntry();
|
||||
|
||||
rootEntry.displayName = "";
|
||||
rootEntry.isDirectory = true;
|
||||
rootEntry.lastModifiedTime = -1;
|
||||
rootEntry.canRead = rootEntry.canWrite = true;
|
||||
rootEntry.path = getProtocolId()+":///";
|
||||
rootEntry.sizeInBytes = -1;
|
||||
|
||||
return rootEntry;
|
||||
}
|
||||
|
||||
public enum AccessType { Full, AppFolder};
|
||||
|
||||
protected AccessType mAccessType = AccessType.Full;
|
||||
|
||||
DbxClientV2 dbxClient;
|
||||
|
||||
|
||||
public DropboxV2Storage(Context ctx, String _appKey, String _appSecret)
|
||||
{
|
||||
initialize(ctx, _appKey, _appSecret, false, mAccessType);
|
||||
}
|
||||
|
||||
public DropboxV2Storage(Context ctx, String _appKey, String _appSecret, boolean clearKeysOnStart)
|
||||
{
|
||||
initialize(ctx, _appKey, _appSecret, clearKeysOnStart, mAccessType);
|
||||
}
|
||||
|
||||
public DropboxV2Storage(Context ctx, String _appKey, String _appSecret, boolean clearKeysOnStart, AccessType accessType)
|
||||
{
|
||||
initialize(ctx, _appKey, _appSecret, clearKeysOnStart, accessType);
|
||||
}
|
||||
|
||||
private void initialize(Context ctx, String _appKey, String _appSecret,
|
||||
boolean clearKeysOnStart, AccessType accessType) {
|
||||
appInfo = new DbxAppInfo(_appKey,_appSecret);
|
||||
mContext = ctx;
|
||||
|
||||
if (clearKeysOnStart)
|
||||
clearKeys();
|
||||
|
||||
this.mAccessType = accessType;
|
||||
|
||||
buildSession();
|
||||
|
||||
}
|
||||
|
||||
public boolean tryConnect(Activity activity)
|
||||
{
|
||||
if (!mLoggedIn)
|
||||
Auth.startOAuth2Authentication(activity, appInfo.getKey());
|
||||
return mLoggedIn;
|
||||
}
|
||||
|
||||
private void setLoggedIn(boolean b) {
|
||||
mLoggedIn = b;
|
||||
|
||||
}
|
||||
|
||||
|
||||
public boolean isConnected()
|
||||
{
|
||||
return mLoggedIn;
|
||||
}
|
||||
|
||||
|
||||
public boolean checkForFileChangeFast(String path, String previousFileVersion) throws Exception
|
||||
{
|
||||
if ((previousFileVersion == null) || (previousFileVersion.equals("")))
|
||||
return false;
|
||||
path = removeProtocol(path);
|
||||
try {
|
||||
Metadata entry = dbxClient.files().getMetadata(path);
|
||||
return !String.valueOf(entry.hashCode()) .equals(previousFileVersion);
|
||||
|
||||
} catch (DbxException e) {
|
||||
throw convertException(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public String getCurrentFileVersionFast(String path)
|
||||
{
|
||||
try {
|
||||
path = removeProtocol(path);
|
||||
Metadata entry = dbxClient.files().getMetadata(path);
|
||||
return String.valueOf(entry.hashCode());
|
||||
} catch (DbxException e) {
|
||||
Log.d(TAG, e.toString());
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
public InputStream openFileForRead(String path) throws Exception
|
||||
{
|
||||
try {
|
||||
path = removeProtocol(path);
|
||||
return dbxClient.files().download(path).getInputStream();
|
||||
} catch (DbxException e) {
|
||||
//System.out.println("Something went wrong: " + e);
|
||||
throw convertException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void uploadFile(String path, byte[] data, boolean writeTransactional) throws Exception
|
||||
{
|
||||
ByteArrayInputStream bis = new ByteArrayInputStream(data);
|
||||
try {
|
||||
path = removeProtocol(path);
|
||||
|
||||
dbxClient.files().uploadBuilder(path).withMode(WriteMode.OVERWRITE).uploadAndFinish(bis);
|
||||
|
||||
} catch (DbxException e) {
|
||||
throw convertException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private Exception convertException(DbxException e) {
|
||||
|
||||
Log.d(TAG, "Exception of type " +e.getClass().getName()+":" + e.getMessage());
|
||||
|
||||
if (InvalidAccessTokenException.class.isAssignableFrom(e.getClass()) ) {
|
||||
Log.d(TAG, "LoggedIn=false (due to InvalidAccessTokenException)");
|
||||
setLoggedIn(false);
|
||||
clearKeys();
|
||||
return new UserInteractionRequiredException("Unlinked from Dropbox! User must re-link.", e);
|
||||
}
|
||||
|
||||
if (ListFolderErrorException.class.isAssignableFrom(e.getClass()) ) {
|
||||
ListFolderErrorException listFolderErrorException = (ListFolderErrorException)e;
|
||||
if (listFolderErrorException.errorValue.getPathValue().isNotFound())
|
||||
return new FileNotFoundException(e.toString());
|
||||
}
|
||||
if (DownloadErrorException.class.isAssignableFrom(e.getClass()) ) {
|
||||
DownloadErrorException downloadErrorException = (DownloadErrorException)e;
|
||||
if (downloadErrorException.errorValue.getPathValue().isNotFound())
|
||||
return new FileNotFoundException(e.toString());
|
||||
}
|
||||
if (GetMetadataErrorException.class.isAssignableFrom(e.getClass()) ) {
|
||||
GetMetadataErrorException getMetadataErrorException = (GetMetadataErrorException)e;
|
||||
if (getMetadataErrorException.errorValue.getPathValue().isNotFound())
|
||||
return new FileNotFoundException(e.toString());
|
||||
}
|
||||
if (DeleteErrorException.class.isAssignableFrom(e.getClass()) ) {
|
||||
DeleteErrorException deleteErrorException = (DeleteErrorException)e;
|
||||
if (deleteErrorException.errorValue.getPathLookupValue().isNotFound())
|
||||
return new FileNotFoundException(e.toString());
|
||||
}
|
||||
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
private void showToast(String msg) {
|
||||
Toast error = Toast.makeText(mContext, msg, Toast.LENGTH_LONG);
|
||||
error.show();
|
||||
}
|
||||
|
||||
/**
|
||||
* Keep the access keys returned from Trusted Authenticator in a local
|
||||
* store, rather than storing user name & password, and re-authenticating each
|
||||
* time (which is not to be done, ever).
|
||||
*
|
||||
* @return Array of [access_key, access_secret], or null if none stored
|
||||
*/
|
||||
private String[] getKeysV1() {
|
||||
SharedPreferences prefs = mContext.getSharedPreferences(ACCOUNT_PREFS_NAME, 0);
|
||||
String key = prefs.getString(ACCESS_KEY_V1_NAME, null);
|
||||
String secret = prefs.getString(ACCESS_SECRET_V1_NAME, null);
|
||||
if (key != null && secret != null) {
|
||||
String[] ret = new String[2];
|
||||
ret[0] = key;
|
||||
ret[1] = secret;
|
||||
return ret;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private String getKeyV2() {
|
||||
SharedPreferences prefs = mContext.getSharedPreferences(ACCOUNT_PREFS_NAME, 0);
|
||||
return prefs.getString(ACCESS_TOKEN_NAME, null);
|
||||
}
|
||||
|
||||
|
||||
private void storeKey(String v2token) {
|
||||
Log.d(TAG, "Storing Dropbox accessToken");
|
||||
// Save the access key for later
|
||||
SharedPreferences prefs = mContext.getSharedPreferences(ACCOUNT_PREFS_NAME, 0);
|
||||
Editor edit = prefs.edit();
|
||||
edit.putString(ACCESS_TOKEN_NAME, v2token);
|
||||
edit.commit();
|
||||
}
|
||||
|
||||
private void clearKeys() {
|
||||
SharedPreferences prefs = mContext.getSharedPreferences(ACCOUNT_PREFS_NAME, 0);
|
||||
Editor edit = prefs.edit();
|
||||
edit.clear();
|
||||
edit.commit();
|
||||
}
|
||||
|
||||
private void buildSession() {
|
||||
|
||||
String v2Token = getKeyV2();
|
||||
|
||||
if (v2Token != null)
|
||||
{
|
||||
dbxClient = new DbxClientV2(requestConfig, v2Token);
|
||||
|
||||
setLoggedIn(true);
|
||||
Log.d(TAG, "Creating Dropbox Session with accessToken");
|
||||
} else {
|
||||
setLoggedIn(false);
|
||||
Log.d(TAG, "Creating Dropbox Session without accessToken");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String createFolder(String parentPath, String newDirName) throws Exception {
|
||||
try
|
||||
{
|
||||
String path = parentPath;
|
||||
if (!path.endsWith("/"))
|
||||
path = path + "/";
|
||||
path = path + newDirName;
|
||||
|
||||
String pathWithoutProtocol = removeProtocol(path);
|
||||
dbxClient.files().createFolder(pathWithoutProtocol);
|
||||
|
||||
return path;
|
||||
}
|
||||
catch (DbxException e) {
|
||||
throw convertException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String createFilePath(String parentPath, String newFileName) throws Exception {
|
||||
String path = parentPath;
|
||||
if (!path.endsWith("/"))
|
||||
path = path + "/";
|
||||
path = path + newFileName;
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<FileEntry> listFiles(String parentPath) throws Exception {
|
||||
try
|
||||
{
|
||||
parentPath = removeProtocol(parentPath);
|
||||
if (parentPath.equals("/"))
|
||||
parentPath = ""; //Dropbox is a bit picky here
|
||||
ListFolderResult dirEntry = dbxClient.files().listFolder(parentPath);
|
||||
|
||||
List<FileEntry> result = new ArrayList<FileEntry>();
|
||||
|
||||
while (true)
|
||||
{
|
||||
for (Metadata e: dirEntry.getEntries())
|
||||
{
|
||||
FileEntry fileEntry = convertToFileEntry(e);
|
||||
result.add(fileEntry);
|
||||
}
|
||||
|
||||
if (!dirEntry.getHasMore()) {
|
||||
break;
|
||||
}
|
||||
|
||||
dirEntry = dbxClient.files().listFolderContinue(dirEntry.getCursor());
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
|
||||
|
||||
} catch (DbxException e) {
|
||||
|
||||
throw convertException(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private FileEntry convertToFileEntry(Metadata e) throws Exception {
|
||||
//Log.d("JFS","e="+e);
|
||||
|
||||
FileEntry fileEntry = new FileEntry();
|
||||
fileEntry.canRead = true;
|
||||
fileEntry.canWrite = true;
|
||||
if (e instanceof FolderMetadata)
|
||||
{
|
||||
FolderMetadata fm = (FolderMetadata)e;
|
||||
fileEntry.isDirectory = true;
|
||||
fileEntry.sizeInBytes = 0;
|
||||
fileEntry.lastModifiedTime = 0;
|
||||
}
|
||||
else if (e instanceof FileMetadata)
|
||||
{
|
||||
FileMetadata fm = (FileMetadata)e;
|
||||
fileEntry.sizeInBytes = fm.getSize();
|
||||
fileEntry.isDirectory = false;
|
||||
fileEntry.lastModifiedTime = fm.getServerModified().getTime();
|
||||
}
|
||||
else if (e instanceof DeletedMetadata)
|
||||
{
|
||||
throw new FileNotFoundException();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("unexpected metadata " + e.getClass().getName() );
|
||||
}
|
||||
|
||||
fileEntry.path = getProtocolId()+"://"+ e.getPathLower();
|
||||
fileEntry.displayName = e.getName();
|
||||
//Log.d("JFS","fileEntry="+fileEntry);
|
||||
//Log.d("JFS","Ok. Dir="+fileEntry.isDirectory);
|
||||
return fileEntry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(String path) throws Exception {
|
||||
try
|
||||
{
|
||||
path = removeProtocol(path);
|
||||
dbxClient.files().delete(path);
|
||||
} catch (DbxException e) {
|
||||
throw convertException(e);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileEntry getFileEntry(String filename) throws Exception {
|
||||
try
|
||||
{
|
||||
filename = removeProtocol(filename);
|
||||
Log.d("KP2AJ", "getFileEntry(), " +filename);
|
||||
|
||||
//querying root is not supported
|
||||
if ((filename.equals("")) || (filename.equals("/")))
|
||||
return getRootFileEntry();
|
||||
if (filename.endsWith("/"))
|
||||
filename = filename.substring(0,filename.length()-1);
|
||||
|
||||
Metadata dbEntry = dbxClient.files().getMetadata(filename);
|
||||
return convertToFileEntry(dbEntry);
|
||||
|
||||
} catch (DbxException e) {
|
||||
|
||||
throw convertException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startSelectFile(FileStorageSetupInitiatorActivity activity, boolean isForSave,
|
||||
int requestCode)
|
||||
{
|
||||
|
||||
String path = getProtocolId()+":///";
|
||||
Log.d("KP2AJ", "startSelectFile "+path+", connected: "+path);
|
||||
/*if (isConnected())
|
||||
{
|
||||
Intent intent = new Intent();
|
||||
intent.putExtra(EXTRA_IS_FOR_SAVE, isForSave);
|
||||
intent.putExtra(EXTRA_PATH, path);
|
||||
activity.onImmediateResult(requestCode, RESULT_FILECHOOSER_PREPARED, intent);
|
||||
}
|
||||
else*/
|
||||
{
|
||||
activity.startSelectFileProcess(path, isForSave, requestCode);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProtocolId() {
|
||||
return "dropbox";
|
||||
}
|
||||
|
||||
public boolean requiresSetup(String path)
|
||||
{
|
||||
return !isConnected();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void prepareFileUsage(FileStorageSetupInitiatorActivity activity, String path, int requestCode, boolean alwaysReturnSuccess) {
|
||||
if (isConnected())
|
||||
{
|
||||
Intent intent = new Intent();
|
||||
intent.putExtra(EXTRA_PATH, path);
|
||||
activity.onImmediateResult(requestCode, RESULT_FILEUSAGE_PREPARED, intent);
|
||||
}
|
||||
else
|
||||
{
|
||||
activity.startFileUsageProcess(path, requestCode, alwaysReturnSuccess);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void prepareFileUsage(Context appContext, String path) throws UserInteractionRequiredException {
|
||||
if (!isConnected())
|
||||
{
|
||||
throw new UserInteractionRequiredException();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(FileStorageSetupActivity activity, Bundle savedInstanceState) {
|
||||
|
||||
Log.d("KP2AJ", "OnCreate");
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume(final FileStorageSetupActivity activity) {
|
||||
|
||||
if (activity.getProcessName().equals(PROCESS_NAME_SELECTFILE))
|
||||
activity.getState().putString(EXTRA_PATH, activity.getPath());
|
||||
|
||||
Log.d("KP2AJ", "OnResume (3). LoggedIn="+mLoggedIn);
|
||||
/*if (mLoggedIn)
|
||||
{
|
||||
finishActivityWithSuccess(activity);
|
||||
return;
|
||||
}*/
|
||||
|
||||
|
||||
final String[] storedV1Keys = getKeysV1();
|
||||
if (storedV1Keys != null) {
|
||||
new AsyncTask<Object, Object, Object>()
|
||||
{
|
||||
@Override
|
||||
protected Object doInBackground(Object... objects) {
|
||||
DbxOAuth1AccessToken v1Token = new DbxOAuth1AccessToken(storedV1Keys[0], storedV1Keys[1]);
|
||||
DbxOAuth1Upgrader upgrader = new DbxOAuth1Upgrader(requestConfig, appInfo);
|
||||
try {
|
||||
String v2Token = upgrader.createOAuth2AccessToken(v1Token);
|
||||
upgrader.disableOAuth1AccessToken(v1Token);
|
||||
storeKey(v2Token);
|
||||
return v2Token;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
clearKeys();
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Object o) {
|
||||
if (o != null) {
|
||||
buildSession();
|
||||
finishActivityWithSuccess(activity);
|
||||
}
|
||||
else
|
||||
resumeGetAuthToken(activity);
|
||||
}
|
||||
}.execute();
|
||||
}
|
||||
|
||||
else {
|
||||
|
||||
resumeGetAuthToken(activity);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
private void resumeGetAuthToken(FileStorageSetupActivity activity) {
|
||||
FileStorageSetupActivity storageSetupAct = activity;
|
||||
|
||||
if (storageSetupAct.getState().containsKey("hasStartedAuth")) {
|
||||
Log.d("KP2AJ", "auth started");
|
||||
|
||||
String v2Token = Auth.getOAuth2Token();
|
||||
|
||||
|
||||
if (v2Token != null) {
|
||||
Log.d("KP2AJ", "auth successful");
|
||||
try {
|
||||
storeKey(v2Token);
|
||||
buildSession();
|
||||
finishActivityWithSuccess(activity);
|
||||
return;
|
||||
|
||||
} catch (Exception e) {
|
||||
Log.d("KP2AJ", "finish with error: " + e.toString());
|
||||
finishWithError(activity, e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Log.i(TAG, "authenticating not succesful");
|
||||
Intent data = new Intent();
|
||||
data.putExtra(EXTRA_ERROR_MESSAGE, "authenticating not succesful");
|
||||
((Activity) activity).setResult(Activity.RESULT_CANCELED, data);
|
||||
((Activity) activity).finish();
|
||||
} else {
|
||||
Log.d("KP2AJ", "Starting auth");
|
||||
Auth.startOAuth2Authentication((Activity) activity, appInfo.getKey());
|
||||
storageSetupAct.getState().putBoolean("hasStartedAuth", true);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart(FileStorageSetupActivity activity) {
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityResult(FileStorageSetupActivity activity, int requestCode, int resultCode, Intent data) {
|
||||
//nothing to do here
|
||||
|
||||
}
|
||||
|
||||
String removeProtocol(String path)
|
||||
{
|
||||
if (path == null)
|
||||
return null;
|
||||
return path.substring(getProtocolId().length()+3);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayName(String path) {
|
||||
return path;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFilename(String path) throws Exception {
|
||||
return path.substring(path.lastIndexOf("/")+1);
|
||||
}
|
||||
|
||||
}
|
@@ -1,885 +0,0 @@
|
||||
package keepass2android.javafilestorage;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.api.client.extensions.android.http.AndroidHttp;
|
||||
import com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential;
|
||||
import com.google.api.client.googleapis.extensions.android.gms.auth.UserRecoverableAuthIOException;
|
||||
import com.google.api.client.googleapis.json.GoogleJsonResponseException;
|
||||
import com.google.api.client.http.ByteArrayContent;
|
||||
import com.google.api.client.http.GenericUrl;
|
||||
import com.google.api.client.http.HttpResponse;
|
||||
import com.google.api.client.json.gson.GsonFactory;
|
||||
import com.google.api.services.drive.Drive;
|
||||
import com.google.api.services.drive.DriveScopes;
|
||||
import com.google.api.services.drive.Drive.Files;
|
||||
import com.google.api.services.drive.model.About;
|
||||
import com.google.api.services.drive.model.File;
|
||||
import com.google.api.services.drive.model.FileList;
|
||||
import com.google.api.services.drive.model.ParentReference;
|
||||
|
||||
import android.Manifest;
|
||||
import android.accounts.AccountManager;
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
|
||||
|
||||
public class GoogleDriveFileStorage extends JavaFileStorageBase {
|
||||
|
||||
private static final String GDRIVE_PROTOCOL_ID = "gdrive";
|
||||
private static final String FOLDER_MIME_TYPE = "application/vnd.google-apps.folder";
|
||||
static final int MAGIC_GDRIVE=2082334;
|
||||
static final int REQUEST_ACCOUNT_PICKER = MAGIC_GDRIVE+1;
|
||||
static final int REQUEST_AUTHORIZATION = MAGIC_GDRIVE+2;
|
||||
private boolean mRequiresRuntimePermissions = false;
|
||||
|
||||
|
||||
class FileSystemEntryData
|
||||
{
|
||||
String displayName;
|
||||
String id;
|
||||
HashSet<String> parentIds = new HashSet<String>();
|
||||
};
|
||||
|
||||
class AccountData
|
||||
{
|
||||
//guaranteed to be set if AccountData is in HashMap
|
||||
Drive drive;
|
||||
|
||||
//may be null if first initialization failed
|
||||
protected String mRootFolderId;
|
||||
};
|
||||
|
||||
HashMap<String /*accountName*/, AccountData> mAccountData = new HashMap<String, AccountData>();
|
||||
|
||||
|
||||
|
||||
public String getRootPathForAccount(String accountName) throws UnsupportedEncodingException {
|
||||
return GDRIVE_PROTOCOL_ID+"://"+encode(accountName)+"/";
|
||||
}
|
||||
|
||||
class GDrivePath
|
||||
{
|
||||
String mAccount;
|
||||
String mAccountLocalPath; // the path after the "gdrive://account%40%0Agmail.com/"
|
||||
|
||||
public GDrivePath()
|
||||
{
|
||||
}
|
||||
|
||||
public GDrivePath(String path) throws InvalidPathException, IOException
|
||||
{
|
||||
setPath(path);
|
||||
}
|
||||
|
||||
public void setPath(String path) throws
|
||||
InvalidPathException, IOException {
|
||||
setPathWithoutVerify(path);
|
||||
verify();
|
||||
}
|
||||
|
||||
public void setPathWithoutVerify(String path) throws UnsupportedEncodingException, InvalidPathException
|
||||
{
|
||||
logDebug("setPath: "+path);
|
||||
mAccount = extractAccount(path);
|
||||
mAccountLocalPath = path.substring(getProtocolPrefix().length()+encode(mAccount).length()+1);
|
||||
logDebug(" mAccount=" + mAccount);
|
||||
logDebug(" mAccountLocalPath=" + mAccountLocalPath);
|
||||
}
|
||||
|
||||
public GDrivePath(String parentPath, File fileToAppend) throws UnsupportedEncodingException, FileNotFoundException, IOException, InvalidPathException
|
||||
{
|
||||
setPath(parentPath);
|
||||
|
||||
if ((!mAccountLocalPath.endsWith("/")) && (!mAccountLocalPath.equals("")))
|
||||
mAccountLocalPath = mAccountLocalPath + "/";
|
||||
mAccountLocalPath += encode(fileToAppend.getTitle())+NAME_ID_SEP+fileToAppend.getId();
|
||||
}
|
||||
|
||||
//make sure the path exists
|
||||
/*Note: in earlier versions, this method checked the full path. This was causing trouble
|
||||
* for some users, it seems like the IDs of parent folders can behave unexpectedly.
|
||||
* Now the display name does no longer contain the parent folders, which is why it is no longer
|
||||
* necessary to check if they were renamed.
|
||||
* (The path still contains the parents for file browsing, but this is only required temporarily
|
||||
* during setup where everything seems fine.)*/
|
||||
private void verify() throws IOException {
|
||||
|
||||
if (mAccountLocalPath.equals(""))
|
||||
return;
|
||||
|
||||
String[] parts = mAccountLocalPath.split("/");
|
||||
|
||||
AccountData accountData = mAccountData.get(mAccount);
|
||||
if (accountData == null)
|
||||
{
|
||||
throw new IllegalStateException("Looks like account "+mAccount+" was not properly initialized!");
|
||||
}
|
||||
|
||||
//if initialization failed, try to repeat:
|
||||
finishInitialization(accountData, mAccount);
|
||||
|
||||
String part = parts[parts.length-1];
|
||||
logDebug("parsing part " + part);
|
||||
int indexOfSeparator = part.lastIndexOf(NAME_ID_SEP);
|
||||
if (indexOfSeparator < 0)
|
||||
throw new FileNotFoundException("invalid path " + mAccountLocalPath);
|
||||
String id = part.substring(indexOfSeparator+NAME_ID_SEP.length());
|
||||
String name = decode(part.substring(0, indexOfSeparator));
|
||||
logDebug(" name=" + name);
|
||||
|
||||
File fl;
|
||||
try {
|
||||
fl = getDriveService(getAccount()).files().get(getGDriveId()).execute();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
throw new FileNotFoundException("error getting file with for "+ this.getFullPath());
|
||||
}
|
||||
|
||||
String displayName = fl.getTitle();
|
||||
|
||||
if (displayName.equals(name) == false)
|
||||
throw new FileNotFoundException("Name of "+id+" changed from "+name+" to "+displayName +" in "+ mAccountLocalPath+" in GDrive account " + mAccount);
|
||||
|
||||
}
|
||||
|
||||
private String extractAccount(String path) throws InvalidPathException, UnsupportedEncodingException {
|
||||
if (!path.startsWith(getProtocolPrefix()))
|
||||
throw new InvalidPathException("Invalid path: "+path);
|
||||
String pathWithoutProtocol = path.substring(getProtocolPrefix().length());
|
||||
int slashPos = pathWithoutProtocol.indexOf("/");
|
||||
String accountNameEncoded;
|
||||
if (slashPos < 0)
|
||||
accountNameEncoded = pathWithoutProtocol;
|
||||
else
|
||||
accountNameEncoded = pathWithoutProtocol.substring(0, slashPos);
|
||||
return decode(accountNameEncoded);
|
||||
}
|
||||
|
||||
public String getDisplayName()
|
||||
{
|
||||
//gdrive://
|
||||
String displayName = getProtocolPrefix();
|
||||
|
||||
//gdrive://me@google.com/
|
||||
|
||||
displayName += mAccount;
|
||||
|
||||
if (mAccountLocalPath.equals(""))
|
||||
return displayName;
|
||||
|
||||
String[] parts = mAccountLocalPath.split("/");
|
||||
|
||||
String part = parts[parts.length-1];
|
||||
logDebug("parsing part " + part);
|
||||
int indexOfSeparator = part.lastIndexOf(NAME_ID_SEP);
|
||||
if (indexOfSeparator < 0)
|
||||
{
|
||||
//seems invalid, but we're very generous here
|
||||
displayName += "/"+part;
|
||||
}
|
||||
String name = part.substring(0, indexOfSeparator);
|
||||
try {
|
||||
name = decode(name);
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
//ignore
|
||||
}
|
||||
displayName += "/"+name;
|
||||
|
||||
return displayName;
|
||||
}
|
||||
|
||||
|
||||
public String getGDriveId() throws InvalidPathException, IOException {
|
||||
String pathWithoutTrailingSlash = mAccountLocalPath;
|
||||
if (pathWithoutTrailingSlash.endsWith("/"))
|
||||
pathWithoutTrailingSlash = pathWithoutTrailingSlash.substring(0,pathWithoutTrailingSlash.length()-1);
|
||||
if (pathWithoutTrailingSlash.equals(""))
|
||||
{
|
||||
AccountData accountData = mAccountData.get(mAccount);
|
||||
finishInitialization(accountData, mAccount);
|
||||
return accountData.mRootFolderId;
|
||||
}
|
||||
String lastPart = pathWithoutTrailingSlash.substring(pathWithoutTrailingSlash.lastIndexOf(NAME_ID_SEP)+NAME_ID_SEP.length());
|
||||
if (lastPart.contains("/"))
|
||||
throw new InvalidPathException("error extracting GDriveId from "+mAccountLocalPath);
|
||||
return decode(lastPart);
|
||||
}
|
||||
|
||||
public String getFullPath() throws UnsupportedEncodingException {
|
||||
return getProtocolPrefix()+encode(mAccount)+"/"+mAccountLocalPath;
|
||||
}
|
||||
|
||||
public String getAccount() {
|
||||
return mAccount;
|
||||
}
|
||||
|
||||
public String getFilename() throws InvalidPathException {
|
||||
|
||||
String[] parts = mAccountLocalPath.split("/");
|
||||
|
||||
String lastPart = parts[parts.length-1];
|
||||
int indexOfSeparator = lastPart.lastIndexOf(NAME_ID_SEP);
|
||||
if (indexOfSeparator < 0) {
|
||||
throw new InvalidPathException("cannot extract filename from " + mAccountLocalPath);
|
||||
}
|
||||
String name = lastPart.substring(0, indexOfSeparator);
|
||||
try {
|
||||
name = decode(name);
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
// ignore
|
||||
}
|
||||
return name;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
public GoogleDriveFileStorage()
|
||||
{
|
||||
logDebug("Creating GDrive FileStorage.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkForFileChangeFast(String path,
|
||||
String previousFileVersion) throws Exception {
|
||||
String currentVersion = getCurrentFileVersionFast(path);
|
||||
if (currentVersion == null)
|
||||
return false;
|
||||
return currentVersion.equals(previousFileVersion) == false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCurrentFileVersionFast(String path) {
|
||||
|
||||
try {
|
||||
GDrivePath gdrivePath = new GDrivePath(path);
|
||||
return getFileForPath(gdrivePath, getDriveService(gdrivePath.getAccount())).getMd5Checksum();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream openFileForRead(String path) throws Exception {
|
||||
|
||||
logDebug("openFileForRead...");
|
||||
GDrivePath gdrivePath = new GDrivePath(path);
|
||||
Drive driveService = getDriveService(gdrivePath.getAccount());
|
||||
|
||||
try
|
||||
{
|
||||
File file = getFileForPath(gdrivePath, driveService);
|
||||
InputStream res = getFileContent(file, driveService);
|
||||
logDebug("openFileForRead ok.");
|
||||
return res;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw convertException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private File getFileForPath(GDrivePath path, Drive driveService)
|
||||
throws IOException, InvalidPathException {
|
||||
logDebug("getFileForPath... ");
|
||||
try
|
||||
{
|
||||
//throw new IOException("argh");
|
||||
String driveId = path.getGDriveId();
|
||||
logDebug("id"+driveId);
|
||||
File file = driveService.files().get(driveId).execute();
|
||||
logDebug("...done.");
|
||||
return file;
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
throw e;
|
||||
}
|
||||
catch (InvalidPathException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
throw e;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
private InputStream getFileContent(File driveFile, Drive driveService) throws IOException {
|
||||
if (driveFile.getDownloadUrl() != null && driveFile.getDownloadUrl().length() > 0) {
|
||||
|
||||
GenericUrl downloadUrl = new GenericUrl(driveFile.getDownloadUrl());
|
||||
|
||||
HttpResponse resp = driveService.getRequestFactory().buildGetRequest(downloadUrl).execute();
|
||||
return resp.getContent();
|
||||
} else {
|
||||
//return an empty input stream
|
||||
return new ByteArrayInputStream("".getBytes());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void uploadFile(String path, byte[] data, boolean writeTransactional)
|
||||
throws Exception {
|
||||
logDebug("upload file...");
|
||||
try
|
||||
{
|
||||
ByteArrayContent content = new ByteArrayContent(null, data);
|
||||
GDrivePath gdrivePath = new GDrivePath(path);
|
||||
Drive driveService = getDriveService(gdrivePath.getAccount());
|
||||
|
||||
File driveFile = getFileForPath(gdrivePath, driveService);
|
||||
getDriveService(gdrivePath.getAccount()).files()
|
||||
.update(driveFile.getId(), driveFile, content).execute();
|
||||
logDebug("upload file ok.");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw convertException(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String createFolder(String parentPath, String newDirName) throws Exception {
|
||||
File body = new File();
|
||||
body.setTitle(newDirName);
|
||||
body.setMimeType(FOLDER_MIME_TYPE);
|
||||
|
||||
GDrivePath parentGdrivePath = new GDrivePath(parentPath);
|
||||
|
||||
body.setParents(
|
||||
Arrays.asList(new ParentReference().setId(parentGdrivePath.getGDriveId())));
|
||||
try
|
||||
{
|
||||
File file = getDriveService(parentGdrivePath.getAccount()).files().insert(body).execute();
|
||||
|
||||
logDebug("created folder "+newDirName+" in "+parentPath+". id: "+file.getId());
|
||||
|
||||
return new GDrivePath(parentPath, file).getFullPath();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw convertException(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String createFilePath(String parentPath, String newFileName) throws Exception {
|
||||
File body = new File();
|
||||
body.setTitle(newFileName);
|
||||
GDrivePath parentGdrivePath = new GDrivePath(parentPath);
|
||||
|
||||
body.setParents(
|
||||
Arrays.asList(new ParentReference().setId(parentGdrivePath.getGDriveId())));
|
||||
try
|
||||
{
|
||||
File file = getDriveService(parentGdrivePath.getAccount()).files().insert(body).execute();
|
||||
|
||||
return new GDrivePath(parentPath, file).getFullPath();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw convertException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public List<FileEntry> listFiles(String parentPath) throws Exception {
|
||||
GDrivePath gdrivePath = new GDrivePath(parentPath);
|
||||
String parentId = gdrivePath.getGDriveId();
|
||||
|
||||
List<FileEntry> result = new ArrayList<FileEntry>();
|
||||
|
||||
Drive driveService = getDriveService(gdrivePath.getAccount());
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
if (driveService.files().get(parentId).execute().getLabels().getTrashed())
|
||||
throw new FileNotFoundException(parentPath + " is trashed!");
|
||||
logDebug("listing files in "+parentId);
|
||||
Files.List request = driveService.files().list()
|
||||
.setQ("trashed=false and '" + parentId + "' in parents");
|
||||
|
||||
do {
|
||||
try {
|
||||
FileList files = request.execute();
|
||||
|
||||
for (File file : files.getItems()) {
|
||||
|
||||
String path = new GDrivePath(parentPath, file).getFullPath();
|
||||
logDebug("listing file "+path);
|
||||
FileEntry e = convertToFileEntry(file, path);
|
||||
|
||||
result.add(e);
|
||||
}
|
||||
request.setPageToken(files.getNextPageToken());
|
||||
} catch (IOException e) {
|
||||
System.out.println("An error occurred: " + e);
|
||||
request.setPageToken(null);
|
||||
throw e;
|
||||
}
|
||||
} while (request.getPageToken() != null && request.getPageToken().length() > 0);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw convertException(e);
|
||||
}
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
private Exception convertException(Exception e) {
|
||||
logDebug("Exception: " + e.toString());
|
||||
e.printStackTrace();
|
||||
if (UserRecoverableAuthIOException.class.isAssignableFrom(e.getClass()))
|
||||
{
|
||||
logDebug("clearing account data.");
|
||||
//this is not really nice because it removes data from the cache which might still be valid but we don't have the account name here...
|
||||
mAccountData.clear();
|
||||
}
|
||||
if (GoogleJsonResponseException.class.isAssignableFrom(e.getClass()) )
|
||||
{
|
||||
GoogleJsonResponseException jsonEx = (GoogleJsonResponseException)e;
|
||||
if (jsonEx.getDetails().getCode() == 404)
|
||||
return new FileNotFoundException(jsonEx.getMessage());
|
||||
}
|
||||
|
||||
return e;
|
||||
|
||||
}
|
||||
|
||||
|
||||
private FileEntry convertToFileEntry(File file, String path) {
|
||||
FileEntry e = new FileEntry();
|
||||
e.canRead = e.canWrite = true;
|
||||
e.isDirectory = FOLDER_MIME_TYPE.equals(file.getMimeType());
|
||||
e.lastModifiedTime = file.getModifiedDate().getValue();
|
||||
e.path = path;
|
||||
try
|
||||
{
|
||||
e.sizeInBytes = file.getFileSize();
|
||||
}
|
||||
catch (NullPointerException ex)
|
||||
{
|
||||
e.sizeInBytes = 0;
|
||||
}
|
||||
e.displayName = file.getTitle();
|
||||
return e;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public FileEntry getFileEntry(String filename) throws Exception {
|
||||
|
||||
try
|
||||
{
|
||||
logDebug("getFileEntry "+filename);
|
||||
GDrivePath gdrivePath = new GDrivePath(filename);
|
||||
FileEntry res = convertToFileEntry(
|
||||
getFileForPath(gdrivePath, getDriveService(gdrivePath.getAccount())),
|
||||
filename);
|
||||
logDebug("getFileEntry res" + res);
|
||||
return res;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logDebug("Exception in getFileEntry! "+e);
|
||||
throw convertException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(String path) throws Exception {
|
||||
|
||||
GDrivePath gdrivePath = new GDrivePath(path);
|
||||
Drive driveService = getDriveService(gdrivePath.getAccount());
|
||||
try
|
||||
{
|
||||
driveService.files().delete(gdrivePath.getGDriveId()).execute();
|
||||
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw convertException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private Drive createDriveService(String accountName, Context appContext) {
|
||||
logDebug("createDriveService "+accountName);
|
||||
GoogleAccountCredential credential = createCredential(appContext);
|
||||
credential.setSelectedAccountName(accountName);
|
||||
|
||||
return new Drive.Builder(AndroidHttp.newCompatibleTransport(), new GsonFactory(), credential)
|
||||
.setApplicationName(getApplicationName())
|
||||
.build();
|
||||
}
|
||||
|
||||
protected String getApplicationName()
|
||||
{
|
||||
return "Keepass2Android";
|
||||
}
|
||||
|
||||
private Drive getDriveService(String accountName)
|
||||
{
|
||||
logDebug("getDriveService "+accountName);
|
||||
AccountData accountData = mAccountData.get(accountName);
|
||||
logDebug("accountData " + accountData);
|
||||
return accountData.drive;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityResult(final JavaFileStorage.FileStorageSetupActivity setupAct, int requestCode, int resultCode, Intent data) {
|
||||
logDebug("ActivityResult: " + requestCode + "/" + resultCode);
|
||||
switch (requestCode) {
|
||||
case REQUEST_ACCOUNT_PICKER:
|
||||
logDebug("ActivityResult: REQUEST_ACCOUNT_PICKER");
|
||||
if (resultCode == Activity.RESULT_OK && data != null && data.getExtras() != null) {
|
||||
String accountName = data.getStringExtra(AccountManager.KEY_ACCOUNT_NAME);
|
||||
if (accountName != null) {
|
||||
logDebug("Initialize Account name="+accountName);
|
||||
initializeAccountOrPath(setupAct, accountName);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
logDebug("Error selecting account");
|
||||
//Intent retData = new Intent();
|
||||
//retData.putExtra(EXTRA_ERROR_MESSAGE, t.getMessage());
|
||||
((Activity)setupAct).setResult(Activity.RESULT_CANCELED, data);
|
||||
((Activity)setupAct).finish();
|
||||
|
||||
case REQUEST_AUTHORIZATION:
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
//for (String k: data.getExtras().keySet())
|
||||
//{
|
||||
//logDebug(data.getExtras().get(k).toString());
|
||||
//}
|
||||
String accountName = data.getStringExtra(AccountManager.KEY_ACCOUNT_NAME);
|
||||
if (accountName != null) {
|
||||
logDebug("Account name="+accountName);
|
||||
initializeAccountOrPath(setupAct, accountName);
|
||||
}
|
||||
else
|
||||
{
|
||||
logDebug("Account name is null");
|
||||
}
|
||||
} else {
|
||||
logDebug("Error authenticating");
|
||||
//Intent retData = new Intent();
|
||||
//retData.putExtra(EXTRA_ERROR_MESSAGE, t.getMessage());
|
||||
((Activity)setupAct).setResult(Activity.RESULT_CANCELED, data);
|
||||
((Activity)setupAct).finish();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void initializeAccountOrPath(final JavaFileStorage.FileStorageSetupActivity setupAct, final String accountNameOrPath) {
|
||||
|
||||
final Activity activity = ((Activity)setupAct);
|
||||
final Context appContext = activity.getApplicationContext();
|
||||
|
||||
String accountNameTemp;
|
||||
GDrivePath gdrivePath = null;
|
||||
if (accountNameOrPath.startsWith(getProtocolPrefix()))
|
||||
{
|
||||
gdrivePath = new GDrivePath();
|
||||
//don't verify yet, we're not yet initialized:
|
||||
try {
|
||||
gdrivePath.setPathWithoutVerify(accountNameOrPath);
|
||||
} catch (Exception e) {
|
||||
finishWithError(setupAct, e);
|
||||
}
|
||||
accountNameTemp = gdrivePath.getAccount();
|
||||
}
|
||||
else
|
||||
accountNameTemp = accountNameOrPath;
|
||||
|
||||
final String accountName = accountNameTemp;
|
||||
|
||||
AsyncTask<Object, Void, AsyncTaskResult<String> > task = new AsyncTask<Object, Void, AsyncTaskResult<String>>()
|
||||
{
|
||||
|
||||
@Override
|
||||
protected AsyncTaskResult<String> doInBackground(Object... arg0) {
|
||||
try {
|
||||
|
||||
|
||||
initializeAccount(appContext, accountName);
|
||||
|
||||
if (setupAct.getProcessName().equals(PROCESS_NAME_SELECTFILE))
|
||||
setupAct.getState().putString(EXTRA_PATH, getRootPathForAccount(accountName));
|
||||
|
||||
return new AsyncTaskResult<String>("ok");
|
||||
} catch ( Exception anyError) {
|
||||
return new AsyncTaskResult<String>(anyError);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(AsyncTaskResult<String> result) {
|
||||
Exception error = result.getError();
|
||||
if (error != null ) {
|
||||
if (UserRecoverableAuthIOException.class.isAssignableFrom(error.getClass()))
|
||||
{
|
||||
mAccountData.remove(accountName);
|
||||
activity.startActivityForResult(((UserRecoverableAuthIOException)error).getIntent(), REQUEST_AUTHORIZATION);
|
||||
}
|
||||
else
|
||||
{
|
||||
finishWithError(setupAct, error);
|
||||
}
|
||||
} else if ( isCancelled()) {
|
||||
// cancel handling here
|
||||
logDebug("Async Task cancelled!");
|
||||
|
||||
activity.setResult(Activity.RESULT_CANCELED);
|
||||
activity.finish();
|
||||
} else {
|
||||
|
||||
//all right!
|
||||
finishActivityWithSuccess(setupAct);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
task.execute(new Object[]{});
|
||||
|
||||
}
|
||||
|
||||
private void initializeAccount(final Context appContext,
|
||||
final String accountName) throws IOException {
|
||||
logDebug("Init account for " + accountName);
|
||||
if (!mAccountData.containsKey(accountName))
|
||||
{
|
||||
AccountData newAccountData = new AccountData();
|
||||
newAccountData.drive = createDriveService(accountName, appContext);
|
||||
mAccountData.put(accountName, newAccountData);
|
||||
logDebug("Added account data for " + accountName);
|
||||
}
|
||||
AccountData accountData = mAccountData.get(accountName);
|
||||
//try to finish the initialization. If this fails, we throw.
|
||||
//in case of "Always return true" (inside CachingFileStorage) this means
|
||||
//we have a partially uninitialized AccountData object.
|
||||
//We'll try to initialize later in verify() if (e.g.) network is available again.
|
||||
finishInitialization(accountData, accountName);
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void finishInitialization(AccountData newAccountData, String accountName) throws IOException
|
||||
{
|
||||
|
||||
if (TextUtils.isEmpty(newAccountData.mRootFolderId))
|
||||
{
|
||||
logDebug("Finish init account for " + accountName);
|
||||
About about = newAccountData.drive.about().get().execute();
|
||||
newAccountData.mRootFolderId = about.getRootFolderId();
|
||||
}
|
||||
else
|
||||
{
|
||||
logDebug("Account for " + accountName + " already fully initialized.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startSelectFile(JavaFileStorage.FileStorageSetupInitiatorActivity activity, boolean isForSave,
|
||||
int requestCode) {
|
||||
((JavaFileStorage.FileStorageSetupInitiatorActivity)(activity)).startSelectFileProcess(getProtocolPrefix(), isForSave, requestCode);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void prepareFileUsage(JavaFileStorage.FileStorageSetupInitiatorActivity activity, String path, int requestCode, boolean alwaysReturnSuccess) {
|
||||
((JavaFileStorage.FileStorageSetupInitiatorActivity)(activity)).startFileUsageProcess(path, requestCode, alwaysReturnSuccess);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
public void prepareFileUsage(Context appContext, String path) throws UserInteractionRequiredException, Throwable
|
||||
{
|
||||
try
|
||||
{
|
||||
logDebug("prepareFileUsage " + path + "...");
|
||||
String accountName;
|
||||
GDrivePath gdrivePath = null;
|
||||
if (path.startsWith(getProtocolPrefix()))
|
||||
{
|
||||
gdrivePath = new GDrivePath();
|
||||
//don't verify yet, we're not yet initialized:
|
||||
gdrivePath.setPathWithoutVerify(path);
|
||||
|
||||
accountName = gdrivePath.getAccount();
|
||||
}
|
||||
else
|
||||
accountName = path;
|
||||
|
||||
initializeAccount(appContext, accountName);
|
||||
logDebug("prepareFileUsage ok");
|
||||
}
|
||||
catch (UserRecoverableAuthIOException e)
|
||||
{
|
||||
logDebug("prepareFileUsage: UserInteractionRequiredException");
|
||||
throw new UserInteractionRequiredException(e);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProtocolId() {
|
||||
return GDRIVE_PROTOCOL_ID;
|
||||
}
|
||||
|
||||
|
||||
@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
|
||||
public void onResume(JavaFileStorage.FileStorageSetupActivity setupAct) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart(final JavaFileStorage.FileStorageSetupActivity setupAct) {
|
||||
logDebug("onStart "+mRequiresRuntimePermissions);
|
||||
if (!mRequiresRuntimePermissions)
|
||||
{
|
||||
initFileStorage(setupAct);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
private GoogleAccountCredential createCredential(Context appContext) {
|
||||
List<String> scopes = new ArrayList<String>();
|
||||
scopes.add(DriveScopes.DRIVE);
|
||||
GoogleAccountCredential credential = GoogleAccountCredential.usingOAuth2(appContext, scopes);
|
||||
return credential;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean requiresSetup(String path) {
|
||||
//always send the user through the prepare file usage workflow if he needs to authorize
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(FileStorageSetupActivity activity,
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getDisplayName(String path) {
|
||||
GDrivePath gdrivePath = new GDrivePath();
|
||||
try {
|
||||
gdrivePath.setPathWithoutVerify(path);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return path;
|
||||
}
|
||||
return gdrivePath.getDisplayName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFilename(String path) throws Exception
|
||||
{
|
||||
GDrivePath gdrivePath = new GDrivePath();
|
||||
gdrivePath.setPathWithoutVerify(path);
|
||||
|
||||
return gdrivePath.getFilename();
|
||||
}
|
||||
|
||||
|
||||
}
|
@@ -1,182 +0,0 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
This project contains annotations derived from JCIP-ANNOTATIONS
|
||||
Copyright (c) 2005 Brian Goetz and Tim Peierls.
|
||||
See http://www.jcip.net and the Creative Commons Attribution License
|
||||
(http://creativecommons.org/licenses/by/2.5)
|
||||
|
@@ -1,202 +0,0 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -141,8 +141,6 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
//import keepass2android.javafilestorage.DropboxCloudRailStorage;
|
||||
import keepass2android.javafilestorage.DropboxV2Storage;
|
||||
import keepass2android.javafilestorage.ICertificateErrorHandler;
|
||||
import keepass2android.javafilestorage.JavaFileStorage;
|
||||
import keepass2android.javafilestorage.JavaFileStorage.FileEntry;
|
||||
import keepass2android.javafilestorage.OneDriveStorage;
|
||||
|
@@ -86,7 +86,6 @@
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/jniLibs" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/lint" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/manifests" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/proguard-rules" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/res" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/rs" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/shaders" />
|
||||
|
@@ -1,144 +0,0 @@
|
||||
<?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">
|
||||
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="23" />
|
||||
<permission android:description="@string/permission_desc" android:icon="@drawable/ic_notify_locked" android:label="KP2A internal file browsing" android:name="keepass2android.keepass2android_debug.permission.KP2aInternalFileBrowsing" android:protectionLevel="signature" />
|
||||
<permission android:description="@string/permission_desc2" android:icon="@drawable/ic_notify_locked" android:label="KP2A entry search" android:name="keepass2android.keepass2android_debug.permission.KP2aInternalSearch" android:protectionLevel="signature" />
|
||||
<application android:label="keepass2android" android:icon="@drawable/ic_launcher">
|
||||
|
||||
<activity android:name="com.dropbox.core.android.AuthActivity" android:launchMode="singleTask" android:configChanges="orientation|keyboard">
|
||||
<intent-filter>
|
||||
<data android:scheme="db-2gormiq7iq1jls1" />
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<data android:scheme="db-ax0268uydp1ya57" />
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
|
||||
</activity>
|
||||
|
||||
<provider android:name="group.pals.android.lib.ui.filechooser.providers.localfile.LocalFileProvider" android:authorities="keepass2android.keepass2android_debug.android-filechooser.localfile" android:exported="false" />
|
||||
<provider android:name="group.pals.android.lib.ui.filechooser.providers.history.HistoryProvider" android:authorities="keepass2android.keepass2android_debug.android-filechooser.history" android:exported="false" />
|
||||
<activity android:name="group.pals.android.lib.ui.filechooser.FileChooserActivity" android:configChanges="keyboard|keyboardHidden|orientation|screenSize" android:screenOrientation="user" android:theme="@style/Afc.Theme.Light">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.GET_CONTENT" />
|
||||
<data android:mimeType="*/*" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.OPENABLE" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<service android:name="keepass2android.autofill.AutoFillService"
|
||||
android:enabled="true"
|
||||
android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
|
||||
<intent-filter>
|
||||
<action android:name="android.accessibilityservice.AccessibilityService" />
|
||||
</intent-filter>
|
||||
<meta-data
|
||||
android:name="android.accessibilityservice"
|
||||
android:resource="@xml/accserviceconfig" />
|
||||
</service>
|
||||
<service android:name="keepass2android.softkeyboard.KP2AKeyboard" android:permission="android.permission.BIND_INPUT_METHOD">
|
||||
<intent-filter>
|
||||
<action android:name="android.view.InputMethod" />
|
||||
</intent-filter>
|
||||
<meta-data android:name="android.view.im" android:resource="@xml/method" />
|
||||
</service>
|
||||
<activity android:name="keepass2android.softkeyboard.LatinIMESettings" android:label="@string/english_ime_settings">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="keepass2android.softkeyboard.LatinIMESettings" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity android:name="keepass2android.softkeyboard.InputLanguageSelection"
|
||||
android:label="@string/language_selection_title">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<action android:name="keepass2android.softkeyboard.INPUT_LANGUAGE_SELECTION"/>
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<service android:name="keepass2android.autofill.AutoFillService"
|
||||
android:enabled="true"
|
||||
android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
|
||||
<intent-filter>
|
||||
<action android:name="android.accessibilityservice.AccessibilityService" />
|
||||
</intent-filter>
|
||||
<meta-data
|
||||
android:name="android.accessibilityservice"
|
||||
android:resource="@xml/accserviceconfig" />
|
||||
|
||||
</service>
|
||||
|
||||
<activity android:configChanges="orientation" android:label="@string/app_name" android:theme="@style/MyTheme_Blue" android:name="keepass2android.PasswordActivity" android:windowSoftInputMode="adjustResize">
|
||||
<intent-filter android:label="@string/app_name">
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<data android:scheme="content" />
|
||||
<data android:mimeType="*/*" />
|
||||
<data android:host="*" />
|
||||
</intent-filter>
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="kp2a.action.PasswordActivity" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
|
||||
|
||||
<intent-filter android:label="@string/app_name">
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<data android:scheme="file" />
|
||||
<data android:mimeType="*/*" />
|
||||
<data android:host="*" />
|
||||
<data android:pathPattern=".*\\.kdbp" />
|
||||
<data android:pathPattern=".*\\..*\\.kdbp" />
|
||||
<data android:pathPattern=".*\\..*\\..*\\.kdbp" />
|
||||
<data android:pathPattern=".*\\..*\\..*\\..*\\.kdbp" />
|
||||
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\.kdbp" />
|
||||
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\.kdbp" />
|
||||
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdbp" />
|
||||
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdbp" />
|
||||
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdbp" />
|
||||
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdbp" />
|
||||
<data android:pathPattern=".*\\.kdbx" />
|
||||
<data android:pathPattern=".*\\..*\\.kdbx" />
|
||||
<data android:pathPattern=".*\\..*\\..*\\.kdbx" />
|
||||
<data android:pathPattern=".*\\..*\\..*\\..*\\.kdbx" />
|
||||
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\.kdbx" />
|
||||
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\.kdbx" />
|
||||
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdbx" />
|
||||
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdbx" />
|
||||
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdbx" />
|
||||
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdbx" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<uses-library required="false" name="com.sec.android.app.multiwindow" />
|
||||
<meta-data android:name="com.sec.android.support.multiwindow" android:value="true" />
|
||||
<meta-data android:name="com.sec.android.multiwindow.DEFAULT_SIZE_W" android:value="632.0dip" />
|
||||
<meta-data android:name="com.sec.android.multiwindow.DEFAULT_SIZE_H" android:value="598.0dip" />
|
||||
<meta-data android:name="com.sec.android.multiwindow.MINIMUM_SIZE_W" android:value="426.0dip" />
|
||||
<meta-data android:name="com.sec.android.multiwindow.MINIMUM_SIZE_H" android:value="360.0dip" />
|
||||
</application>
|
||||
<uses-permission android:name="android.permission.VIBRATE" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
|
||||
<uses-permission android:name="android.permission.USE_CREDENTIALS" />
|
||||
<uses-permission android:name="android.permission.MANAGE_ACCOUNTS" />
|
||||
<uses-permission android:name="keepass2android.keepass2android_debug.permission.KP2aInternalFileBrowsing" />
|
||||
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
|
||||
<!-- Samsung Pass permission -->
|
||||
<uses-permission android:name="com.samsung.android.providers.context.permission.WRITE_USE_APP_FEATURE_SURVEY" />
|
||||
<uses-permission android:name="android.permission.BIND_ACCESSIBILITY_SERVICE" />
|
||||
|
||||
</manifest>
|
@@ -1,48 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="23" android:versionName="0.8.6" package="keepass2android.keepass2android" android:installLocation="auto">
|
||||
<uses-sdk android:minSdkVersion="8" android:targetSdkVersion="14" />
|
||||
<application android:label="keepass2android" android:icon="@drawable/ic_launcher">
|
||||
<activity android:name="com.dropbox.client2.android.AuthActivity" android:launchMode="singleTask" android:configChanges="orientation|keyboard">
|
||||
<intent-filter>
|
||||
<!-- Change this to be db- followed by your app key -->
|
||||
<data android:scheme="db-i8shu7v1hgh7ynt" />
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity android:configChanges="keyboardHidden|orientation" android:label="@string/app_name" android:theme="@style/MyTheme" android:name="keepass2android.PasswordActivity">
|
||||
<intent-filter android:label="@string/app_name">
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<data android:scheme="file" />
|
||||
<data android:mimeType="*/*" />
|
||||
<data android:host="*" />
|
||||
<data android:pathPattern=".*\\.kdbp" />
|
||||
<data android:pathPattern=".*\\..*\\.kdbp" />
|
||||
<data android:pathPattern=".*\\..*\\..*\\.kdbp" />
|
||||
<data android:pathPattern=".*\\..*\\..*\\..*\\.kdbp" />
|
||||
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\.kdbp" />
|
||||
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\.kdbp" />
|
||||
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdbp" />
|
||||
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdbp" />
|
||||
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdbp" />
|
||||
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdbp" />
|
||||
<data android:pathPattern=".*\\.kdbx" />
|
||||
<data android:pathPattern=".*\\..*\\.kdbx" />
|
||||
<data android:pathPattern=".*\\..*\\..*\\.kdbx" />
|
||||
<data android:pathPattern=".*\\..*\\..*\\..*\\.kdbx" />
|
||||
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\.kdbx" />
|
||||
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\.kdbx" />
|
||||
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdbx" />
|
||||
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdbx" />
|
||||
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdbx" />
|
||||
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdbx" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
<uses-permission android:name="android.permission.VIBRATE" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
</manifest>
|
@@ -2,11 +2,11 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:versionCode="98"
|
||||
android:versionName="1.02"
|
||||
package="keepass2android.keepass2android"
|
||||
package="keepass2android.keepass2android_fdroid"
|
||||
android:installLocation="auto">
|
||||
<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_desc2" android:icon="@drawable/ic_launcher_online" android:label="KP2A entry search" android:name="keepass2android.keepass2android.permission.KP2aInternalSearch" 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_fdroid.permission.KP2aInternalFileBrowsing" android:protectionLevel="signature" />
|
||||
<permission android:description="@string/permission_desc2" android:icon="@drawable/ic_launcher_online" android:label="KP2A entry search" android:name="keepass2android.keepass2android_fdroid.permission.KP2aInternalSearch" android:protectionLevel="signature" />
|
||||
|
||||
<application android:label="keepass2android" android:icon="@drawable/ic_launcher_online">
|
||||
<activity android:name="com.dropbox.core.android.AuthActivity" android:launchMode="singleTask" android:configChanges="orientation|keyboard">
|
||||
@@ -25,8 +25,8 @@
|
||||
|
||||
</activity>
|
||||
|
||||
<provider android:name="group.pals.android.lib.ui.filechooser.providers.localfile.LocalFileProvider" android:authorities="keepass2android.keepass2android.android-filechooser.localfile" android:exported="false" />
|
||||
<provider android:name="group.pals.android.lib.ui.filechooser.providers.history.HistoryProvider" android:authorities="keepass2android.keepass2android.android-filechooser.history" android:exported="false" />
|
||||
<provider android:name="group.pals.android.lib.ui.filechooser.providers.localfile.LocalFileProvider" android:authorities="keepass2android.keepass2android_fdroid.android-filechooser.localfile" android:exported="false" />
|
||||
<provider android:name="group.pals.android.lib.ui.filechooser.providers.history.HistoryProvider" android:authorities="keepass2android.keepass2android_fdroid.android-filechooser.history" android:exported="false" />
|
||||
<activity android:name="group.pals.android.lib.ui.filechooser.FileChooserActivity" android:configChanges="keyboard|keyboardHidden|orientation|screenSize" android:screenOrientation="user" android:theme="@style/Afc.Theme.Light">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.GET_CONTENT" />
|
||||
@@ -144,11 +144,8 @@
|
||||
<uses-permission android:name="android.permission.VIBRATE" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
|
||||
<uses-permission android:name="android.permission.USE_CREDENTIALS" />
|
||||
<uses-permission android:name="android.permission.MANAGE_ACCOUNTS" />
|
||||
<uses-permission android:name="keepass2android.keepass2android.permission.KP2aInternalFileBrowsing" />
|
||||
<uses-permission android:name="keepass2android.keepass2android_debug.permission.KP2aInternalSearch" />
|
||||
<uses-permission android:name="keepass2android.keepass2android_fdroid.permission.KP2aInternalFileBrowsing" />
|
||||
<uses-permission android:name="keepass2android.keepass2android_fdroid.permission.KP2aInternalSearch" />
|
||||
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
|
||||
<uses-permission android:name="android.permission.BIND_ACCESSIBILITY_SERVICE" />
|
||||
|
||||
|
@@ -1,134 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:versionCode="93"
|
||||
android:versionName="1.01-g"
|
||||
package="keepass2android.keepass2android_nonet"
|
||||
android:installLocation="auto">
|
||||
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="23" />
|
||||
<permission android:description="@string/permission_desc2" android:icon="@drawable/ic_launcher_online" android:label="KP2A entry search" android:name="keepass2android.keepass2android_nonet.permission.KP2aInternalSearch" android:protectionLevel="signature" />
|
||||
<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.history.HistoryProvider" android:authorities="keepass2android.keepass2android_nonet.android-filechooser.history" android:exported="false" />
|
||||
<activity android:name="group.pals.android.lib.ui.filechooser.FileChooserActivity" android:configChanges="keyboard|keyboardHidden|orientation|screenSize" android:screenOrientation="user" android:theme="@style/Afc.Theme.Light">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.GET_CONTENT" />
|
||||
<data android:mimeType="*/*" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.OPENABLE" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<service android:name="keepass2android.autofill.AutoFillService"
|
||||
android:enabled="true"
|
||||
android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
|
||||
<intent-filter>
|
||||
<action android:name="android.accessibilityservice.AccessibilityService" />
|
||||
</intent-filter>
|
||||
<meta-data
|
||||
android:name="android.accessibilityservice"
|
||||
android:resource="@xml/accserviceconfig" />
|
||||
</service>
|
||||
|
||||
<service android:name="keepass2android.softkeyboard.KP2AKeyboard" android:permission="android.permission.BIND_INPUT_METHOD">
|
||||
<intent-filter>
|
||||
<action android:name="android.view.InputMethod" />
|
||||
</intent-filter>
|
||||
<meta-data android:name="android.view.im" android:resource="@xml/method" />
|
||||
</service>
|
||||
<activity android:name="keepass2android.softkeyboard.LatinIMESettings" android:label="@string/english_ime_settings">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="keepass2android.softkeyboard.LatinIMESettings" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity android:name="keepass2android.softkeyboard.InputLanguageSelection"
|
||||
android:label="@string/language_selection_title">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<action android:name="keepass2android.softkeyboard.INPUT_LANGUAGE_SELECTION"/>
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity android:configChanges="orientation" android:label="@string/app_name" android:theme="@style/MyTheme_Blue" android:name="keepass2android.PasswordActivity" android:windowSoftInputMode="adjustResize">
|
||||
<intent-filter android:label="@string/app_name">
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<data android:scheme="content" />
|
||||
<data android:mimeType="application/octet-stream" />
|
||||
<data android:host="*" />
|
||||
</intent-filter>
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="kp2a.action.PasswordActivity" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
|
||||
<intent-filter android:label="@string/app_name">
|
||||
<action android:name="android.intent.action.SEND" />
|
||||
<action android:name="android.intent.action.SEND_MULTIPLE" />
|
||||
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
|
||||
<data android:mimeType="application/*" />
|
||||
</intent-filter>
|
||||
|
||||
<intent-filter android:label="@string/app_name">
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<data android:scheme="file" />
|
||||
<data android:scheme="content" />
|
||||
<data android:mimeType="*/*" />
|
||||
<data android:host="*" />
|
||||
<data android:pathPattern=".*\\.kdbp" />
|
||||
<data android:pathPattern=".*\\..*\\.kdbp" />
|
||||
<data android:pathPattern=".*\\..*\\..*\\.kdbp" />
|
||||
<data android:pathPattern=".*\\..*\\..*\\..*\\.kdbp" />
|
||||
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\.kdbp" />
|
||||
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\.kdbp" />
|
||||
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdbp" />
|
||||
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdbp" />
|
||||
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdbp" />
|
||||
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdbp" />
|
||||
<data android:pathPattern=".*\\.kdbx" />
|
||||
<data android:pathPattern=".*\\..*\\.kdbx" />
|
||||
<data android:pathPattern=".*\\..*\\..*\\.kdbx" />
|
||||
<data android:pathPattern=".*\\..*\\..*\\..*\\.kdbx" />
|
||||
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\.kdbx" />
|
||||
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\.kdbx" />
|
||||
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdbx" />
|
||||
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdbx" />
|
||||
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdbx" />
|
||||
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdbx" />
|
||||
<data android:pathPattern=".*\\.kdb" />
|
||||
<data android:pathPattern=".*\\..*\\.kdb" />
|
||||
<data android:pathPattern=".*\\..*\\..*\\.kdb" />
|
||||
<data android:pathPattern=".*\\..*\\..*\\..*\\.kdb" />
|
||||
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\.kdb" />
|
||||
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\.kdb" />
|
||||
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdb" />
|
||||
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdb" />
|
||||
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdb" />
|
||||
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdb" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<uses-library required="false" name="com.sec.android.app.multiwindow" />
|
||||
<meta-data android:name="com.sec.android.support.multiwindow" android:value="true" />
|
||||
<meta-data android:name="com.sec.android.multiwindow.DEFAULT_SIZE_W" android:value="632.0dip" />
|
||||
<meta-data android:name="com.sec.android.multiwindow.DEFAULT_SIZE_H" android:value="598.0dip" />
|
||||
<meta-data android:name="com.sec.android.multiwindow.MINIMUM_SIZE_W" android:value="426.0dip" />
|
||||
<meta-data android:name="com.sec.android.multiwindow.MINIMUM_SIZE_H" android:value="360.0dip" />
|
||||
</application>
|
||||
<uses-permission android:name="android.permission.VIBRATE" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
|
||||
<uses-permission android:name="android.permission.BIND_ACCESSIBILITY_SERVICE" />
|
||||
<uses-permission android:name="keepass2android.keepass2android.permission.KP2aInternalFileBrowsing" />
|
||||
<uses-permission android:name="keepass2android.keepass2android_debug.permission.KP2aInternalSearch" />
|
||||
<!-- Samsung Pass permission -->
|
||||
<uses-permission android:name="com.samsung.android.providers.context.permission.WRITE_USE_APP_FEATURE_SURVEY" />
|
||||
</manifest>
|
Binary file not shown.
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.4 KiB |
Binary file not shown.
Before Width: | Height: | Size: 4.7 KiB After Width: | Height: | Size: 4.9 KiB |
@@ -4,7 +4,7 @@
|
||||
android:hint="@string/search_hint"
|
||||
android:searchSettingsDescription="Search database"
|
||||
android:searchMode="showSearchLabelAsBadge"
|
||||
android:searchSuggestAuthority="kp2a.keepass2android.SearchProvider"
|
||||
android:searchSuggestAuthority="kp2a.keepass2android_fdroid.SearchProvider"
|
||||
android:searchSuggestIntentAction="android.intent.action.VIEW"
|
||||
android:searchSuggestSelection=" ?"
|
||||
android:searchSuggestThreshold="2" />
|
@@ -40,7 +40,6 @@ using keepass2android.Io;
|
||||
using keepass2android.addons.OtpKeyProv;
|
||||
#if !NoNet
|
||||
using Keepass2android.Javafilestorage;
|
||||
using GoogleDriveFileStorage = keepass2android.Io.GoogleDriveFileStorage;
|
||||
#endif
|
||||
namespace keepass2android
|
||||
{
|
||||
@@ -80,7 +79,7 @@ namespace keepass2android
|
||||
public const string PackagePart = "keepass2android_debug";
|
||||
public const string Searchable = "@xml/searchable_debug";
|
||||
#else
|
||||
public const string PackagePart = "keepass2android";
|
||||
public const string PackagePart = "keepass2android_fdroid";
|
||||
public const string Searchable = "@xml/searchable";
|
||||
#endif
|
||||
public const int LauncherIcon = Resource.Drawable.ic_launcher_online;
|
||||
@@ -511,9 +510,6 @@ namespace keepass2android
|
||||
new AndroidContentStorage(Application.Context),
|
||||
#if !EXCLUDE_JAVAFILESTORAGE
|
||||
#if !NoNet
|
||||
new DropboxFileStorage(Application.Context, this),
|
||||
new DropboxAppFolderFileStorage(Application.Context, this),
|
||||
new GoogleDriveFileStorage(Application.Context, this),
|
||||
new OneDriveFileStorage(Application.Context, this),
|
||||
new SftpFileStorage(this),
|
||||
new NetFtpFileStorage(Application.Context, this),
|
||||
|
Reference in New Issue
Block a user