mirror of
https://github.com/moparisthebest/keepass2android
synced 2024-12-24 07:48:49 -05:00
Implemented SkyDriveFileStorage including transactional write
This commit is contained in:
parent
17bfc0c975
commit
684312b412
@ -13,4 +13,5 @@ proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.
|
|||||||
# Project target.
|
# Project target.
|
||||||
target=android-17
|
target=android-17
|
||||||
android.library=true
|
android.library=true
|
||||||
android.library.reference.1=../../../../../../../AppData/Local/Android/android-sdk/extras/google/google_play_services/libproject/google-play-services_lib
|
android.library.reference.1=..\\..\\..\\..\\..\\..\\..\\AppData\\Local\\Android\\android-sdk\\extras\\google\\google_play_services\\libproject\\google-play-services_lib
|
||||||
|
android.library.reference.2=../../../../LiveSDK-for-Android/src
|
||||||
|
@ -1,36 +1,45 @@
|
|||||||
package keepass2android.javafilestorage;
|
package keepass2android.javafilestorage;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
import keepass2android.javafilestorage.JavaFileStorageBase.InvalidPathException;
|
import keepass2android.javafilestorage.JavaFileStorageBase.InvalidPathException;
|
||||||
|
import keepass2android.javafilestorage.skydrive.SkyDriveException;
|
||||||
|
import keepass2android.javafilestorage.skydrive.SkyDriveFile;
|
||||||
|
import keepass2android.javafilestorage.skydrive.SkyDriveFolder;
|
||||||
|
import keepass2android.javafilestorage.skydrive.SkyDriveObject;
|
||||||
|
|
||||||
import org.json.JSONArray;
|
import org.json.JSONArray;
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
|
||||||
import com.google.api.services.drive.model.File;
|
|
||||||
import com.microsoft.live.LiveAuthClient;
|
import com.microsoft.live.LiveAuthClient;
|
||||||
import com.microsoft.live.LiveAuthException;
|
import com.microsoft.live.LiveAuthException;
|
||||||
import com.microsoft.live.LiveAuthListener;
|
import com.microsoft.live.LiveAuthListener;
|
||||||
import com.microsoft.live.LiveConnectClient;
|
import com.microsoft.live.LiveConnectClient;
|
||||||
import com.microsoft.live.LiveConnectSession;
|
import com.microsoft.live.LiveConnectSession;
|
||||||
|
import com.microsoft.live.LiveDownloadOperation;
|
||||||
import com.microsoft.live.LiveOperation;
|
import com.microsoft.live.LiveOperation;
|
||||||
import com.microsoft.live.LiveOperationException;
|
import com.microsoft.live.LiveOperationException;
|
||||||
import com.microsoft.live.LiveStatus;
|
import com.microsoft.live.LiveStatus;
|
||||||
|
import com.microsoft.live.OverwriteOption;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.os.AsyncTask;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
|
||||||
public class SkyDriveFileStorage extends JavaFileStorageBase {
|
public class SkyDriveFileStorage extends JavaFileStorageBase {
|
||||||
|
|
||||||
private LiveAuthClient mAuthClient;
|
private LiveAuthClient mAuthClient;
|
||||||
@ -43,10 +52,10 @@ public class SkyDriveFileStorage extends JavaFileStorageBase {
|
|||||||
|
|
||||||
private HashMap<String /* id */, SkyDriveObject> mFolderCache = new HashMap<String, SkyDriveObject>();
|
private HashMap<String /* id */, SkyDriveObject> mFolderCache = new HashMap<String, SkyDriveObject>();
|
||||||
|
|
||||||
public static final String[] SCOPES = {
|
public static final String[] SCOPES = { "wl.signin", "wl.skydrive_update", };
|
||||||
"wl.signin",
|
|
||||||
"wl.skydrive_update",
|
// see http://stackoverflow.com/questions/17997688/howto-to-parse-skydrive-api-date-in-java
|
||||||
};
|
SimpleDateFormat SKYDRIVE_DATEFORMATTER = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.ENGLISH);
|
||||||
|
|
||||||
public final class JsonKeys {
|
public final class JsonKeys {
|
||||||
public static final String CODE = "code";
|
public static final String CODE = "code";
|
||||||
@ -81,60 +90,58 @@ public class SkyDriveFileStorage extends JavaFileStorageBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class SkyDrivePath {
|
||||||
|
|
||||||
|
|
||||||
class SkyDrivePath
|
|
||||||
{
|
|
||||||
String mPath;
|
String mPath;
|
||||||
|
|
||||||
public SkyDrivePath()
|
public SkyDrivePath() {
|
||||||
{
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public SkyDrivePath(String path) throws UnsupportedEncodingException, FileNotFoundException, InvalidPathException, LiveOperationException, SkyDriveException
|
public SkyDrivePath(String path) throws UnsupportedEncodingException,
|
||||||
{
|
FileNotFoundException, InvalidPathException,
|
||||||
|
LiveOperationException, SkyDriveException {
|
||||||
setPath(path);
|
setPath(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
public SkyDrivePath(String parentPath, JSONObject fileToAppend) throws UnsupportedEncodingException, FileNotFoundException, IOException, InvalidPathException, JSONException, LiveOperationException, SkyDriveException
|
public SkyDrivePath(String parentPath, JSONObject fileToAppend)
|
||||||
{
|
throws UnsupportedEncodingException, FileNotFoundException,
|
||||||
|
IOException, InvalidPathException, JSONException,
|
||||||
|
LiveOperationException, SkyDriveException {
|
||||||
setPath(parentPath);
|
setPath(parentPath);
|
||||||
|
|
||||||
if ((!mPath.endsWith("/")) && (!mPath.equals("")))
|
if ((!mPath.endsWith("/")) && (!mPath.equals("")))
|
||||||
mPath = mPath + "/";
|
mPath = mPath + "/";
|
||||||
mPath += encode(fileToAppend.getString("name"))+NAME_ID_SEP+encode(fileToAppend.getString("id"));
|
mPath += encode(fileToAppend.getString("name")) + NAME_ID_SEP
|
||||||
|
+ encode(fileToAppend.getString("id"));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPath(String path) throws UnsupportedEncodingException, InvalidPathException, FileNotFoundException, LiveOperationException, SkyDriveException {
|
public void setPath(String path) throws UnsupportedEncodingException,
|
||||||
|
InvalidPathException, FileNotFoundException,
|
||||||
|
LiveOperationException, SkyDriveException {
|
||||||
setPathWithoutVerify(path);
|
setPathWithoutVerify(path);
|
||||||
verifyWithRetry();
|
verifyWithRetry();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void verifyWithRetry() throws FileNotFoundException,
|
||||||
private void verifyWithRetry() throws FileNotFoundException, LiveOperationException, SkyDriveException, UnsupportedEncodingException {
|
LiveOperationException, SkyDriveException,
|
||||||
try
|
UnsupportedEncodingException {
|
||||||
{
|
try {
|
||||||
verify();
|
verify();
|
||||||
}
|
} catch (FileNotFoundException e) {
|
||||||
catch (FileNotFoundException e)
|
|
||||||
{
|
|
||||||
initializeFoldersCache();
|
initializeFoldersCache();
|
||||||
verify();
|
verify();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setPathWithoutVerify(String path)
|
||||||
public void setPathWithoutVerify(String path) throws UnsupportedEncodingException, InvalidPathException
|
throws UnsupportedEncodingException, InvalidPathException {
|
||||||
{
|
|
||||||
mPath = path.substring(getProtocolPrefix().length());
|
mPath = path.substring(getProtocolPrefix().length());
|
||||||
// Log.d(TAG, " mAccount=" + mAccount);
|
// Log.d(TAG, " mAccount=" + mAccount);
|
||||||
// Log.d(TAG, " mAccountLocalPath=" + mAccountLocalPath);
|
// Log.d(TAG, " mAccountLocalPath=" + mAccountLocalPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// make sure the path exists
|
// make sure the path exists
|
||||||
private void verify() throws FileNotFoundException, UnsupportedEncodingException {
|
private void verify() throws FileNotFoundException,
|
||||||
|
UnsupportedEncodingException {
|
||||||
|
|
||||||
if (mPath.equals(""))
|
if (mPath.equals(""))
|
||||||
return;
|
return;
|
||||||
@ -143,38 +150,43 @@ public class SkyDriveFileStorage extends JavaFileStorageBase {
|
|||||||
|
|
||||||
String parentId = mRootFolderId;
|
String parentId = mRootFolderId;
|
||||||
|
|
||||||
for (int i=0;i<parts.length;i++)
|
for (int i = 0; i < parts.length; i++) {
|
||||||
{
|
|
||||||
String part = parts[i];
|
String part = parts[i];
|
||||||
// Log.d(TAG, "parsing part " + part);
|
// Log.d(TAG, "parsing part " + part);
|
||||||
int indexOfSeparator = part.lastIndexOf(NAME_ID_SEP);
|
int indexOfSeparator = part.lastIndexOf(NAME_ID_SEP);
|
||||||
if (indexOfSeparator < 0)
|
if (indexOfSeparator < 0)
|
||||||
throw new FileNotFoundException("invalid path " + mPath);
|
throw new FileNotFoundException("invalid path " + mPath);
|
||||||
String id = decode(part.substring(indexOfSeparator+NAME_ID_SEP.length()));
|
String id = decode(part.substring(indexOfSeparator
|
||||||
|
+ NAME_ID_SEP.length()));
|
||||||
String name = decode(part.substring(0, indexOfSeparator));
|
String name = decode(part.substring(0, indexOfSeparator));
|
||||||
// Log.d(TAG, " name=" + name);
|
// Log.d(TAG, " name=" + name);
|
||||||
SkyDriveObject thisFolder = mFolderCache.get(id);
|
SkyDriveObject thisFolder = mFolderCache.get(id);
|
||||||
if (thisFolder == null)
|
if (thisFolder == null) {
|
||||||
{
|
|
||||||
thisFolder = tryAddFileToCache(this);
|
thisFolder = tryAddFileToCache(this);
|
||||||
|
|
||||||
// check if it's still null
|
// check if it's still null
|
||||||
if (thisFolder == null)
|
if (thisFolder == null)
|
||||||
throw new FileNotFoundException("couldn't find id " + id + " being part of "+ mPath+" in SkyDrive ");
|
throw new FileNotFoundException("couldn't find id "
|
||||||
|
+ id + " being part of " + mPath
|
||||||
|
+ " in SkyDrive ");
|
||||||
}
|
}
|
||||||
if (thisFolder.getParentId().equals(parentId) == false)
|
if (thisFolder.getParentId().equals(parentId) == false)
|
||||||
throw new FileNotFoundException("couldn't find parent id " + parentId + " as parent of "+thisFolder.getName() +" in "+ mPath+" in SkyDrive");
|
throw new FileNotFoundException("couldn't find parent id "
|
||||||
|
+ parentId + " as parent of "
|
||||||
|
+ thisFolder.getName() + " in " + mPath
|
||||||
|
+ " in SkyDrive");
|
||||||
if (thisFolder.getName().equals(name) == false)
|
if (thisFolder.getName().equals(name) == false)
|
||||||
throw new FileNotFoundException("Name of "+id+" changed from "+name+" to "+thisFolder.getName() +" in "+ mPath+" in SkyDrive " );
|
throw new FileNotFoundException("Name of " + id
|
||||||
|
+ " changed from " + name + " to "
|
||||||
|
+ thisFolder.getName() + " in " + mPath
|
||||||
|
+ " in SkyDrive ");
|
||||||
|
|
||||||
parentId = id;
|
parentId = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getDisplayName() {
|
||||||
public String getDisplayName()
|
|
||||||
{
|
|
||||||
// skydrive://
|
// skydrive://
|
||||||
String displayName = getProtocolPrefix();
|
String displayName = getProtocolPrefix();
|
||||||
|
|
||||||
@ -183,13 +195,11 @@ public class SkyDriveFileStorage extends JavaFileStorageBase {
|
|||||||
|
|
||||||
String[] parts = mPath.split("/");
|
String[] parts = mPath.split("/");
|
||||||
|
|
||||||
for (int i=0;i<parts.length;i++)
|
for (int i = 0; i < parts.length; i++) {
|
||||||
{
|
|
||||||
String part = parts[i];
|
String part = parts[i];
|
||||||
// Log.d(TAG, "parsing part " + part);
|
// Log.d(TAG, "parsing part " + part);
|
||||||
int indexOfSeparator = part.lastIndexOf(NAME_ID_SEP);
|
int indexOfSeparator = part.lastIndexOf(NAME_ID_SEP);
|
||||||
if (indexOfSeparator < 0)
|
if (indexOfSeparator < 0) {
|
||||||
{
|
|
||||||
// seems invalid, but we're very generous here
|
// seems invalid, but we're very generous here
|
||||||
displayName += "/" + part;
|
displayName += "/" + part;
|
||||||
continue;
|
continue;
|
||||||
@ -205,18 +215,21 @@ public class SkyDriveFileStorage extends JavaFileStorageBase {
|
|||||||
return displayName;
|
return displayName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getSkyDriveId() throws InvalidPathException,
|
||||||
public String getSkyDriveId() throws InvalidPathException, UnsupportedEncodingException {
|
UnsupportedEncodingException {
|
||||||
String pathWithoutTrailingSlash = mPath;
|
String pathWithoutTrailingSlash = mPath;
|
||||||
if (pathWithoutTrailingSlash.endsWith("/"))
|
if (pathWithoutTrailingSlash.endsWith("/"))
|
||||||
pathWithoutTrailingSlash = pathWithoutTrailingSlash.substring(0,pathWithoutTrailingSlash.length()-1);
|
pathWithoutTrailingSlash = pathWithoutTrailingSlash.substring(
|
||||||
if (pathWithoutTrailingSlash.equals(""))
|
0, pathWithoutTrailingSlash.length() - 1);
|
||||||
{
|
if (pathWithoutTrailingSlash.equals("")) {
|
||||||
return mRootFolderId;
|
return mRootFolderId;
|
||||||
}
|
}
|
||||||
String lastPart = pathWithoutTrailingSlash.substring(pathWithoutTrailingSlash.lastIndexOf(NAME_ID_SEP)+NAME_ID_SEP.length());
|
String lastPart = pathWithoutTrailingSlash
|
||||||
|
.substring(pathWithoutTrailingSlash
|
||||||
|
.lastIndexOf(NAME_ID_SEP) + NAME_ID_SEP.length());
|
||||||
if (lastPart.contains("/"))
|
if (lastPart.contains("/"))
|
||||||
throw new InvalidPathException("error extracting SkyDriveId from "+mPath);
|
throw new InvalidPathException(
|
||||||
|
"error extracting SkyDriveId from " + mPath);
|
||||||
return decode(lastPart);
|
return decode(lastPart);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -224,58 +237,126 @@ public class SkyDriveFileStorage extends JavaFileStorageBase {
|
|||||||
return getProtocolPrefix() + mPath;
|
return getProtocolPrefix() + mPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public SkyDrivePath getParentPath() throws UnsupportedEncodingException, FileNotFoundException, InvalidPathException, LiveOperationException, SkyDriveException {
|
||||||
|
String pathWithoutTrailingSlash = mPath;
|
||||||
|
if (pathWithoutTrailingSlash.endsWith("/"))
|
||||||
|
pathWithoutTrailingSlash = pathWithoutTrailingSlash.substring(
|
||||||
|
0, pathWithoutTrailingSlash.length() - 1);
|
||||||
|
if (pathWithoutTrailingSlash.equals(""))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
int indexOfLastSlash = pathWithoutTrailingSlash.lastIndexOf("/");
|
||||||
|
if (indexOfLastSlash == -1)
|
||||||
|
{
|
||||||
|
return new SkyDrivePath(getProtocolPrefix());
|
||||||
|
}
|
||||||
|
String parentPath = pathWithoutTrailingSlash.substring(0, indexOfLastSlash);
|
||||||
|
return new SkyDrivePath(getProtocolPrefix()+parentPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFilename() throws InvalidPathException {
|
||||||
|
String pathWithoutTrailingSlash = mPath;
|
||||||
|
if (pathWithoutTrailingSlash.endsWith("/"))
|
||||||
|
pathWithoutTrailingSlash = pathWithoutTrailingSlash.substring(
|
||||||
|
0, pathWithoutTrailingSlash.length() - 1);
|
||||||
|
|
||||||
|
String[] parts = mPath.split("/");
|
||||||
|
|
||||||
|
String lastPart = parts[parts.length-1];
|
||||||
|
int indexOfSeparator = lastPart.lastIndexOf(NAME_ID_SEP);
|
||||||
|
if (indexOfSeparator < 0) {
|
||||||
|
throw new InvalidPathException("cannot extract filename from " + mPath);
|
||||||
|
}
|
||||||
|
String name = lastPart.substring(0, indexOfSeparator);
|
||||||
|
try {
|
||||||
|
name = decode(name);
|
||||||
|
} catch (UnsupportedEncodingException e) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
return name;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
public SkyDriveFileStorage(String clientId, Context appContext) {
|
||||||
public SkyDriveFileStorage(String clientId, Context appContext)
|
|
||||||
{
|
|
||||||
mAuthClient = new LiveAuthClient(appContext, clientId);
|
mAuthClient = new LiveAuthClient(appContext, clientId);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void login(final FileStorageSetupActivity activity)
|
void login(final FileStorageSetupActivity activity) {
|
||||||
{
|
mAuthClient.login((Activity) activity, Arrays.asList(SCOPES),
|
||||||
mAuthClient.login((Activity)activity,
|
|
||||||
Arrays.asList(SCOPES),
|
|
||||||
new LiveAuthListener() {
|
new LiveAuthListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onAuthComplete(LiveStatus status,
|
public void onAuthComplete(LiveStatus status,
|
||||||
LiveConnectSession session,
|
LiveConnectSession session, Object userState) {
|
||||||
Object userState) {
|
|
||||||
if (status == LiveStatus.CONNECTED) {
|
if (status == LiveStatus.CONNECTED) {
|
||||||
try
|
initialize(activity, session);
|
||||||
{
|
|
||||||
initializeSession(session);
|
|
||||||
finishActivityWithSuccess(activity);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
finishWithError((Activity)activity, e);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
finishWithError((Activity)activity, new Exception("Error connecting to SkdDrive. Status is "+status));
|
finishWithError((Activity) activity, new Exception(
|
||||||
|
"Error connecting to SkdDrive. Status is "
|
||||||
|
+ status));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onAuthError(LiveAuthException exception, Object userState) {
|
public void onAuthError(LiveAuthException exception,
|
||||||
|
Object userState) {
|
||||||
finishWithError((Activity) activity, exception);
|
finishWithError((Activity) activity, exception);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initializeSession(LiveConnectSession session) throws LiveOperationException, SkyDriveException {
|
private void initialize(final FileStorageSetupActivity setupAct,
|
||||||
|
LiveConnectSession session) {
|
||||||
|
|
||||||
mSession = session;
|
mSession = session;
|
||||||
mConnectClient = new LiveConnectClient(session);
|
mConnectClient = new LiveConnectClient(session);
|
||||||
|
|
||||||
|
final Activity activity = (Activity)setupAct;
|
||||||
|
|
||||||
|
AsyncTask<Object, Void, AsyncTaskResult<String> > task = new AsyncTask<Object, Void, AsyncTaskResult<String>>()
|
||||||
|
{
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected AsyncTaskResult<String> doInBackground(Object... arg0) {
|
||||||
|
try {
|
||||||
initializeFoldersCache();
|
initializeFoldersCache();
|
||||||
|
if (setupAct.getProcessName().equals(PROCESS_NAME_SELECTFILE))
|
||||||
|
setupAct.getState().putString(EXTRA_PATH, getProtocolPrefix());
|
||||||
|
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 ) {
|
||||||
|
finishWithError(activity, error);
|
||||||
|
} else if ( isCancelled()) {
|
||||||
|
activity.setResult(Activity.RESULT_CANCELED);
|
||||||
|
activity.finish();
|
||||||
|
} else {
|
||||||
|
//all right!
|
||||||
|
finishActivityWithSuccess(setupAct);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
task.execute(new Object[]{});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void initializeFoldersCache() throws LiveOperationException, SkyDriveException {
|
|
||||||
|
private void initializeFoldersCache() throws LiveOperationException,
|
||||||
|
SkyDriveException, FileNotFoundException {
|
||||||
|
|
||||||
|
//use alias for now (overwritten later):
|
||||||
mRootFolderId = "me/skydrive";
|
mRootFolderId = "me/skydrive";
|
||||||
|
|
||||||
LiveOperation operation = mConnectClient.get(mRootFolderId + "/files");
|
LiveOperation operation = mConnectClient.get(mRootFolderId + "/files");
|
||||||
@ -287,44 +368,64 @@ public class SkyDriveFileStorage extends JavaFileStorageBase {
|
|||||||
|
|
||||||
JSONArray data = result.optJSONArray(JsonKeys.DATA);
|
JSONArray data = result.optJSONArray(JsonKeys.DATA);
|
||||||
for (int i = 0; i < data.length(); i++) {
|
for (int i = 0; i < data.length(); i++) {
|
||||||
SkyDriveObject skyDriveObj = SkyDriveObject.create(data.optJSONObject(i));
|
SkyDriveObject skyDriveObj = SkyDriveObject.create(data
|
||||||
|
.optJSONObject(i));
|
||||||
if (skyDriveObj == null)
|
if (skyDriveObj == null)
|
||||||
continue; // ignored type
|
continue; // ignored type
|
||||||
|
Log.d(TAG, "adding "+skyDriveObj.getName()+" to cache with id " + skyDriveObj.getId()+" in "+skyDriveObj.getParentId());
|
||||||
mFolderCache.put(skyDriveObj.getId(), skyDriveObj);
|
mFolderCache.put(skyDriveObj.getId(), skyDriveObj);
|
||||||
|
|
||||||
|
mRootFolderId = skyDriveObj.getParentId();
|
||||||
|
}
|
||||||
|
|
||||||
|
//check if we received anything. If not: query the root folder directly
|
||||||
|
if (data.length() == 0)
|
||||||
|
{
|
||||||
|
operation = mConnectClient.get(mRootFolderId);
|
||||||
|
result = operation.getResult();
|
||||||
|
checkResult(result);
|
||||||
|
mRootFolderId = SkyDriveObject.create(result).getId();
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkResult(JSONObject result) throws SkyDriveException {
|
private void checkResult(JSONObject result) throws SkyDriveException, FileNotFoundException {
|
||||||
if (result.has(JsonKeys.ERROR)) {
|
if (result.has(JsonKeys.ERROR)) {
|
||||||
JSONObject error = result.optJSONObject(JsonKeys.ERROR);
|
JSONObject error = result.optJSONObject(JsonKeys.ERROR);
|
||||||
String message = error.optString(JsonKeys.MESSAGE);
|
String message = error.optString(JsonKeys.MESSAGE);
|
||||||
String code = error.optString(JsonKeys.CODE);
|
String code = error.optString(JsonKeys.CODE);
|
||||||
|
Log.d(TAG, "Code: "+code);
|
||||||
|
if ("resource_not_found".equals(code))
|
||||||
|
throw new FileNotFoundException(message);
|
||||||
|
else
|
||||||
throw new SkyDriveException(message, code);
|
throw new SkyDriveException(message, code);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private SkyDriveObject tryAddFileToCache(SkyDrivePath skyDrivePath) {
|
private SkyDriveObject tryAddFileToCache(SkyDrivePath skyDrivePath) {
|
||||||
try
|
try {
|
||||||
{
|
SkyDriveObject obj = getSkyDriveObject(skyDrivePath);
|
||||||
LiveOperation operation = mConnectClient.get(skyDrivePath.getSkyDriveId());
|
if (obj != null) {
|
||||||
JSONObject result = operation.getResult();
|
|
||||||
checkResult(result);
|
|
||||||
SkyDriveObject obj = SkyDriveObject.create(result);
|
|
||||||
if (obj != null)
|
|
||||||
{
|
|
||||||
mFolderCache.put(obj.getId(), obj);
|
mFolderCache.put(obj.getId(), obj);
|
||||||
}
|
}
|
||||||
return obj;
|
return obj;
|
||||||
}
|
} catch (Exception e) {
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private SkyDriveObject getSkyDriveObject(SkyDrivePath skyDrivePath)
|
||||||
|
throws LiveOperationException, InvalidPathException,
|
||||||
|
UnsupportedEncodingException, SkyDriveException, FileNotFoundException {
|
||||||
|
LiveOperation operation = mConnectClient.get(skyDrivePath
|
||||||
|
.getSkyDriveId());
|
||||||
|
JSONObject result = operation.getResult();
|
||||||
|
checkResult(result);
|
||||||
|
SkyDriveObject obj = SkyDriveObject.create(result);
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean requiresSetup(String path) {
|
public boolean requiresSetup(String path) {
|
||||||
// always go through the setup process:
|
// always go through the setup process:
|
||||||
@ -335,14 +436,17 @@ public class SkyDriveFileStorage extends JavaFileStorageBase {
|
|||||||
public void startSelectFile(FileStorageSetupInitiatorActivity activity,
|
public void startSelectFile(FileStorageSetupInitiatorActivity activity,
|
||||||
boolean isForSave, int requestCode) {
|
boolean isForSave, int requestCode) {
|
||||||
|
|
||||||
((JavaFileStorage.FileStorageSetupInitiatorActivity)(activity)).startSelectFileProcess(getProtocolId()+"://", isForSave, requestCode);
|
((JavaFileStorage.FileStorageSetupInitiatorActivity) (activity))
|
||||||
|
.startSelectFileProcess(getProtocolId() + "://", isForSave,
|
||||||
|
requestCode);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void prepareFileUsage(FileStorageSetupInitiatorActivity activity,
|
public void prepareFileUsage(FileStorageSetupInitiatorActivity activity,
|
||||||
String path, int requestCode) {
|
String path, int requestCode) {
|
||||||
((JavaFileStorage.FileStorageSetupInitiatorActivity)(activity)).startFileUsageProcess(path, requestCode);
|
((JavaFileStorage.FileStorageSetupInitiatorActivity) (activity))
|
||||||
|
.startFileUsageProcess(path, requestCode);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -356,60 +460,124 @@ public class SkyDriveFileStorage extends JavaFileStorageBase {
|
|||||||
|
|
||||||
return "";
|
return "";
|
||||||
/*
|
/*
|
||||||
SkyDrivePath skydrivePath = new SkyDrivePath();
|
* SkyDrivePath skydrivePath = new SkyDrivePath(); try {
|
||||||
try {
|
* skydrivePath.setPathWithoutVerify(path); } catch (Exception e) {
|
||||||
skydrivePath.setPathWithoutVerify(path);
|
* e.printStackTrace(); return path; } return
|
||||||
} catch (Exception e) {
|
* skydrivePath.getDisplayName();
|
||||||
e.printStackTrace();
|
*/
|
||||||
return path;
|
|
||||||
}
|
|
||||||
return skydrivePath.getDisplayName();*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean checkForFileChangeFast(String path,
|
public boolean checkForFileChangeFast(String path,
|
||||||
String previousFileVersion) throws Exception {
|
String previousFileVersion) throws Exception {
|
||||||
// TODO Auto-generated method stub
|
|
||||||
|
String currentVersion = getCurrentFileVersionFast(path);
|
||||||
|
if (currentVersion == null)
|
||||||
return false;
|
return false;
|
||||||
|
return currentVersion.equals(previousFileVersion) == false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getCurrentFileVersionFast(String path) {
|
public String getCurrentFileVersionFast(String path) {
|
||||||
// TODO Auto-generated method stub
|
try
|
||||||
|
{
|
||||||
|
SkyDrivePath drivePath = new SkyDrivePath(path);
|
||||||
|
SkyDriveObject obj = getSkyDriveObject(drivePath);
|
||||||
|
if (obj == null)
|
||||||
return null;
|
return null;
|
||||||
|
return obj.getUpdatedTime();
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Log.w(TAG,"Error getting file version:");
|
||||||
|
e.printStackTrace();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public InputStream openFileForRead(String path) throws Exception {
|
public InputStream openFileForRead(String path) throws Exception {
|
||||||
// TODO Auto-generated method stub
|
try
|
||||||
return null;
|
{
|
||||||
|
LiveDownloadOperation op = mConnectClient.download(new SkyDrivePath(path).getSkyDriveId()+"/content");
|
||||||
|
return op.getStream();
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
throw convertException(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void uploadFile(String path, byte[] data, boolean writeTransactional)
|
public void uploadFile(String path, byte[] data, boolean writeTransactional)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
// TODO Auto-generated method stub
|
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
SkyDrivePath driveTargetPath = new SkyDrivePath(path);
|
||||||
|
SkyDrivePath driveUploadPath = driveTargetPath;
|
||||||
|
SkyDrivePath driveTempPath = null;
|
||||||
|
ByteArrayInputStream bis = new ByteArrayInputStream(data);
|
||||||
|
|
||||||
|
//if writeTransactional, upload the file to a temp destination.
|
||||||
|
//this is a somewhat ugly way because it requires two uploads, but renaming/copying doesn't work
|
||||||
|
//nicely in SkyDrive, and SkyDrive doesn't provide file histories by itself, so we need to make sure
|
||||||
|
//no file gets corrupt if upload is canceled.
|
||||||
|
if (writeTransactional)
|
||||||
|
{
|
||||||
|
LiveOperation uploadOp = uploadFile(driveUploadPath.getParentPath(), driveUploadPath.getFilename()+".tmp", bis);
|
||||||
|
driveTempPath = new SkyDrivePath(driveUploadPath.getParentPath().getFullPath(), uploadOp.getResult());
|
||||||
|
//recreate ByteArrayInputStream for use in uploadFile below
|
||||||
|
bis = new ByteArrayInputStream(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
//upload the file
|
||||||
|
uploadFile(driveUploadPath.getParentPath(), driveUploadPath.getFilename(), bis);
|
||||||
|
|
||||||
|
if (writeTransactional)
|
||||||
|
{
|
||||||
|
//delete old file
|
||||||
|
mConnectClient.delete(driveTempPath.getSkyDriveId());
|
||||||
|
// don't check result. If delete fails -> not a big deal
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
throw convertException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private LiveOperation uploadFile(SkyDrivePath parentPath, String filename, ByteArrayInputStream bis)
|
||||||
|
throws LiveOperationException, InvalidPathException,
|
||||||
|
UnsupportedEncodingException, FileNotFoundException,
|
||||||
|
SkyDriveException {
|
||||||
|
LiveOperation op = mConnectClient.upload(parentPath.getSkyDriveId(), filename, bis, OverwriteOption.Overwrite);
|
||||||
|
checkResult(op.getResult());
|
||||||
|
return op;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String createFolder(String parentPath, String newDirName)
|
public String createFolder(String parentPath, String newDirName)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
|
|
||||||
try
|
try {
|
||||||
{
|
|
||||||
SkyDrivePath skyDriveParentPath = new SkyDrivePath(parentPath);
|
SkyDrivePath skyDriveParentPath = new SkyDrivePath(parentPath);
|
||||||
|
|
||||||
|
String parentId = skyDriveParentPath.getSkyDriveId();
|
||||||
|
|
||||||
JSONObject newFolder = new JSONObject();
|
JSONObject newFolder = new JSONObject();
|
||||||
newFolder.put("name", newDirName);
|
newFolder.put("name", newDirName);
|
||||||
|
newFolder.put("description", "folder");
|
||||||
|
|
||||||
LiveOperation operation = mConnectClient.put(skyDriveParentPath.getSkyDriveId(), newFolder);
|
LiveOperation operation = mConnectClient.post(
|
||||||
|
parentId, newFolder);
|
||||||
JSONObject result = operation.getResult();
|
JSONObject result = operation.getResult();
|
||||||
checkResult(result);
|
checkResult(result);
|
||||||
return new SkyDrivePath(parentPath, result).getFullPath();
|
return new SkyDrivePath(parentPath, result).getFullPath();
|
||||||
}
|
} catch (Exception e) {
|
||||||
catch(Exception e)
|
|
||||||
{
|
|
||||||
throw convertException(e);
|
throw convertException(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -427,25 +595,108 @@ public class SkyDriveFileStorage extends JavaFileStorageBase {
|
|||||||
@Override
|
@Override
|
||||||
public String createFilePath(String parentPath, String newFileName)
|
public String createFilePath(String parentPath, String newFileName)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
// TODO Auto-generated method stub
|
try {
|
||||||
return null;
|
SkyDrivePath skyDriveParentPath = new SkyDrivePath(parentPath);
|
||||||
|
|
||||||
|
LiveOperation op = uploadFile(skyDriveParentPath, newFileName, new ByteArrayInputStream(new byte[0]));
|
||||||
|
checkResult(op.getResult());
|
||||||
|
|
||||||
|
return new SkyDrivePath(parentPath, op.getResult()).getFullPath();
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw convertException(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<FileEntry> listFiles(String parentPath) throws Exception {
|
public List<FileEntry> listFiles(String parentPath) throws Exception {
|
||||||
// TODO Auto-generated method stub
|
|
||||||
return null;
|
try
|
||||||
|
{
|
||||||
|
SkyDrivePath parentDrivePath = new SkyDrivePath(parentPath);
|
||||||
|
LiveOperation operation = mConnectClient.get(parentDrivePath.getSkyDriveId() + "/files");
|
||||||
|
|
||||||
|
JSONObject result = operation.getResult();
|
||||||
|
checkResult(result);
|
||||||
|
|
||||||
|
JSONArray data = result.optJSONArray(JsonKeys.DATA);
|
||||||
|
List<FileEntry> resultList = new ArrayList<FileEntry>(data.length());
|
||||||
|
|
||||||
|
for (int i = 0; i < data.length(); i++) {
|
||||||
|
SkyDriveObject skyDriveObj = SkyDriveObject.create(data
|
||||||
|
.optJSONObject(i));
|
||||||
|
if (skyDriveObj == null)
|
||||||
|
continue; // ignored type
|
||||||
|
Log.d(TAG, "listing "+skyDriveObj.getName()+" with id " + skyDriveObj.getId()+" in "+skyDriveObj.getParentId());
|
||||||
|
|
||||||
|
resultList.add(convertToFileEntry(parentDrivePath, skyDriveObj));
|
||||||
|
}
|
||||||
|
return resultList;
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
throw convertException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private FileEntry convertToFileEntry(SkyDrivePath parentPath, SkyDriveObject skyDriveObj) throws UnsupportedEncodingException, FileNotFoundException, IOException, InvalidPathException, JSONException, LiveOperationException, SkyDriveException {
|
||||||
|
|
||||||
|
FileEntry res = new FileEntry();
|
||||||
|
res.canRead = true;
|
||||||
|
res.canWrite = true;
|
||||||
|
res.displayName = skyDriveObj.getName();
|
||||||
|
res.isDirectory = SkyDriveFolder.class.isAssignableFrom(skyDriveObj.getClass());
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
res.lastModifiedTime = SKYDRIVE_DATEFORMATTER.parse(skyDriveObj.getUpdatedTime()).getTime();
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Log.w(TAG, "Cannot parse time " + skyDriveObj.getUpdatedTime());
|
||||||
|
res.lastModifiedTime = -1;
|
||||||
|
}
|
||||||
|
if (parentPath == null) //this is the case if we're listing the parent path itself
|
||||||
|
res.path = getProtocolPrefix();
|
||||||
|
else
|
||||||
|
res.path = new SkyDrivePath(parentPath.getFullPath(), skyDriveObj.toJson()).getFullPath();
|
||||||
|
Log.d(TAG, "path: "+res.path);
|
||||||
|
if (SkyDriveFile.class.isAssignableFrom(skyDriveObj.getClass()))
|
||||||
|
{
|
||||||
|
res.sizeInBytes = ((SkyDriveFile)skyDriveObj).getSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public FileEntry getFileEntry(String filename) throws Exception {
|
public FileEntry getFileEntry(String filename) throws Exception {
|
||||||
// TODO Auto-generated method stub
|
try
|
||||||
return null;
|
{
|
||||||
|
SkyDrivePath drivePath = new SkyDrivePath(filename);
|
||||||
|
Log.d(TAG, "getFileEntry for "+ filename +" = "+drivePath.getFullPath());
|
||||||
|
Log.d(TAG, " parent is "+drivePath.getParentPath());
|
||||||
|
return convertToFileEntry(drivePath.getParentPath(),getSkyDriveObject(drivePath));
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
throw convertException(e);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void delete(String path) throws Exception {
|
public void delete(String path) throws Exception {
|
||||||
// TODO Auto-generated method stub
|
try
|
||||||
|
{
|
||||||
|
SkyDrivePath drivePath = new SkyDrivePath(path);
|
||||||
|
LiveOperation op = mConnectClient.delete(drivePath.getSkyDriveId());
|
||||||
|
checkResult(op.getResult());
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
throw convertException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -453,17 +704,14 @@ public class SkyDriveFileStorage extends JavaFileStorageBase {
|
|||||||
public void onCreate(FileStorageSetupActivity activity,
|
public void onCreate(FileStorageSetupActivity activity,
|
||||||
Bundle savedInstanceState) {
|
Bundle savedInstanceState) {
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onResume(FileStorageSetupActivity activity) {
|
public void onResume(FileStorageSetupActivity activity) {
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void finishWithError(final Activity activity,
|
private void finishWithError(final Activity activity, Exception error) {
|
||||||
Exception error) {
|
|
||||||
Log.e("KP2AJ", "Exception: " + error.toString());
|
Log.e("KP2AJ", "Exception: " + error.toString());
|
||||||
error.printStackTrace();
|
error.printStackTrace();
|
||||||
|
|
||||||
@ -473,13 +721,13 @@ public class SkyDriveFileStorage extends JavaFileStorageBase {
|
|||||||
activity.finish();
|
activity.finish();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private void finishActivityWithSuccess(
|
||||||
private void finishActivityWithSuccess(FileStorageSetupActivity setupActivity) {
|
FileStorageSetupActivity setupActivity) {
|
||||||
Log.d("KP2AJ", "Success with authenticating!");
|
Log.d("KP2AJ", "Success with authenticating!");
|
||||||
Activity activity = (Activity) setupActivity;
|
Activity activity = (Activity) setupActivity;
|
||||||
|
|
||||||
if (setupActivity.getProcessName().equals(PROCESS_NAME_FILE_USAGE_SETUP))
|
if (setupActivity.getProcessName()
|
||||||
{
|
.equals(PROCESS_NAME_FILE_USAGE_SETUP)) {
|
||||||
Intent data = new Intent();
|
Intent data = new Intent();
|
||||||
data.putExtra(EXTRA_IS_FOR_SAVE, setupActivity.isForSave());
|
data.putExtra(EXTRA_IS_FOR_SAVE, setupActivity.isForSave());
|
||||||
data.putExtra(EXTRA_PATH, setupActivity.getPath());
|
data.putExtra(EXTRA_PATH, setupActivity.getPath());
|
||||||
@ -487,8 +735,7 @@ public class SkyDriveFileStorage extends JavaFileStorageBase {
|
|||||||
activity.finish();
|
activity.finish();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (setupActivity.getProcessName().equals(PROCESS_NAME_SELECTFILE))
|
if (setupActivity.getProcessName().equals(PROCESS_NAME_SELECTFILE)) {
|
||||||
{
|
|
||||||
Intent data = new Intent();
|
Intent data = new Intent();
|
||||||
|
|
||||||
String path = setupActivity.getState().getString(EXTRA_PATH);
|
String path = setupActivity.getState().getString(EXTRA_PATH);
|
||||||
@ -501,33 +748,24 @@ public class SkyDriveFileStorage extends JavaFileStorageBase {
|
|||||||
|
|
||||||
Log.w("KP2AJ", "Unknown process: " + setupActivity.getProcessName());
|
Log.w("KP2AJ", "Unknown process: " + setupActivity.getProcessName());
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStart(final FileStorageSetupActivity activity) {
|
public void onStart(final FileStorageSetupActivity activity) {
|
||||||
mAuthClient.initialize(Arrays.asList(SCOPES), new LiveAuthListener() {
|
mAuthClient.initialize(Arrays.asList(SCOPES), new LiveAuthListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onAuthError(LiveAuthException exception, Object userState) {
|
public void onAuthError(LiveAuthException exception,
|
||||||
|
Object userState) {
|
||||||
finishWithError(((Activity) activity), exception);
|
finishWithError(((Activity) activity), exception);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onAuthComplete(LiveStatus status,
|
public void onAuthComplete(LiveStatus status,
|
||||||
LiveConnectSession session,
|
LiveConnectSession session, Object userState) {
|
||||||
Object userState) {
|
|
||||||
|
|
||||||
if (status == LiveStatus.CONNECTED) {
|
if (status == LiveStatus.CONNECTED) {
|
||||||
try
|
initialize(activity, session);
|
||||||
{
|
|
||||||
initializeSession(session);
|
|
||||||
finishActivityWithSuccess(activity);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
finishWithError((Activity)activity, e);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
login(activity);
|
login(activity);
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package keepass2android.javafilestorage;
|
package keepass2android.javafilestorage.skydrive;
|
||||||
|
|
||||||
public class SkyDriveException extends Exception {
|
public class SkyDriveException extends Exception {
|
||||||
|
|
@ -1,4 +1,5 @@
|
|||||||
package keepass2android.javafilestorage;
|
package keepass2android.javafilestorage.skydrive;
|
||||||
|
|
||||||
|
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
package keepass2android.javafilestorage;
|
package keepass2android.javafilestorage.skydrive;
|
||||||
|
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
|
@ -1,4 +1,5 @@
|
|||||||
package keepass2android.javafilestorage;
|
package keepass2android.javafilestorage.skydrive;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
Loading…
Reference in New Issue
Block a user