mirror of
https://github.com/moparisthebest/keepass2android
synced 2025-01-09 04:28:05 -05:00
* GoogleDrive: remove full path check, display only filename
* added method prepareFileUsage() without Activity parameter
This commit is contained in:
parent
d93946ed05
commit
458e0a3d90
@ -417,6 +417,15 @@ public class DropboxFileStorage extends JavaFileStorageBase {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void prepareFileUsage(Context appContext, String path) throws UserInteractionRequiredException {
|
||||
if (!isConnected())
|
||||
{
|
||||
throw new UserInteractionRequiredException();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(FileStorageSetupActivity activity, Bundle savedInstanceState) {
|
||||
|
@ -29,6 +29,7 @@ import com.google.api.services.drive.model.ParentReference;
|
||||
|
||||
import android.accounts.AccountManager;
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
@ -57,9 +58,6 @@ public class GoogleDriveFileStorage extends JavaFileStorageBase {
|
||||
//guaranteed to be set if AccountData is in HashMap
|
||||
Drive drive;
|
||||
|
||||
//may be null if first initialization failed
|
||||
HashMap<String /*fileId*/, FileSystemEntryData> mFolderCache;
|
||||
|
||||
//may be null if first initialization failed
|
||||
protected String mRootFolderId;
|
||||
};
|
||||
@ -89,7 +87,7 @@ public class GoogleDriveFileStorage extends JavaFileStorageBase {
|
||||
public void setPath(String path) throws
|
||||
InvalidPathException, IOException {
|
||||
setPathWithoutVerify(path);
|
||||
verifyWithRetry();
|
||||
verify();
|
||||
}
|
||||
|
||||
public void setPathWithoutVerify(String path) throws UnsupportedEncodingException, InvalidPathException
|
||||
@ -109,24 +107,14 @@ public class GoogleDriveFileStorage extends JavaFileStorageBase {
|
||||
mAccountLocalPath = mAccountLocalPath + "/";
|
||||
mAccountLocalPath += encode(fileToAppend.getTitle())+NAME_ID_SEP+fileToAppend.getId();
|
||||
}
|
||||
|
||||
private void verifyWithRetry() throws IOException,
|
||||
FileNotFoundException {
|
||||
try
|
||||
{
|
||||
verify();
|
||||
}
|
||||
catch (FileNotFoundException e)
|
||||
{
|
||||
//the folders cache might be out of date -> rebuild and try again:
|
||||
AccountData accountData = mAccountData.get(mAccount);
|
||||
accountData.mFolderCache = buildFoldersCache(mAccount);
|
||||
|
||||
verify();
|
||||
}
|
||||
}
|
||||
|
||||
//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(""))
|
||||
@ -143,38 +131,28 @@ public class GoogleDriveFileStorage extends JavaFileStorageBase {
|
||||
//if initialization failed, try to repeat:
|
||||
finishInitialization(accountData, mAccount);
|
||||
|
||||
String parentId = accountData.mRootFolderId;
|
||||
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);
|
||||
|
||||
for (int i=0;i<parts.length;i++)
|
||||
{
|
||||
String part = parts[i];
|
||||
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);
|
||||
FileSystemEntryData thisFolder = accountData.mFolderCache.get(id);
|
||||
if (thisFolder == null)
|
||||
{
|
||||
if (i== parts.length-1)
|
||||
{
|
||||
//not all files are cached
|
||||
thisFolder = tryAddFileToCache(this);
|
||||
}
|
||||
//check if it's still null
|
||||
if (thisFolder == null)
|
||||
throw new FileNotFoundException("couldn't find id " + id + " being part of "+ mAccountLocalPath+" in GDrive account " + mAccount);
|
||||
}
|
||||
if (thisFolder.parentIds.contains(parentId) == false)
|
||||
throw new FileNotFoundException("couldn't find parent id " + parentId + " as parent of "+thisFolder.displayName +" in "+ mAccountLocalPath+" in GDrive account " + mAccount);
|
||||
if (thisFolder.displayName.equals(name) == false)
|
||||
throw new FileNotFoundException("Name of "+id+" changed from "+name+" to "+thisFolder.displayName +" in "+ mAccountLocalPath+" in GDrive account " + mAccount);
|
||||
|
||||
parentId = id;
|
||||
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 {
|
||||
@ -204,25 +182,22 @@ public class GoogleDriveFileStorage extends JavaFileStorageBase {
|
||||
|
||||
String[] parts = mAccountLocalPath.split("/");
|
||||
|
||||
for (int i=0;i<parts.length;i++)
|
||||
String part = parts[parts.length-1];
|
||||
logDebug("parsing part " + part);
|
||||
int indexOfSeparator = part.lastIndexOf(NAME_ID_SEP);
|
||||
if (indexOfSeparator < 0)
|
||||
{
|
||||
String part = parts[i];
|
||||
logDebug("parsing part " + part);
|
||||
int indexOfSeparator = part.lastIndexOf(NAME_ID_SEP);
|
||||
if (indexOfSeparator < 0)
|
||||
{
|
||||
//seems invalid, but we're very generous here
|
||||
displayName += "/"+part;
|
||||
continue;
|
||||
}
|
||||
String name = part.substring(0, indexOfSeparator);
|
||||
try {
|
||||
name = decode(name);
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
//ignore
|
||||
}
|
||||
displayName += "/"+name;
|
||||
//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;
|
||||
}
|
||||
|
||||
@ -290,34 +265,6 @@ public class GoogleDriveFileStorage extends JavaFileStorageBase {
|
||||
return currentVersion.equals(previousFileVersion) == false;
|
||||
}
|
||||
|
||||
public FileSystemEntryData tryAddFileToCache(GDrivePath path) {
|
||||
FileSystemEntryData thisFile = new FileSystemEntryData();
|
||||
|
||||
File fl;
|
||||
try {
|
||||
fl = getDriveService(path.getAccount()).files().get(path.getGDriveId()).execute();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
|
||||
thisFile.id = fl.getId();
|
||||
thisFile.displayName = fl.getTitle();
|
||||
|
||||
for (ParentReference parent: fl.getParents())
|
||||
{
|
||||
thisFile.parentIds.add(parent.getId());
|
||||
}
|
||||
mAccountData.get(path.getAccount()).mFolderCache.put(thisFile.id, thisFile);
|
||||
/*try {
|
||||
Log.d(TAG, "Added "+path.getFullPath()+" to cache");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
e.printStackTrace();
|
||||
}*/
|
||||
return thisFile;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getCurrentFileVersionFast(String path) {
|
||||
|
||||
@ -425,13 +372,6 @@ public class GoogleDriveFileStorage extends JavaFileStorageBase {
|
||||
|
||||
logDebug("created folder "+newDirName+" in "+parentPath+". id: "+file.getId());
|
||||
|
||||
//add to cache to avoid network traffic if this folder is accessed (which is likely to happen soon)
|
||||
FileSystemEntryData newCacheEntry = new FileSystemEntryData();
|
||||
newCacheEntry.displayName = newDirName;
|
||||
newCacheEntry.id = file.getId();
|
||||
newCacheEntry.parentIds.add(parentGdrivePath.getGDriveId());
|
||||
mAccountData.get(parentGdrivePath.getAccount()).mFolderCache.put(file.getId(), newCacheEntry);
|
||||
|
||||
return new GDrivePath(parentPath, file).getFullPath();
|
||||
}
|
||||
catch (Exception e)
|
||||
@ -575,7 +515,7 @@ public class GoogleDriveFileStorage extends JavaFileStorageBase {
|
||||
try
|
||||
{
|
||||
driveService.files().delete(gdrivePath.getGDriveId()).execute();
|
||||
mAccountData.get(gdrivePath.getAccount()).mFolderCache.remove(gdrivePath.getGDriveId());
|
||||
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@ -584,9 +524,9 @@ public class GoogleDriveFileStorage extends JavaFileStorageBase {
|
||||
}
|
||||
|
||||
|
||||
private Drive createDriveService(String accountName, Activity activity) {
|
||||
private Drive createDriveService(String accountName, Context appContext) {
|
||||
logDebug("createDriveService "+accountName);
|
||||
GoogleAccountCredential credential = createCredential(activity);
|
||||
GoogleAccountCredential credential = createCredential(appContext);
|
||||
credential.setSelectedAccountName(accountName);
|
||||
|
||||
return new Drive.Builder(AndroidHttp.newCompatibleTransport(), new GsonFactory(), credential)
|
||||
@ -658,6 +598,7 @@ public class GoogleDriveFileStorage extends JavaFileStorageBase {
|
||||
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;
|
||||
@ -685,18 +626,7 @@ public class GoogleDriveFileStorage extends JavaFileStorageBase {
|
||||
try {
|
||||
|
||||
|
||||
if (!mAccountData.containsKey(accountName))
|
||||
{
|
||||
AccountData newAccountData = new AccountData();
|
||||
newAccountData.drive = createDriveService(accountName, activity);
|
||||
mAccountData.put(accountName, newAccountData);
|
||||
logDebug("Added account data for " + 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(newAccountData, accountName);
|
||||
}
|
||||
initializeAccount(appContext, accountName);
|
||||
|
||||
if (setupAct.getProcessName().equals(PROCESS_NAME_SELECTFILE))
|
||||
setupAct.getState().putString(EXTRA_PATH, getRootPathForAccount(accountName));
|
||||
@ -711,6 +641,8 @@ public class GoogleDriveFileStorage extends JavaFileStorageBase {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(AsyncTaskResult<String> result) {
|
||||
Exception error = result.getError();
|
||||
@ -747,14 +679,26 @@ public class GoogleDriveFileStorage extends JavaFileStorageBase {
|
||||
|
||||
}
|
||||
|
||||
private void initializeAccount(final Context appContext,
|
||||
final String accountName) throws IOException {
|
||||
if (!mAccountData.containsKey(accountName))
|
||||
{
|
||||
AccountData newAccountData = new AccountData();
|
||||
newAccountData.drive = createDriveService(accountName, appContext);
|
||||
mAccountData.put(accountName, newAccountData);
|
||||
logDebug("Added account data for " + 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(newAccountData, accountName);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void finishInitialization(AccountData newAccountData, String accountName) throws IOException
|
||||
{
|
||||
if (newAccountData.mFolderCache == null)
|
||||
{
|
||||
newAccountData.mFolderCache = buildFoldersCache(accountName);
|
||||
}
|
||||
|
||||
if (TextUtils.isEmpty(newAccountData.mRootFolderId))
|
||||
{
|
||||
About about = newAccountData.drive.about().get().execute();
|
||||
@ -762,32 +706,6 @@ public class GoogleDriveFileStorage extends JavaFileStorageBase {
|
||||
}
|
||||
}
|
||||
|
||||
private HashMap<String,FileSystemEntryData> buildFoldersCache(String accountName) throws IOException {
|
||||
|
||||
HashMap<String, FileSystemEntryData> folderCache = new HashMap<String, GoogleDriveFileStorage.FileSystemEntryData>();
|
||||
logDebug("buildFoldersCache");
|
||||
FileList folders=getDriveService(accountName).files().list().setQ("mimeType='"+FOLDER_MIME_TYPE+"' and trashed=false")
|
||||
.setFields("items(id,title,parents),nextPageToken")
|
||||
.execute();
|
||||
for(File fl: folders.getItems()){
|
||||
logDebug("buildFoldersCache: " + fl.getTitle());
|
||||
FileSystemEntryData thisFolder = new FileSystemEntryData();
|
||||
thisFolder.id = fl.getId();
|
||||
thisFolder.displayName = fl.getTitle();
|
||||
|
||||
for (ParentReference parent: fl.getParents())
|
||||
{
|
||||
thisFolder.parentIds.add(parent.getId());
|
||||
}
|
||||
folderCache.put(thisFolder.id, thisFolder);
|
||||
}
|
||||
|
||||
logDebug("that's it!");
|
||||
return folderCache;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void startSelectFile(JavaFileStorage.FileStorageSetupInitiatorActivity activity, boolean isForSave,
|
||||
int requestCode) {
|
||||
@ -800,6 +718,27 @@ public class GoogleDriveFileStorage extends JavaFileStorageBase {
|
||||
((JavaFileStorage.FileStorageSetupInitiatorActivity)(activity)).startFileUsageProcess(path, requestCode, alwaysReturnSuccess);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
public void prepareFileUsage(Context appContext, String path) throws UserInteractionRequiredException, Throwable
|
||||
{
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProtocolId() {
|
||||
@ -820,7 +759,7 @@ public class GoogleDriveFileStorage extends JavaFileStorageBase {
|
||||
|
||||
if (PROCESS_NAME_SELECTFILE.equals(setupAct.getProcessName()))
|
||||
{
|
||||
GoogleAccountCredential credential = createCredential(activity);
|
||||
GoogleAccountCredential credential = createCredential(activity.getApplicationContext());
|
||||
|
||||
logDebug("starting REQUEST_ACCOUNT_PICKER");
|
||||
activity.startActivityForResult(credential.newChooseAccountIntent(), REQUEST_ACCOUNT_PICKER);
|
||||
@ -832,10 +771,10 @@ public class GoogleDriveFileStorage extends JavaFileStorageBase {
|
||||
}
|
||||
}
|
||||
|
||||
private GoogleAccountCredential createCredential(Activity activity) {
|
||||
private GoogleAccountCredential createCredential(Context appContext) {
|
||||
List<String> scopes = new ArrayList<String>();
|
||||
scopes.add(DriveScopes.DRIVE);
|
||||
GoogleAccountCredential credential = GoogleAccountCredential.usingOAuth2(activity.getApplicationContext(), scopes);
|
||||
GoogleAccountCredential credential = GoogleAccountCredential.usingOAuth2(appContext, scopes);
|
||||
return credential;
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,7 @@ import java.io.InputStream;
|
||||
import java.util.List;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
|
||||
@ -115,6 +116,11 @@ public class FileEntry {
|
||||
|
||||
public void startSelectFile(FileStorageSetupInitiatorActivity activity, boolean isForSave, int requestCode);
|
||||
|
||||
//prepare the file usage. if not possible, throw an exception. Must throw UserInteractionRequiredException if the
|
||||
// problem can be resolved by the user. Caller should then retry with prepareFileUsage(FileStorageSetupInitiatorActivity activity, String path, int requestCode, boolean alwaysReturnSuccess)
|
||||
public void prepareFileUsage(Context appContext, String path) throws UserInteractionRequiredException, Throwable;
|
||||
|
||||
//prepare the file usage. if necessary, use the activity to interact with the user, e.g. to grant access.
|
||||
public void prepareFileUsage(FileStorageSetupInitiatorActivity activity, String path, int requestCode, boolean alwaysReturnSuccess);
|
||||
|
||||
public String getProtocolId();
|
||||
|
@ -20,6 +20,7 @@ import com.jcraft.jsch.SftpATTRS;
|
||||
import com.jcraft.jsch.SftpException;
|
||||
import com.jcraft.jsch.UserInfo;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
|
||||
@ -424,4 +425,10 @@ public class SftpStorage extends JavaFileStorageBase {
|
||||
return getProtocolPrefix()+encode(username)+":"+encode(password)+"@"+host+localPath;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void prepareFileUsage(Context appContext, String path) {
|
||||
//nothing to do
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import keepass2android.javafilestorage.skydrive.PrepareFileUsageListener;
|
||||
import keepass2android.javafilestorage.skydrive.SkyDriveException;
|
||||
import keepass2android.javafilestorage.skydrive.SkyDriveFile;
|
||||
import keepass2android.javafilestorage.skydrive.SkyDriveFolder;
|
||||
@ -456,9 +457,41 @@ public class SkyDriveFileStorage extends JavaFileStorageBase {
|
||||
@Override
|
||||
public void prepareFileUsage(FileStorageSetupInitiatorActivity activity,
|
||||
String path, int requestCode, boolean alwaysReturnSuccess) {
|
||||
|
||||
//tell the activity which requests the file usage that it must launch the FileStorageSetupActivity
|
||||
// which will then go through the onCreate/onStart/onResume process which is used by our FileStorage
|
||||
((JavaFileStorage.FileStorageSetupInitiatorActivity) (activity))
|
||||
.startFileUsageProcess(path, requestCode, alwaysReturnSuccess);
|
||||
|
||||
}
|
||||
@Override
|
||||
public void prepareFileUsage(Context appContext, String path) throws Exception
|
||||
{
|
||||
PrepareFileUsageListener listener = new PrepareFileUsageListener();
|
||||
mAuthClient.initialize(Arrays.asList(SCOPES), listener);
|
||||
|
||||
if (listener.exception != null)
|
||||
throw listener.exception;
|
||||
|
||||
if (listener.status == LiveStatus.CONNECTED) {
|
||||
if (mFolderCache.isEmpty())
|
||||
{
|
||||
initializeFoldersCache();
|
||||
}
|
||||
|
||||
} else {
|
||||
if (listener.status == LiveStatus.NOT_CONNECTED)
|
||||
logDebug( "not connected");
|
||||
else if (listener.status == LiveStatus.UNKNOWN)
|
||||
logDebug( "unknown");
|
||||
else
|
||||
logDebug( "unexpected status " + listener.status);
|
||||
|
||||
throw new UserInteractionRequiredException();
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -0,0 +1,12 @@
|
||||
package keepass2android.javafilestorage;
|
||||
|
||||
public class UserInteractionRequiredException extends Exception {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package keepass2android.javafilestorage.skydrive;
|
||||
|
||||
import com.microsoft.live.LiveAuthException;
|
||||
import com.microsoft.live.LiveAuthListener;
|
||||
import com.microsoft.live.LiveConnectSession;
|
||||
import com.microsoft.live.LiveStatus;
|
||||
|
||||
public class PrepareFileUsageListener implements LiveAuthListener {
|
||||
|
||||
public Exception exception;
|
||||
public LiveStatus status;
|
||||
|
||||
@Override
|
||||
public void onAuthError(LiveAuthException _exception,
|
||||
Object userState) {
|
||||
exception = _exception;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAuthComplete(LiveStatus _status,
|
||||
LiveConnectSession session, Object userState)
|
||||
{
|
||||
status = _status;
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user