Skip to content

Commit

Permalink
Merge pull request #92 from nextcloud/externalSD2
Browse files Browse the repository at this point in the history
External SD support
  • Loading branch information
AndyScherzinger committed Nov 2, 2016
2 parents 226abe2 + b09126c commit 9f8fdae
Show file tree
Hide file tree
Showing 22 changed files with 1,483 additions and 103 deletions.
5 changes: 5 additions & 0 deletions AndroidManifest.xml
Expand Up @@ -56,6 +56,9 @@
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.WAKE_LOCK" />

<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

<application
android:name=".MainApp"
android:icon="@mipmap/ic_launcher"
Expand All @@ -79,6 +82,8 @@
android:taskAffinity=""
android:excludeFromRecents="true"
android:theme="@style/Theme.ownCloud.NoActionBar">
<activity android:name=".ui.activity.LocalDirectorySelectorActivity" />
<activity android:name=".ui.activity.StorageMigrationActivity" />
<intent-filter>
<action android:name="android.intent.action.SEND" />

Expand Down
52 changes: 52 additions & 0 deletions res/layout/migration_layout.xml
@@ -0,0 +1,52 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Nextcloud Android client application
Copyright (C) 2016 Bartosz Przybylski
Copyright (C) 2016 Nextcloud
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
License as published by the Free Software Foundation; either
version 3 of the License, or any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU AFFERO GENERAL PUBLIC LICENSE for more details.
You should have received a copy of the GNU Affero General Public
License along with this program. If not, see <http://www.gnu.org/licenses/>.
-->

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:orientation="vertical">

<ProgressBar
android:id="@+id/migrationProgress"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:paddingLeft="30dp"
android:paddingRight="30dp"
android:progress="50"/>

<TextView
android:id="@+id/migrationText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text=""
android:textAppearance="?android:attr/textAppearanceMedium"/>

<Button
android:id="@+id/finishButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="@string/drawer_close"/>
</LinearLayout>
28 changes: 28 additions & 0 deletions res/values/strings.xml
Expand Up @@ -356,6 +356,28 @@
<string name="uploader_upload_forbidden_permissions">to upload in this folder</string>
<string name="downloader_download_file_not_found">The file is no longer available on the server</string>

<string name="file_migration_dialog_title">Updating storage path</string>
<string name="file_migration_finish_button">Finish</string>
<string name="file_migration_preparing">Preparing for migration&#8230;</string>
<string name="file_migration_checking_destination">Checking destination&#8230;</string>
<string name="file_migration_saving_accounts_configuration">Saving accounts configuration&#8230;</string>
<string name="file_migration_waiting_for_unfinished_sync">Waiting for unfinished synchronizations&#8230;</string>
<string name="file_migration_migrating">Moving data&#8230;</string>
<string name="file_migration_updating_index">Updating index&#8230;</string>
<string name="file_migration_cleaning">Cleaning&#8230;</string>
<string name="file_migration_restoring_accounts_configuration">Restoring accounts configuration&#8230;</string>
<string name="file_migration_ok_finished">Finished</string>
<string name="file_migration_failed_not_enough_space">ERROR: Not enough space</string>
<string name="file_migration_failed_not_writable">ERROR: File is not writable</string>
<string name="file_migration_failed_not_readable">ERROR: File is not readable</string>
<string name="file_migration_failed_dir_already_exists">ERROR: Nextcloud directory already exists</string>
<string name="file_migration_failed_while_coping">ERROR: While migrating</string>
<string name="file_migration_failed_while_updating_index">ERROR: While updating index</string>

<string name="file_migration_directory_already_exists">Data folder already exists, what to do?</string>
<string name="file_migration_override_data_folder">Override</string>
<string name="file_migration_use_data_folder">Use existing</string>

<string name="prefs_category_accounts">Accounts</string>
<string name="prefs_add_account">Add account</string>
<string name="drawer_manage_accounts">Manage accounts</string>
Expand Down Expand Up @@ -422,6 +444,8 @@
<string name="pref_behaviour_entries_keep_file">kept in original folder</string>
<string name="pref_behaviour_entries_move">moved to app folder</string>
<string name="pref_behaviour_entries_delete_file">deleted</string>
<string name="prefs_storage_path">Storage path</string>
<string name="prefs_common">Common</string>

<string name="share_dialog_title">Sharing</string>
<string name="share_file">Share %1$s</string>
Expand Down Expand Up @@ -506,4 +530,8 @@
<item quantity="other">%d selected</item>
</plurals>

<string name="storage_description_default">Default</string>
<string name="storage_description_sd_no">SD card %1$d</string>
<string name="storage_description_unknown">Unknown</string>

</resources>
5 changes: 5 additions & 0 deletions res/xml/preferences.xml
Expand Up @@ -18,6 +18,11 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >
<PreferenceCategory android:title="@string/prefs_category_general">
<ListPreference
android:title="@string/prefs_storage_path"
android:key="storage_path" />
</PreferenceCategory>

<PreferenceCategory android:title="@string/prefs_category_instant_uploading" android:key="instant_uploading_category">
<com.owncloud.android.ui.CheckBoxPreferenceWithLongTitle android:key="instant_uploading"
Expand Down
23 changes: 20 additions & 3 deletions src/com/owncloud/android/MainApp.java
Expand Up @@ -23,16 +23,19 @@
import android.app.Activity;
import android.app.Application;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.Environment;
import android.preference.PreferenceManager;

import com.owncloud.android.authentication.PassCodeManager;
import com.owncloud.android.datamodel.ThumbnailsCacheManager;
import com.owncloud.android.lib.common.OwnCloudClientManagerFactory;
import com.owncloud.android.lib.common.OwnCloudClientManagerFactory.Policy;
import com.owncloud.android.lib.common.utils.Log_OC;
import com.owncloud.android.ui.activity.Preferences;


/**
Expand All @@ -54,13 +57,20 @@ public class MainApp extends Application {

private static Context mContext;

private static String storagePath;

private static boolean mOnlyOnDevice = false;


public void onCreate(){
super.onCreate();
MainApp.mContext = getApplicationContext();


SharedPreferences appPrefs =
PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
MainApp.storagePath = appPrefs.getString(Preferences.Keys.STORAGE_PATH, Environment.
getExternalStorageDirectory().getAbsolutePath());

boolean isSamlAuth = AUTH_ON.equals(getString(R.string.auth_method_saml_web_sso));

OwnCloudClientManagerFactory.setUserAgent(getUserAgent());
Expand All @@ -80,8 +90,7 @@ public void onCreate(){
// Set folder for store logs
Log_OC.setLogDataFolder(dataFolder);

//TODO: to be changed/fixed whenever SD card support gets merged.
Log_OC.startLogging(Environment.getExternalStorageDirectory().getAbsolutePath());
Log_OC.startLogging(MainApp.storagePath);
Log_OC.d("Debug", "start logging");
}

Expand Down Expand Up @@ -132,6 +141,14 @@ public static Context getAppContext() {
return MainApp.mContext;
}

public static String getStoragePath(){
return MainApp.storagePath;
}

public static void setStoragePath(String path){
MainApp.storagePath = path;
}

// Methods to obtain Strings referring app_name
// From AccountAuthenticator
// public static final String ACCOUNT_TYPE = "owncloud";
Expand Down
86 changes: 53 additions & 33 deletions src/com/owncloud/android/datamodel/FileDataStorageManager.java
Expand Up @@ -46,11 +46,6 @@
import com.owncloud.android.utils.MimeTypeUtil;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
Expand Down Expand Up @@ -727,44 +722,69 @@ public void copyLocalFile(OCFile file, String targetPath) {
if (!targetFolder.exists()) {
targetFolder.mkdirs();
}
copied = copyFile(localFile, targetFile);
copied = FileStorageUtils.copyFile(localFile, targetFile);
}
Log_OC.d(TAG, "Local file COPIED : " + copied);
}
}

private boolean copyFile(File src, File target) {
boolean ret = true;

InputStream in = null;
OutputStream out = null;
public void migrateStoredFiles(String srcPath, String dstPath) throws Exception {
Cursor c = null;
if (getContentResolver() != null) {
c = getContentResolver().query(ProviderTableMeta.CONTENT_URI_FILE,
null,
ProviderTableMeta.FILE_STORAGE_PATH + " IS NOT NULL",
null,
null);

try {
in = new FileInputStream(src);
out = new FileOutputStream(target);
byte[] buf = new byte[1024];
int len;
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
} catch (IOException ex) {
ret = false;
} finally {
if (in != null) try {
in.close();
} catch (IOException e) {
e.printStackTrace(System.err);
}
if (out != null) try {
out.close();
} catch (IOException e) {
e.printStackTrace(System.err);
} else {
try {
c = getContentProviderClient().query(ProviderTableMeta.CONTENT_URI_FILE,
new String[]{ProviderTableMeta._ID, ProviderTableMeta.FILE_STORAGE_PATH},
ProviderTableMeta.FILE_STORAGE_PATH + " IS NOT NULL",
null,
null);
} catch (RemoteException e) {
Log_OC.e(TAG, e.getMessage());
throw e;
}
}

return ret;
}
ArrayList<ContentProviderOperation> operations =
new ArrayList<ContentProviderOperation>(c.getCount());
if (c.moveToFirst()) {
do {
ContentValues cv = new ContentValues();
long fileId = c.getLong(c.getColumnIndex(ProviderTableMeta._ID));
String oldFileStoragePath = c.getString(c.getColumnIndex(ProviderTableMeta.FILE_STORAGE_PATH));

if (oldFileStoragePath.startsWith(srcPath)) {

cv.put(
ProviderTableMeta.FILE_STORAGE_PATH,
oldFileStoragePath.replaceFirst(srcPath, dstPath));

operations.add(
ContentProviderOperation.newUpdate(ProviderTableMeta.CONTENT_URI).
withValues(cv).
withSelection(
ProviderTableMeta._ID + "=?",
new String[]{String.valueOf(fileId)}
)
.build());
}

} while (c.moveToNext());
}
c.close();

/// 3. apply updates in batch
if (getContentResolver() != null) {
getContentResolver().applyBatch(MainApp.getAuthority(), operations);
} else {
getContentProviderClient().applyBatch(operations);
}
}

private Vector<OCFile> getFolderContent(long parentId, boolean onlyOnDevice) {

Expand Down

0 comments on commit 9f8fdae

Please sign in to comment.