Merge pull request #1493 from owncloud/reliable_uploads_actions_uploads_view
Uploads view added to monitor and handle uploads progress
|
@ -3,7 +3,7 @@
|
|||
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
|
||||
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
|
||||
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.DEPENDENCIES"/>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry kind="src" path="gen"/>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry kind="output" path="bin/classes"/>
|
||||
</classpath>
|
||||
|
|
1
.gitignore
vendored
|
@ -21,6 +21,7 @@ oc_workaround/local.properties
|
|||
oc_framework/local.properties
|
||||
oc_framework-test-project/local.properties
|
||||
tests/local.properties
|
||||
lint.xml
|
||||
|
||||
# Mac .DS_Store files
|
||||
.DS_Store
|
||||
|
|
|
@ -163,12 +163,23 @@
|
|||
<service android:name=".media.MediaService" />
|
||||
|
||||
<activity android:name=".ui.activity.PassCodeActivity" />
|
||||
<activity android:name=".ui.activity.ConflictsResolveActivity" />
|
||||
<activity android:name=".ui.activity.GenericExplanationActivity" />
|
||||
<activity android:name=".ui.activity.ErrorsWhileCopyingHandlerActivity" />
|
||||
<activity android:name=".ui.activity.LogHistoryActivity" />
|
||||
<activity android:name=".ui.activity.ConflictsResolveActivity"/>
|
||||
<activity android:name=".ui.activity.GenericExplanationActivity"/>
|
||||
<activity android:name=".ui.activity.ErrorsWhileCopyingHandlerActivity"/>
|
||||
|
||||
<activity android:name=".ui.activity.LogHistoryActivity"/>
|
||||
|
||||
<receiver android:name=".files.InstantUploadBroadcastReceiver" >
|
||||
<activity android:name=".ui.errorhandling.ErrorShowActivity" />
|
||||
<activity android:name=".ui.activity.UploadListActivity" />
|
||||
|
||||
<receiver android:name=".files.services.ConnectivityActionReceiver"
|
||||
android:enabled="true" android:label="ConnectivityActionReceiver">
|
||||
<intent-filter>
|
||||
<!--action android:name="android.net.conn.CONNECTIVITY_CHANGE"/-->
|
||||
<action android:name="android.net.wifi.STATE_CHANGE"/>
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
<receiver android:name=".files.InstantUploadBroadcastReceiver">
|
||||
<intent-filter>
|
||||
|
||||
<!-- unofficially supported by many Android phones but not by HTC devices: -->
|
||||
|
@ -183,9 +194,6 @@
|
|||
|
||||
<data android:mimeType="video/*" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
<receiver android:name=".files.BootupBroadcastReceiver" >
|
||||
<intent-filter>
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 573afa15382b67cc84f67fc9a7b2329a72ecb352
|
||||
Subproject commit 39e3ddaa07b0943b034b34a84a33b4dc4c7475d0
|
BIN
res/drawable-hdpi/ic_refresh.png
Normal file
After Width: | Height: | Size: 840 B |
BIN
res/drawable-mdpi/ic_cancel.png
Normal file
After Width: | Height: | Size: 935 B |
BIN
res/drawable-mdpi/ic_refresh.png
Normal file
After Width: | Height: | Size: 578 B |
BIN
res/drawable-mdpi/ic_uploads.png
Normal file
After Width: | Height: | Size: 183 B |
BIN
res/drawable-xhdpi/ic_refresh.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
res/drawable-xhdpi/ic_uploads.png
Normal file
After Width: | Height: | Size: 230 B |
BIN
res/drawable-xxhdpi/ic_refresh.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
res/drawable-xxhdpi/ic_uploads.png
Normal file
After Width: | Height: | Size: 275 B |
BIN
res/drawable-xxxhdpi/ic_refresh.png
Normal file
After Width: | Height: | Size: 2 KiB |
BIN
res/drawable-xxxhdpi/ic_uploads.png
Normal file
After Width: | Height: | Size: 360 B |
46
res/drawable/btn_small_round.xml
Executable file
|
@ -0,0 +1,46 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<!-- pressed state of button, only change: color of actual button -->
|
||||
<item android:state_pressed="true" >
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<!-- shadow, a little down and a little to the right -->
|
||||
<item><shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval">
|
||||
<gradient android:angle="270" android:endColor="#99000000" android:startColor="#99000000" />
|
||||
</shape></item>
|
||||
<!-- this is the actual button -->
|
||||
<item android:bottom="1px" android:right="1px"><shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval">
|
||||
<gradient android:angle="270" android:endColor="#47ffffff" android:startColor="#97ffffff" />
|
||||
</shape></item>
|
||||
</layer-list>
|
||||
</item>
|
||||
|
||||
<!-- focused state of button, only change: color of actual button -->
|
||||
<item android:state_focused="true" >
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<!-- shadow, a little down and a little to the right -->
|
||||
<item><shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval">
|
||||
<gradient android:angle="270" android:endColor="#22000000" android:startColor="#22000000" />
|
||||
</shape></item>
|
||||
<!-- this is the actual button -->
|
||||
<item android:bottom="1px" android:right="1px"><shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval">
|
||||
<gradient android:angle="270" android:endColor="#47ffffff" android:startColor="#97ffffff" />
|
||||
</shape></item>
|
||||
</layer-list>
|
||||
</item>
<!-- normal state of button. Template for other states. -->
|
||||
<item>
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<!-- shadow, a little down and a little to the right -->
|
||||
<item>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval">
|
||||
<gradient android:angle="270" android:endColor="#55000000" android:startColor="#55000000" />
|
||||
</shape></item>
|
||||
<!-- this is the actual button -->
|
||||
<item android:bottom="1px" android:right="1px">
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval">
|
||||
<gradient android:angle="270" android:endColor="#47ffffff" android:startColor="#97ffffff" />
|
||||
</shape>
|
||||
</item>
|
||||
</layer-list>
|
||||
</item>
|
||||
</selector>
|
BIN
res/drawable/upload_failed.png
Executable file
After Width: | Height: | Size: 461 B |
BIN
res/drawable/upload_finished.png
Executable file
After Width: | Height: | Size: 322 B |
BIN
res/drawable/upload_in_progress.png
Executable file
After Width: | Height: | Size: 658 B |
11
res/layout/errorhandling_showerror.xml
Executable file
|
@ -0,0 +1,11 @@
|
|||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" >
|
||||
|
||||
<TextView
|
||||
android:id="@+id/errorTextView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
</ScrollView>
|
45
res/layout/list_fragment_expandable.xml
Executable file
|
@ -0,0 +1,45 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
This must be a clone of list_fragment.xml
|
||||
|
||||
EXCEPT: ExpandableListView must be used for @+id/swipe_refresh_files_emptyView
|
||||
-->
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1" >
|
||||
|
||||
<android.support.v4.widget.SwipeRefreshLayout
|
||||
android:id="@+id/swipe_refresh_files"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" >
|
||||
|
||||
<ExpandableListView
|
||||
android:id="@+id/list_root"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
</android.support.v4.widget.SwipeRefreshLayout>
|
||||
|
||||
<android.support.v4.widget.SwipeRefreshLayout
|
||||
android:id="@+id/swipe_refresh_files_emptyView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:visibility="gone" >
|
||||
|
||||
<ScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" >
|
||||
|
||||
<TextView
|
||||
android:id="@+id/empty_list_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical|center_horizontal"
|
||||
android:text="@string/empty"
|
||||
android:layout_gravity="center"
|
||||
android:visibility="visible" />
|
||||
|
||||
</ScrollView>
|
||||
</android.support.v4.widget.SwipeRefreshLayout>
|
||||
</FrameLayout>
|
19
res/layout/upload_list_group.xml
Executable file
|
@ -0,0 +1,19 @@
|
|||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="3dp" >
|
||||
|
||||
<TextView
|
||||
android:id="@+id/uploadListGroupName"
|
||||
style="?android:attr/listSeparatorTextViewStyle"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:divider="@null"
|
||||
android:dividerHeight="0dp"
|
||||
android:ellipsize="middle"
|
||||
android:showDividers="none"
|
||||
android:textColor="@color/color_accent"
|
||||
android:paddingLeft="16dp"
|
||||
/>
|
||||
|
||||
</RelativeLayout>
|
127
res/layout/upload_list_item.xml
Executable file
|
@ -0,0 +1,127 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/ListItemLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:orientation="horizontal"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="@dimen/standard_half_padding"
|
||||
android:paddingBottom="@dimen/standard_half_padding"
|
||||
>
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="60dp"
|
||||
android:layout_height="72dp"
|
||||
android:focusable="false"
|
||||
android:focusableInTouchMode="false">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/thumbnail"
|
||||
android:layout_width="@dimen/file_icon_size"
|
||||
android:layout_height="@dimen/file_icon_size"
|
||||
android:layout_gravity="center"
|
||||
android:src="@drawable/ic_menu_archive" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:gravity="center_vertical"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:orientation="vertical" >
|
||||
|
||||
<TextView
|
||||
android:id="@+id/upload_name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:ellipsize="middle"
|
||||
android:singleLine="true"
|
||||
android:textColor="@color/textColor"
|
||||
android:text="@string/placeholder_filename"
|
||||
android:textSize="16sp" />
|
||||
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
<TextView
|
||||
android:id="@+id/upload_file_size"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="left"
|
||||
android:textColor="@color/list_item_lastmod_and_filesize_text"
|
||||
android:ellipsize="middle"
|
||||
android:singleLine="true"
|
||||
android:text="@string/placeholder_filesize"
|
||||
android:textSize="12sp"/>
|
||||
<TextView
|
||||
android:id="@+id/upload_date"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="@color/list_item_lastmod_and_filesize_text"
|
||||
android:layout_marginStart="4dp"
|
||||
android:layout_marginEnd="4dp"
|
||||
android:text="@string/placeholder_timestamp"
|
||||
android:textSize="12sp"/>
|
||||
<TextView
|
||||
android:id="@+id/upload_status"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="@color/list_item_lastmod_and_filesize_text"
|
||||
android:text="@string/uploads_view_upload_status_succeeded"
|
||||
android:textSize="12sp"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/upload_progress_bar"
|
||||
style="?android:attr/progressBarStyleHorizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/upload_account"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="@color/list_item_lastmod_and_filesize_text"
|
||||
android:singleLine="true"
|
||||
android:text="@string/auth_username"
|
||||
android:textSize="12dip"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/upload_remote_path"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="@color/list_item_lastmod_and_filesize_text"
|
||||
android:ellipsize="middle"
|
||||
android:singleLine="true"
|
||||
android:text="@string/instant_upload_path"
|
||||
android:textSize="12dip"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="56dp"
|
||||
android:layout_height="72dp"
|
||||
android:focusable="false"
|
||||
android:focusableInTouchMode="false"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:paddingLeft="8dp"
|
||||
>
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/upload_right_button"
|
||||
android:layout_width="35dp"
|
||||
android:layout_height="35dp"
|
||||
android:layout_gravity="center"
|
||||
android:background="@android:color/transparent"
|
||||
/>
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
|
||||
</LinearLayout>
|
24
res/layout/upload_list_layout.xml
Executable file
|
@ -0,0 +1,24 @@
|
|||
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/drawer_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:clickable="true" >
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/background_color">
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/upload_list_fragment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
</LinearLayout>
|
||||
|
||||
<include
|
||||
layout="@layout/drawer"
|
||||
android:layout_width="240dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="start"/>
|
||||
|
||||
</android.support.v4.widget.DrawerLayout>
|
34
res/menu/upload_list_menu.xml
Executable file
|
@ -0,0 +1,34 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
ownCloud Android client application
|
||||
|
||||
Copyright (C) 2012 Bartek Przybylski
|
||||
Copyright (C) 2012-2013 ownCloud Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License version 2,
|
||||
as published by the Free Software Foundation.
|
||||
|
||||
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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||
|
||||
<item
|
||||
android:id="@+id/action_retry_uploads"
|
||||
android:title="@string/action_retry_uploads"/>
|
||||
<item
|
||||
android:id="@+id/action_clear_failed_uploads"
|
||||
android:title="@string/action_clear_failed_uploads"/>
|
||||
<item
|
||||
android:id="@+id/action_clear_successfull_uploads"
|
||||
android:title="@string/action_clear_successful_uploads"/>
|
||||
<item
|
||||
android:id="@+id/action_clear_finished_uploads"
|
||||
android:title="@string/action_clear_finished_uploads"/>
|
||||
</menu>
|
|
@ -24,6 +24,7 @@
|
|||
<!--<item>@string/prefs_accounts</item>-->
|
||||
<item>@string/drawer_item_all_files</item>
|
||||
<!--<item>@string/drawer_item_on_device</item>-->
|
||||
<item>@string/drawer_item_uploads_list</item>
|
||||
<item>@string/actionbar_settings</item>
|
||||
<item>@string/actionbar_logger</item>
|
||||
</string-array>
|
||||
|
@ -34,6 +35,7 @@
|
|||
<!--<item>@string/drawer_item_accounts</item>-->
|
||||
<item>@string/drawer_item_all_files</item>
|
||||
<!--<item>@string/drawer_item_on_device</item>-->
|
||||
<item>@string/drawer_item_uploads_list</item>
|
||||
<item>@string/drawer_item_settings</item>
|
||||
<item>@string/drawer_item_logs</item>
|
||||
</string-array>
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
<!-- TODO re-enable when "On Device" is available
|
||||
<string name="drawer_item_on_device">On device</string>-->
|
||||
<string name="drawer_item_settings">Settings</string>
|
||||
<string name="drawer_item_uploads_list">Uploads</string>
|
||||
<string name="drawer_item_logs">Logs</string>
|
||||
<string name="drawer_close">Close</string>
|
||||
<string name="drawer_open">Open</string>
|
||||
|
@ -76,6 +77,11 @@
|
|||
<string name="file_list_loading">Loading…</string>
|
||||
<string name="file_list_no_app_for_file_type">No app found for file type!</string>
|
||||
<string name="local_file_list_empty">There are no files in this folder.</string>
|
||||
<string name="upload_list_empty">No uploads available.</string>
|
||||
<string name="file_list_folder">folder</string>
|
||||
<string name="file_list_folders">folders</string>
|
||||
<string name="file_list_file">file</string>
|
||||
<string name="file_list_files">files</string>
|
||||
<string name="filedetails_select_file">Tap on a file to display additional information.</string>
|
||||
<string name="filedetails_size">Size:</string>
|
||||
<string name="filedetails_type">Type:</string>
|
||||
|
@ -89,6 +95,8 @@
|
|||
<string name="common_yes">Yes</string>
|
||||
<string name="common_no">No</string>
|
||||
<string name="common_ok">OK</string>
|
||||
<string name="common_remove_upload">Remove upload</string>
|
||||
<string name="common_retry_upload">Retry upload</string>
|
||||
<string name="common_cancel_sync">Cancel sync</string>
|
||||
<string name="common_cancel">Cancel</string>
|
||||
<string name="common_save_exit">Save & exit</string>
|
||||
|
@ -108,6 +116,25 @@
|
|||
<string name="uploader_upload_failed_ticker">Upload failed</string>
|
||||
<string name="uploader_upload_failed_content_single">Upload of %1$s could not be completed</string>
|
||||
<string name="uploader_upload_failed_credentials_error">Upload failed, you need to log in again</string>
|
||||
<string name="uploads_view_title">Uploads</string>
|
||||
<string name="uploads_view_group_current_uploads">Current</string>
|
||||
<string name="uploads_view_group_failed_uploads">Failed (tap to retry)</string>
|
||||
<string name="uploads_view_group_finished_uploads">Uploaded</string>
|
||||
<string name="uploads_view_upload_status_succeeded">Completed</string>
|
||||
<string name="uploads_view_upload_status_cancelled">Cancelled</string>
|
||||
<string name="uploads_view_upload_status_paused">Paused</string>
|
||||
<string name="uploads_view_upload_status_failed_connection_error">Connection error</string>
|
||||
<string name="uploads_view_upload_status_failed_retry">Upload will be retried shortly</string>
|
||||
<string name="uploads_view_upload_status_failed_credentials_error">Credentials error</string>
|
||||
<string name="uploads_view_upload_status_failed_folder_error">Folder error</string>
|
||||
<string name="uploads_view_upload_status_failed_file_error">File error</string>
|
||||
<string name="uploads_view_upload_status_failed_localfile_error">Local file not found</string>
|
||||
<string name="uploads_view_upload_status_failed_permission_error">Permission error</string>
|
||||
<string name="uploads_view_upload_status_conflict">Conflict</string>
|
||||
<string name="uploads_view_upload_status_service_interrupted">App was terminated</string>
|
||||
<string name="uploads_view_upload_status_unknown_fail">Unknown error</string>
|
||||
<string name="uploads_view_upload_status_waiting_for_wifi">Waiting for wifi connectivity</string>
|
||||
<string name="uploads_view_later_waiting_to_upload">Waiting to upload</string>
|
||||
<string name="downloader_download_in_progress_ticker">Downloading …</string>
|
||||
<string name="downloader_download_in_progress_content">%1$d%% Downloading %2$s</string>
|
||||
<string name="downloader_download_succeeded_ticker">Download succeeded</string>
|
||||
|
@ -219,6 +246,7 @@
|
|||
<string name="filename_forbidden_charaters_from_server">File name contains at least one invalid character</string>
|
||||
<string name="filename_empty">File name cannot be empty</string>
|
||||
<string name="wait_a_moment">Wait a moment</string>
|
||||
<string name="wait_checking_credentials">Checking stored credentials</string>
|
||||
<string name="filedisplay_unexpected_bad_get_content">"Unexpected problem ; please select the file from a different app"</string>
|
||||
<string name="filedisplay_no_file_selected">No file was selected</string>
|
||||
<string name="activity_chooser_title">Send link to …</string>
|
||||
|
@ -405,6 +433,11 @@
|
|||
<string name="edit_share_unshare">Stop sharing</string>
|
||||
<string name="edit_share_done">done</string>
|
||||
|
||||
<string name="action_retry_uploads">Retry failed</string>
|
||||
<string name="action_clear_failed_uploads">Clear failed</string>
|
||||
<string name="action_clear_successful_uploads">Clear successful</string>
|
||||
<string name="action_clear_finished_uploads">Clear all finished</string>
|
||||
|
||||
<string name="action_switch_grid_view">Grid view</string>
|
||||
<string name="action_switch_list_view">List view</string>
|
||||
|
||||
|
@ -414,5 +447,6 @@
|
|||
<string name="manage_space_error">Some files could not be deleted.</string>
|
||||
|
||||
<string name="permission_storage_access">Additional permissions required to upload & download files.</string>
|
||||
<string name="local_file_not_found_toast">The file was not found locally</string>
|
||||
|
||||
</resources>
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
<item name="colorAccent">@color/color_accent</item>
|
||||
<item name="android:alertDialogTheme">@style/Theme.ownCloud.Dialog</item>
|
||||
<item name="alertDialogTheme">@style/ownCloud.AlertDialog</item>
|
||||
<item name="android:windowBackground">@color/background_color</item>
|
||||
<item name="searchViewStyle">@style/ownCloud.SearchView</item>
|
||||
</style>
|
||||
|
||||
|
@ -41,6 +42,7 @@
|
|||
<item name="colorAccent">@color/color_accent</item>
|
||||
<item name="android:alertDialogTheme">@style/Theme.ownCloud.Dialog</item>
|
||||
<item name="alertDialogTheme">@style/ownCloud.AlertDialog</item>
|
||||
<item name="android:windowBackground">@color/background_color</item>
|
||||
<item name="searchViewStyle">@style/ownCloud.SearchView</item>
|
||||
</style>
|
||||
|
||||
|
|
|
@ -166,7 +166,9 @@ public class MainApp extends Application {
|
|||
return getAppContext().getResources().getString(R.string.db_name);
|
||||
}
|
||||
|
||||
// data_folder
|
||||
/**
|
||||
* name of data_folder, e.g., "owncloud"
|
||||
*/
|
||||
public static String getDataFolder() {
|
||||
return getAppContext().getResources().getString(R.string.data_folder);
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* ownCloud Android client application
|
||||
*
|
||||
* Copyright (C) 2012 Bartek Przybylski
|
||||
* Copyright (C) 2015 ownCloud Inc.
|
||||
* Copyright (C) 2016 ownCloud Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
|
@ -20,7 +20,12 @@
|
|||
|
||||
package com.owncloud.android.authentication;
|
||||
|
||||
import java.util.Locale;
|
||||
import android.accounts.Account;
|
||||
import android.accounts.AccountManager;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.net.Uri;
|
||||
import android.preference.PreferenceManager;
|
||||
|
||||
import com.owncloud.android.MainApp;
|
||||
import com.owncloud.android.lib.common.accounts.AccountTypeUtils;
|
||||
|
@ -28,12 +33,7 @@ import com.owncloud.android.lib.common.accounts.AccountUtils.Constants;
|
|||
import com.owncloud.android.lib.common.utils.Log_OC;
|
||||
import com.owncloud.android.lib.resources.status.OwnCloudVersion;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.accounts.AccountManager;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.net.Uri;
|
||||
import android.preference.PreferenceManager;
|
||||
import java.util.Locale;
|
||||
|
||||
public class AccountUtils {
|
||||
|
||||
|
@ -108,6 +108,22 @@ public class AccountUtils {
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns owncloud account identified by accountName or null if it does not exist.
|
||||
* @param context
|
||||
* @param accountName name of account to be returned
|
||||
* @return owncloud account named accountName
|
||||
*/
|
||||
public static Account getOwnCloudAccountByName(Context context, String accountName) {
|
||||
Account[] ocAccounts = AccountManager.get(context).getAccountsByType(
|
||||
MainApp.getAccountType());
|
||||
for (Account account : ocAccounts) {
|
||||
if(account.name.equals(accountName))
|
||||
return account;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public static boolean setCurrentOwnCloudAccount(Context context, String accountName) {
|
||||
boolean result = false;
|
||||
|
|
|
@ -65,6 +65,8 @@ import android.widget.Toast;
|
|||
import com.owncloud.android.MainApp;
|
||||
import com.owncloud.android.R;
|
||||
import com.owncloud.android.authentication.SsoWebViewClient.SsoWebViewClientListener;
|
||||
import com.owncloud.android.lib.common.OwnCloudAccount;
|
||||
import com.owncloud.android.lib.common.OwnCloudClientManagerFactory;
|
||||
import com.owncloud.android.lib.common.OwnCloudCredentials;
|
||||
import com.owncloud.android.lib.common.OwnCloudCredentialsFactory;
|
||||
import com.owncloud.android.lib.common.accounts.AccountTypeUtils;
|
||||
|
@ -925,6 +927,7 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
|
|||
} else {
|
||||
checkBasicAuthorization();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -1465,6 +1468,8 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
|
|||
* the new credentials when needed.
|
||||
*/
|
||||
private void updateAccountAuthentication() throws AccountNotFoundException {
|
||||
|
||||
|
||||
|
||||
Bundle response = new Bundle();
|
||||
response.putString(AccountManager.KEY_ACCOUNT_NAME, mAccount.name);
|
||||
|
@ -1489,7 +1494,15 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
|
|||
response.putString(AccountManager.KEY_AUTHTOKEN, mPasswordInput.getText().toString());
|
||||
mAccountMgr.setPassword(mAccount, mPasswordInput.getText().toString());
|
||||
}
|
||||
|
||||
// remove managed clients for this account to enforce creation with fresh credentials
|
||||
OwnCloudAccount ocAccount = new OwnCloudAccount(mAccount, this);
|
||||
OwnCloudClientManagerFactory.getDefaultSingleton().removeClientFor(ocAccount);
|
||||
|
||||
setAccountAuthenticatorResult(response);
|
||||
final Intent intent = new Intent();
|
||||
intent.putExtras(response);
|
||||
setResult(RESULT_OK, intent);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -254,6 +254,20 @@ public class FileDataStorageManager {
|
|||
}
|
||||
|
||||
|
||||
public void saveNewFile(OCFile newFile) {
|
||||
String remoteParentPath = new File(newFile.getRemotePath()).getParent();
|
||||
remoteParentPath = remoteParentPath.endsWith(OCFile.PATH_SEPARATOR) ?
|
||||
remoteParentPath : remoteParentPath + OCFile.PATH_SEPARATOR;
|
||||
OCFile parent = getFileByPath(remoteParentPath);
|
||||
if (parent != null) {
|
||||
newFile.setParentId(parent.getFileId());
|
||||
saveFile(newFile);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Saving a new file in an unexisting folder");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Inserts or updates the list of files contained in a given folder.
|
||||
* <p/>
|
||||
|
@ -2043,4 +2057,5 @@ public class FileDataStorageManager {
|
|||
}
|
||||
return capability;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* @author Bartek Przybylski
|
||||
* @author David A. Velasco
|
||||
* Copyright (C) 2012 Bartek Przybylski
|
||||
* Copyright (C) 2015 ownCloud Inc.
|
||||
* Copyright (C) 2016 ownCloud Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
|
@ -22,6 +22,9 @@
|
|||
|
||||
package com.owncloud.android.datamodel;
|
||||
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.net.Uri;
|
||||
import android.os.Parcel;
|
||||
|
@ -30,9 +33,8 @@ import android.webkit.MimeTypeMap;
|
|||
|
||||
import com.owncloud.android.lib.common.utils.Log_OC;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import third_parties.daveKoeller.AlphanumComparator;
|
||||
|
||||
public class OCFile implements Parcelable, Comparable<OCFile> {
|
||||
|
||||
public static final Parcelable.Creator<OCFile> CREATOR = new Parcelable.Creator<OCFile>() {
|
||||
|
|
514
src/com/owncloud/android/datamodel/UploadsStorageManager.java
Normal file
|
@ -0,0 +1,514 @@
|
|||
/**
|
||||
* ownCloud Android client application
|
||||
*
|
||||
* @author LukeOwncloud
|
||||
* @author David A. Velasco
|
||||
* @author masensio
|
||||
* Copyright (C) 2016 ownCloud Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.owncloud.android.datamodel;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.content.ContentValues;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
|
||||
import com.owncloud.android.db.OCUpload;
|
||||
import com.owncloud.android.db.ProviderMeta.ProviderTableMeta;
|
||||
import com.owncloud.android.db.UploadResult;
|
||||
import com.owncloud.android.files.services.FileUploader;
|
||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
|
||||
import com.owncloud.android.lib.common.utils.Log_OC;
|
||||
import com.owncloud.android.operations.UploadFileOperation;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.Observable;
|
||||
|
||||
/**
|
||||
* Database helper for storing list of files to be uploaded, including status
|
||||
* information for each file.
|
||||
*/
|
||||
public class UploadsStorageManager extends Observable {
|
||||
|
||||
private ContentResolver mContentResolver;
|
||||
|
||||
static private final String TAG = UploadsStorageManager.class.getSimpleName();
|
||||
|
||||
|
||||
public enum UploadStatus {
|
||||
|
||||
/**
|
||||
* Upload currently in progress or scheduled to be executed.
|
||||
*/
|
||||
UPLOAD_IN_PROGRESS(0),
|
||||
|
||||
/**
|
||||
* Last upload failed.
|
||||
*/
|
||||
UPLOAD_FAILED(1),
|
||||
|
||||
/**
|
||||
* Upload was successful.
|
||||
*/
|
||||
UPLOAD_SUCCEEDED(2);
|
||||
|
||||
private final int value;
|
||||
|
||||
UploadStatus(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public int getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public static UploadStatus fromValue(int value) {
|
||||
switch (value) {
|
||||
case 0:
|
||||
return UPLOAD_IN_PROGRESS;
|
||||
case 1:
|
||||
return UPLOAD_FAILED;
|
||||
case 2:
|
||||
return UPLOAD_SUCCEEDED;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public UploadsStorageManager(ContentResolver contentResolver) {
|
||||
if (contentResolver == null) {
|
||||
throw new IllegalArgumentException("Cannot create an instance with a NULL contentResolver");
|
||||
}
|
||||
mContentResolver = contentResolver;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores an upload object in DB.
|
||||
*
|
||||
* @param ocUpload Upload object to store
|
||||
* @return upload id, -1 if the insert process fails.
|
||||
*/
|
||||
public long storeUpload(OCUpload ocUpload) {
|
||||
Log_OC.v(TAG, "Inserting " + ocUpload.getLocalPath() + " with status=" + ocUpload.getUploadStatus());
|
||||
|
||||
ContentValues cv = new ContentValues();
|
||||
cv.put(ProviderTableMeta.UPLOADS_LOCAL_PATH, ocUpload.getLocalPath());
|
||||
cv.put(ProviderTableMeta.UPLOADS_REMOTE_PATH, ocUpload.getRemotePath());
|
||||
cv.put(ProviderTableMeta.UPLOADS_ACCOUNT_NAME, ocUpload.getAccountName());
|
||||
cv.put(ProviderTableMeta.UPLOADS_FILE_SIZE, ocUpload.getFileSize());
|
||||
cv.put(ProviderTableMeta.UPLOADS_STATUS, ocUpload.getUploadStatus().value);
|
||||
cv.put(ProviderTableMeta.UPLOADS_LOCAL_BEHAVIOUR, ocUpload.getLocalAction());
|
||||
cv.put(ProviderTableMeta.UPLOADS_FORCE_OVERWRITE, ocUpload.isForceOverwrite() ? 1 : 0);
|
||||
cv.put(ProviderTableMeta.UPLOADS_IS_CREATE_REMOTE_FOLDER, ocUpload.isCreateRemoteFolder() ? 1 : 0);
|
||||
cv.put(ProviderTableMeta.UPLOADS_LAST_RESULT, ocUpload.getLastResult().getValue());
|
||||
cv.put(ProviderTableMeta.UPLOADS_CREATED_BY, ocUpload.getCreadtedBy());
|
||||
|
||||
Uri result = getDB().insert(ProviderTableMeta.CONTENT_URI_UPLOADS, cv);
|
||||
|
||||
Log_OC.d(TAG, "storeUpload returns with: " + result + " for file: " + ocUpload.getLocalPath());
|
||||
if (result == null) {
|
||||
Log_OC.e(TAG, "Failed to insert item " + ocUpload.getLocalPath() + " into upload db.");
|
||||
return -1;
|
||||
} else {
|
||||
long new_id = Long.parseLong(result.getPathSegments().get(1));
|
||||
ocUpload.setUploadId(new_id);
|
||||
notifyObserversNow();
|
||||
return new_id;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update an upload object in DB.
|
||||
*
|
||||
* @param ocUpload Upload object with state to update
|
||||
* @return num of updated uploads.
|
||||
*/
|
||||
public int updateUpload(OCUpload ocUpload) {
|
||||
Log_OC.v(TAG, "Updating " + ocUpload.getLocalPath() + " with status=" + ocUpload.getUploadStatus());
|
||||
|
||||
ContentValues cv = new ContentValues();
|
||||
cv.put(ProviderTableMeta.UPLOADS_LOCAL_PATH, ocUpload.getLocalPath());
|
||||
cv.put(ProviderTableMeta.UPLOADS_REMOTE_PATH, ocUpload.getRemotePath());
|
||||
cv.put(ProviderTableMeta.UPLOADS_ACCOUNT_NAME, ocUpload.getAccountName());
|
||||
cv.put(ProviderTableMeta.UPLOADS_STATUS, ocUpload.getUploadStatus().value);
|
||||
cv.put(ProviderTableMeta.UPLOADS_LAST_RESULT, ocUpload.getLastResult().getValue());
|
||||
cv.put(ProviderTableMeta.UPLOADS_UPLOAD_END_TIMESTAMP, ocUpload.getUploadEndTimestamp());
|
||||
|
||||
int result = getDB().update(ProviderTableMeta.CONTENT_URI_UPLOADS,
|
||||
cv,
|
||||
ProviderTableMeta._ID + "=?",
|
||||
new String[]{String.valueOf(ocUpload.getUploadId())}
|
||||
);
|
||||
|
||||
Log_OC.d(TAG, "updateUpload returns with: " + result + " for file: " + ocUpload.getLocalPath());
|
||||
if (result != 1) {
|
||||
Log_OC.e(TAG, "Failed to update item " + ocUpload.getLocalPath() + " into upload db.");
|
||||
} else {
|
||||
notifyObserversNow();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private int updateUploadInternal(Cursor c, UploadStatus status, UploadResult result, String remotePath,
|
||||
String localPath) {
|
||||
|
||||
int r = 0;
|
||||
while (c.moveToNext()) {
|
||||
// read upload object and update
|
||||
OCUpload upload = createOCUploadFromCursor(c);
|
||||
|
||||
String path = c.getString(c.getColumnIndex(ProviderTableMeta.UPLOADS_LOCAL_PATH));
|
||||
Log_OC.v(
|
||||
TAG,
|
||||
"Updating " + path + " with status:" + status + " and result:"
|
||||
+ (result == null ? "null" : result.toString()) + " (old:"
|
||||
+ upload.toFormattedString() + ")");
|
||||
|
||||
upload.setUploadStatus(status);
|
||||
upload.setLastResult(result);
|
||||
upload.setRemotePath(remotePath);
|
||||
if(localPath != null) {
|
||||
upload.setLocalPath(localPath);
|
||||
}
|
||||
if (status == UploadStatus.UPLOAD_SUCCEEDED) {
|
||||
upload.setUploadEndTimestamp(Calendar.getInstance().getTimeInMillis());
|
||||
}
|
||||
|
||||
// store update upload object to db
|
||||
r = updateUpload(upload);
|
||||
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update upload status of file uniquely referenced by id.
|
||||
*
|
||||
* @param id upload id.
|
||||
* @param status new status.
|
||||
* @param result new result of upload operation
|
||||
* @param remotePath path of the file to upload in the ownCloud storage
|
||||
* @param localPath path of the file to upload in the device storage
|
||||
* @return 1 if file status was updated, else 0.
|
||||
*/
|
||||
public int updateUploadStatus(long id, UploadStatus status, UploadResult result, String remotePath,
|
||||
String localPath) {
|
||||
//Log_OC.v(TAG, "Updating "+filepath+" with uploadStatus="+status +" and result="+result);
|
||||
|
||||
int returnValue = 0;
|
||||
Cursor c = getDB().query(
|
||||
ProviderTableMeta.CONTENT_URI_UPLOADS,
|
||||
null,
|
||||
ProviderTableMeta._ID + "=?",
|
||||
new String[]{String.valueOf(id)},
|
||||
null
|
||||
);
|
||||
|
||||
if (c.getCount() != 1) {
|
||||
Log_OC.e(TAG, c.getCount() + " items for id=" + id
|
||||
+ " available in UploadDb. Expected 1. Failed to update upload db.");
|
||||
} else {
|
||||
returnValue = updateUploadInternal(c, status, result, remotePath, localPath);
|
||||
}
|
||||
c.close();
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Should be called when some value of this DB was changed. All observers
|
||||
* are informed.
|
||||
*/
|
||||
public void notifyObserversNow() {
|
||||
Log_OC.d(TAG, "notifyObserversNow");
|
||||
setChanged();
|
||||
notifyObservers();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Remove an upload from the uploads list, known its target account and remote path.
|
||||
*
|
||||
* @param upload Upload instance to remove from persisted storage.
|
||||
*
|
||||
* @return true when the upload was stored and could be removed.
|
||||
*/
|
||||
public int removeUpload(OCUpload upload) {
|
||||
int result = getDB().delete(
|
||||
ProviderTableMeta.CONTENT_URI_UPLOADS,
|
||||
ProviderTableMeta._ID + "=?" ,
|
||||
new String[]{Long.toString(upload.getUploadId())}
|
||||
);
|
||||
Log_OC.d(TAG, "delete returns " + result + " for upload " + upload);
|
||||
if (result > 0) {
|
||||
notifyObserversNow();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Remove an upload from the uploads list, known its target account and remote path.
|
||||
*
|
||||
* @param accountName Name of the OC account target of the upload to remove.
|
||||
* @param remotePath Absolute path in the OC account target of the upload to remove.
|
||||
* @return true when one or more upload entries were removed
|
||||
*/
|
||||
public int removeUpload(String accountName, String remotePath) {
|
||||
int result = getDB().delete(
|
||||
ProviderTableMeta.CONTENT_URI_UPLOADS,
|
||||
ProviderTableMeta.UPLOADS_ACCOUNT_NAME + "=? AND " + ProviderTableMeta.UPLOADS_REMOTE_PATH + "=?" ,
|
||||
new String[]{accountName, remotePath}
|
||||
);
|
||||
Log_OC.d(TAG, "delete returns " + result + " for file " + remotePath + " in " + accountName);
|
||||
if (result > 0) {
|
||||
notifyObserversNow();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Remove all the uploads of a given account from the uploads list.
|
||||
*
|
||||
* @param accountName Name of the OC account target of the uploads to remove.
|
||||
* @return true when one or more upload entries were removed
|
||||
*/
|
||||
public int removeUploads(String accountName) {
|
||||
int result = getDB().delete(
|
||||
ProviderTableMeta.CONTENT_URI_UPLOADS,
|
||||
ProviderTableMeta.UPLOADS_ACCOUNT_NAME + "=?",
|
||||
new String[]{accountName}
|
||||
);
|
||||
Log_OC.d(TAG, "delete returns " + result + " for uploads in " + accountName);
|
||||
if (result > 0) {
|
||||
notifyObserversNow();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public OCUpload[] getAllStoredUploads() {
|
||||
return getUploads(null, null);
|
||||
}
|
||||
|
||||
|
||||
private OCUpload[] getUploads(String selection, String[] selectionArgs) {
|
||||
Cursor c = getDB().query(
|
||||
ProviderTableMeta.CONTENT_URI_UPLOADS,
|
||||
null,
|
||||
selection,
|
||||
selectionArgs,
|
||||
null
|
||||
);
|
||||
OCUpload[] list = new OCUpload[c.getCount()];
|
||||
if (c.moveToFirst()) {
|
||||
do {
|
||||
OCUpload upload = createOCUploadFromCursor(c);
|
||||
if (upload == null) {
|
||||
Log_OC.e(TAG, "OCUpload could not be created from cursor");
|
||||
} else {
|
||||
list[c.getPosition()] = upload;
|
||||
}
|
||||
} while (c.moveToNext());
|
||||
|
||||
}
|
||||
c.close();
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
private OCUpload createOCUploadFromCursor(Cursor c) {
|
||||
OCUpload upload = null;
|
||||
if (c != null) {
|
||||
String localPath = c.getString(c.getColumnIndex(ProviderTableMeta.UPLOADS_LOCAL_PATH));
|
||||
String remotePath = c.getString(c.getColumnIndex(ProviderTableMeta.UPLOADS_REMOTE_PATH));
|
||||
String accountName = c.getString(c.getColumnIndex(ProviderTableMeta.UPLOADS_ACCOUNT_NAME));
|
||||
upload = new OCUpload(localPath, remotePath, accountName);
|
||||
|
||||
upload.setFileSize(c.getLong(c.getColumnIndex(ProviderTableMeta.UPLOADS_FILE_SIZE)));
|
||||
upload.setUploadId(c.getLong(c.getColumnIndex(ProviderTableMeta._ID)));
|
||||
upload.setUploadStatus(
|
||||
UploadStatus.fromValue(c.getInt(c.getColumnIndex(ProviderTableMeta.UPLOADS_STATUS)))
|
||||
);
|
||||
upload.setLocalAction(c.getInt(c.getColumnIndex((ProviderTableMeta.UPLOADS_LOCAL_BEHAVIOUR))));
|
||||
upload.setForceOverwrite(c.getInt(
|
||||
c.getColumnIndex(ProviderTableMeta.UPLOADS_FORCE_OVERWRITE)) == 1);
|
||||
upload.setCreateRemoteFolder(c.getInt(
|
||||
c.getColumnIndex(ProviderTableMeta.UPLOADS_IS_CREATE_REMOTE_FOLDER)) == 1);
|
||||
upload.setUploadEndTimestamp(c.getLong(c.getColumnIndex(ProviderTableMeta.UPLOADS_UPLOAD_END_TIMESTAMP)));
|
||||
upload.setLastResult(UploadResult.fromValue(
|
||||
c.getInt(c.getColumnIndex(ProviderTableMeta.UPLOADS_LAST_RESULT))));
|
||||
upload.setCreatedBy(c.getInt(c.getColumnIndex(ProviderTableMeta.UPLOADS_CREATED_BY)));
|
||||
}
|
||||
return upload;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all uploads which are currently being uploaded or waiting in the queue to be uploaded.
|
||||
*/
|
||||
public OCUpload[] getCurrentAndPendingUploads() {
|
||||
return getUploads(ProviderTableMeta.UPLOADS_STATUS + "==" + UploadStatus.UPLOAD_IN_PROGRESS.value, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all unrecoverably failed. Upload of these should/must/will not be
|
||||
* retried.
|
||||
*/
|
||||
public OCUpload[] getFailedUploads() {
|
||||
return getUploads(ProviderTableMeta.UPLOADS_STATUS + "==" + UploadStatus.UPLOAD_FAILED.value, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all uploads which where successfully completed.
|
||||
*/
|
||||
public OCUpload[] getFinishedUploads() {
|
||||
return getUploads(ProviderTableMeta.UPLOADS_STATUS + "==" + UploadStatus.UPLOAD_SUCCEEDED.value, null);
|
||||
}
|
||||
|
||||
private ContentResolver getDB() {
|
||||
return mContentResolver;
|
||||
}
|
||||
|
||||
public long clearFailedUploads() {
|
||||
long result = getDB().delete(
|
||||
ProviderTableMeta.CONTENT_URI_UPLOADS,
|
||||
ProviderTableMeta.UPLOADS_STATUS + "==" + UploadStatus.UPLOAD_FAILED.value, null
|
||||
);
|
||||
Log_OC.d(TAG, "delete all failed uploads");
|
||||
if (result > 0) {
|
||||
notifyObserversNow();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public long clearSuccessfulUploads() {
|
||||
long result = getDB().delete(
|
||||
ProviderTableMeta.CONTENT_URI_UPLOADS,
|
||||
ProviderTableMeta.UPLOADS_STATUS + "=="+ UploadStatus.UPLOAD_SUCCEEDED.value, null
|
||||
);
|
||||
Log_OC.d(TAG, "delete all successful uploads");
|
||||
if (result > 0) {
|
||||
notifyObserversNow();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public long clearAllFinishedUploads() {
|
||||
String[] whereArgs = new String[2];
|
||||
whereArgs[0] = String.valueOf(UploadStatus.UPLOAD_SUCCEEDED.value);
|
||||
whereArgs[1] = String.valueOf(UploadStatus.UPLOAD_FAILED.value);
|
||||
long result = getDB().delete(
|
||||
ProviderTableMeta.CONTENT_URI_UPLOADS,
|
||||
ProviderTableMeta.UPLOADS_STATUS + "=? OR " + ProviderTableMeta.UPLOADS_STATUS + "=?",
|
||||
whereArgs
|
||||
);
|
||||
Log_OC.d(TAG, "delete all finished uploads");
|
||||
if (result > 0) {
|
||||
notifyObserversNow();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the persistent upload database with upload result.
|
||||
*/
|
||||
public void updateDatabaseUploadResult(RemoteOperationResult uploadResult, UploadFileOperation upload) {
|
||||
// result: success or fail notification
|
||||
Log_OC.d(TAG, "updateDataseUploadResult uploadResult: " + uploadResult + " upload: " + upload);
|
||||
|
||||
if (uploadResult.isCancelled()) {
|
||||
removeUpload(
|
||||
upload.getAccount().name,
|
||||
upload.getRemotePath()
|
||||
);
|
||||
} else {
|
||||
String localPath = (FileUploader.LOCAL_BEHAVIOUR_MOVE == upload.getLocalBehaviour())
|
||||
? upload.getStoragePath() : null;
|
||||
|
||||
if (uploadResult.isSuccess()) {
|
||||
updateUploadStatus(
|
||||
upload.getOCUploadId(),
|
||||
UploadStatus.UPLOAD_SUCCEEDED,
|
||||
UploadResult.UPLOADED,
|
||||
upload.getRemotePath(),
|
||||
localPath
|
||||
);
|
||||
} else {
|
||||
updateUploadStatus(
|
||||
upload.getOCUploadId(),
|
||||
UploadStatus.UPLOAD_FAILED,
|
||||
UploadResult.fromOperationResult(uploadResult),
|
||||
upload.getRemotePath(),
|
||||
localPath
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the persistent upload database with an upload now in progress.
|
||||
*/
|
||||
public void updateDatabaseUploadStart(UploadFileOperation upload) {
|
||||
String localPath = (FileUploader.LOCAL_BEHAVIOUR_MOVE == upload.getLocalBehaviour())
|
||||
? upload.getStoragePath() : null;
|
||||
|
||||
updateUploadStatus(
|
||||
upload.getOCUploadId(),
|
||||
UploadStatus.UPLOAD_IN_PROGRESS,
|
||||
UploadResult.UNKNOWN,
|
||||
upload.getRemotePath(),
|
||||
localPath
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Changes the status of any in progress upload from UploadStatus.UPLOAD_IN_PROGRESS
|
||||
* to UploadStatus.UPLOAD_FAILED
|
||||
*
|
||||
* @return Number of uploads which status was changed.
|
||||
*/
|
||||
public int failInProgressUploads(UploadResult fail) {
|
||||
Log_OC.v(TAG, "Updating state of any killed upload");
|
||||
|
||||
ContentValues cv = new ContentValues();
|
||||
cv.put(ProviderTableMeta.UPLOADS_STATUS, UploadStatus.UPLOAD_FAILED.getValue());
|
||||
cv.put(
|
||||
ProviderTableMeta.UPLOADS_LAST_RESULT,
|
||||
fail != null ? fail.getValue() : UploadResult.UNKNOWN.getValue()
|
||||
);
|
||||
cv.put(ProviderTableMeta.UPLOADS_UPLOAD_END_TIMESTAMP, Calendar.getInstance().getTimeInMillis());
|
||||
|
||||
int result = getDB().update(
|
||||
ProviderTableMeta.CONTENT_URI_UPLOADS,
|
||||
cv,
|
||||
ProviderTableMeta.UPLOADS_STATUS + "=?",
|
||||
new String[]{String.valueOf(UploadStatus.UPLOAD_IN_PROGRESS.getValue())}
|
||||
);
|
||||
|
||||
if (result == 0) {
|
||||
Log_OC.v(TAG, "No upload was killed");
|
||||
} else {
|
||||
Log_OC.w(TAG, Integer.toString(result) + " uploads where abruptly interrupted");
|
||||
notifyObserversNow();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,127 +0,0 @@
|
|||
/**
|
||||
* ownCloud Android client application
|
||||
*
|
||||
* @author Bartek Przybylski
|
||||
* Copyright (C) 2011-2012 Bartek Przybylski
|
||||
* Copyright (C) 2015 ownCloud Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package com.owncloud.android.db;
|
||||
|
||||
import com.owncloud.android.MainApp;
|
||||
import com.owncloud.android.lib.common.utils.Log_OC;
|
||||
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.database.sqlite.SQLiteOpenHelper;
|
||||
|
||||
/**
|
||||
* Custom database helper for ownCloud
|
||||
*/
|
||||
public class DbHandler {
|
||||
private SQLiteDatabase mDB;
|
||||
private OpenerHelper mHelper;
|
||||
private final String mDatabaseName;
|
||||
private final int mDatabaseVersion = 3;
|
||||
|
||||
private final String TABLE_INSTANT_UPLOAD = "instant_upload";
|
||||
|
||||
public static final int UPLOAD_STATUS_UPLOAD_LATER = 0;
|
||||
public static final int UPLOAD_STATUS_UPLOAD_FAILED = 1;
|
||||
|
||||
public DbHandler(Context context) {
|
||||
mDatabaseName = MainApp.getDBName();
|
||||
mHelper = new OpenerHelper(context);
|
||||
mDB = mHelper.getWritableDatabase();
|
||||
}
|
||||
|
||||
public void close() {
|
||||
mDB.close();
|
||||
}
|
||||
|
||||
public boolean putFileForLater(String filepath, String account, String message) {
|
||||
ContentValues cv = new ContentValues();
|
||||
cv.put("path", filepath);
|
||||
cv.put("account", account);
|
||||
cv.put("attempt", UPLOAD_STATUS_UPLOAD_LATER);
|
||||
cv.put("message", message);
|
||||
long result = mDB.insert(TABLE_INSTANT_UPLOAD, null, cv);
|
||||
Log_OC.d(TABLE_INSTANT_UPLOAD, "putFileForLater returns with: " + result + " for file: " + filepath);
|
||||
return result != -1;
|
||||
}
|
||||
|
||||
public int updateFileState(String filepath, Integer status, String message) {
|
||||
ContentValues cv = new ContentValues();
|
||||
cv.put("attempt", status);
|
||||
cv.put("message", message);
|
||||
int result = mDB.update(TABLE_INSTANT_UPLOAD, cv, "path=?", new String[] { filepath });
|
||||
Log_OC.d(TABLE_INSTANT_UPLOAD, "updateFileState returns with: " + result + " for file: " + filepath);
|
||||
return result;
|
||||
}
|
||||
|
||||
public Cursor getAwaitingFiles() {
|
||||
return mDB.query(TABLE_INSTANT_UPLOAD, null, "attempt=" + UPLOAD_STATUS_UPLOAD_LATER, null, null, null, null);
|
||||
}
|
||||
|
||||
public Cursor getFailedFiles() {
|
||||
return mDB.query(TABLE_INSTANT_UPLOAD, null, "attempt>" + UPLOAD_STATUS_UPLOAD_LATER, null, null, null, null);
|
||||
}
|
||||
|
||||
public void clearFiles() {
|
||||
mDB.delete(TABLE_INSTANT_UPLOAD, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param localPath
|
||||
* @return true when one or more pending files was removed
|
||||
*/
|
||||
public boolean removeIUPendingFile(String localPath) {
|
||||
long result = mDB.delete(TABLE_INSTANT_UPLOAD, "path = ?", new String[] { localPath });
|
||||
Log_OC.d(TABLE_INSTANT_UPLOAD, "delete returns with: " + result + " for file: " + localPath);
|
||||
return result != 0;
|
||||
|
||||
}
|
||||
|
||||
private class OpenerHelper extends SQLiteOpenHelper {
|
||||
public OpenerHelper(Context context) {
|
||||
super(context, mDatabaseName, null, mDatabaseVersion);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(SQLiteDatabase db) {
|
||||
db.execSQL("CREATE TABLE " + TABLE_INSTANT_UPLOAD + " (" + " _id INTEGER PRIMARY KEY, " + " path TEXT,"
|
||||
+ " account TEXT,attempt INTEGER,message TEXT);");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
||||
if (oldVersion < 2) {
|
||||
db.execSQL("ALTER TABLE " + TABLE_INSTANT_UPLOAD + " ADD COLUMN attempt INTEGER;");
|
||||
}
|
||||
db.execSQL("ALTER TABLE " + TABLE_INSTANT_UPLOAD + " ADD COLUMN message TEXT;");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
||||
//downgrading is the exception, so deleting and re-creating is acceptable.
|
||||
//otherwise exception will be thrown (cannot downgrade) and oc app will crash.
|
||||
db.execSQL("DROP TABLE IF EXISTS " + TABLE_INSTANT_UPLOAD + ";");
|
||||
onCreate(db);
|
||||
}
|
||||
}
|
||||
}
|
427
src/com/owncloud/android/db/OCUpload.java
Normal file
|
@ -0,0 +1,427 @@
|
|||
/**
|
||||
* ownCloud Android client application
|
||||
*
|
||||
* @author LukeOwncloud
|
||||
* @author masensio
|
||||
* @author David A. Velasco
|
||||
* Copyright (C) 2016 ownCloud Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.owncloud.android.db;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.content.Context;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import com.owncloud.android.authentication.AccountUtils;
|
||||
import com.owncloud.android.datamodel.OCFile;
|
||||
import com.owncloud.android.datamodel.UploadsStorageManager;
|
||||
import com.owncloud.android.datamodel.UploadsStorageManager.UploadStatus;
|
||||
import com.owncloud.android.files.services.FileUploader;
|
||||
import com.owncloud.android.lib.common.utils.Log_OC;
|
||||
import com.owncloud.android.operations.UploadFileOperation;
|
||||
import com.owncloud.android.utils.MimetypeIconUtil;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* Stores all information in order to start upload operations. PersistentUploadObject can
|
||||
* be stored persistently by {@link UploadsStorageManager}.
|
||||
*
|
||||
*/
|
||||
public class OCUpload implements Parcelable {
|
||||
|
||||
private static final String TAG = OCUpload.class.getSimpleName();
|
||||
|
||||
private long mId;
|
||||
|
||||
/**
|
||||
* Absolute path in the local file system to the file to be uploaded
|
||||
*/
|
||||
private String mLocalPath;
|
||||
|
||||
/**
|
||||
* Absolute path in the remote account to set to the uploaded file (not for its parent folder!)
|
||||
*/
|
||||
private String mRemotePath;
|
||||
|
||||
/**
|
||||
* Name of Owncloud account to upload file to.
|
||||
*/
|
||||
private String mAccountName;
|
||||
|
||||
/**
|
||||
* File size
|
||||
*/
|
||||
private long mFileSize;
|
||||
|
||||
/**
|
||||
* Local action for upload. (0 - COPY, 1 - MOVE, 2 - FORGET)
|
||||
*/
|
||||
private int mLocalAction;
|
||||
|
||||
/**
|
||||
* Overwrite destination file?
|
||||
*/
|
||||
private boolean mForceOverwrite;
|
||||
/**
|
||||
* Create destination folder?
|
||||
*/
|
||||
private boolean mIsCreateRemoteFolder;
|
||||
/**
|
||||
* Status of upload (later, in_progress, ...).
|
||||
*/
|
||||
private UploadStatus mUploadStatus;
|
||||
/**
|
||||
* Result from last upload operation. Can be null.
|
||||
*/
|
||||
private UploadResult mLastResult;
|
||||
|
||||
/**
|
||||
* Defines the origin of the upload; see constants CREATED_ in {@link UploadFileOperation}
|
||||
*/
|
||||
private int mCreatedBy;
|
||||
|
||||
/*
|
||||
* When the upload ended
|
||||
*/
|
||||
private long mUploadEndTimeStamp;
|
||||
|
||||
|
||||
/**
|
||||
* Main constructor
|
||||
*
|
||||
* @param localPath Absolute path in the local file system to the file to be uploaded.
|
||||
* @param remotePath Absolute path in the remote account to set to the uploaded file.
|
||||
* @param accountName Name of an ownCloud account to update the file to.
|
||||
*/
|
||||
public OCUpload(String localPath, String remotePath, String accountName) {
|
||||
if (localPath == null || !localPath.startsWith(File.separator)) {
|
||||
throw new IllegalArgumentException("Local path must be an absolute path in the local file system");
|
||||
}
|
||||
if (remotePath == null || !remotePath.startsWith(OCFile.PATH_SEPARATOR)) {
|
||||
throw new IllegalArgumentException("Remote path must be an absolute path in the local file system");
|
||||
}
|
||||
if (accountName == null || accountName.length() < 1) {
|
||||
throw new IllegalArgumentException("Invalid account name");
|
||||
}
|
||||
resetData();
|
||||
mLocalPath = localPath;
|
||||
mRemotePath = remotePath;
|
||||
mAccountName = accountName;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convenience constructor to reupload already existing {@link OCFile}s
|
||||
*
|
||||
* @param ocFile {@link OCFile} instance to update in the remote server.
|
||||
* @param account ownCloud {@link Account} where ocFile is contained.
|
||||
*/
|
||||
public OCUpload(OCFile ocFile, Account account) {
|
||||
this(ocFile.getStoragePath(), ocFile.getRemotePath(), account.name);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reset all the fields to default values.
|
||||
*/
|
||||
private void resetData() {
|
||||
mRemotePath = "";
|
||||
mLocalPath = "";
|
||||
mAccountName = "";
|
||||
mFileSize = -1;
|
||||
mId = -1;
|
||||
mLocalAction = FileUploader.LOCAL_BEHAVIOUR_COPY;
|
||||
mForceOverwrite = false;
|
||||
mIsCreateRemoteFolder = false;
|
||||
mUploadStatus = UploadStatus.UPLOAD_IN_PROGRESS;
|
||||
mLastResult = UploadResult.UNKNOWN;
|
||||
mCreatedBy = UploadFileOperation.CREATED_BY_USER;
|
||||
}
|
||||
|
||||
// Getters & Setters
|
||||
public void setUploadId(long id) {
|
||||
mId = id;
|
||||
}
|
||||
public long getUploadId() {
|
||||
return mId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the uploadStatus
|
||||
*/
|
||||
public UploadStatus getUploadStatus() {
|
||||
return mUploadStatus;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets uploadStatus AND SETS lastResult = null;
|
||||
* @param uploadStatus the uploadStatus to set
|
||||
*/
|
||||
public void setUploadStatus(UploadStatus uploadStatus) {
|
||||
this.mUploadStatus = uploadStatus;
|
||||
setLastResult(UploadResult.UNKNOWN);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the lastResult
|
||||
*/
|
||||
public UploadResult getLastResult() {
|
||||
return mLastResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param lastResult the lastResult to set
|
||||
*/
|
||||
public void setLastResult(UploadResult lastResult) {
|
||||
this.mLastResult = ((lastResult != null) ? lastResult : UploadResult.UNKNOWN);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the localPath
|
||||
*/
|
||||
public String getLocalPath() {
|
||||
return mLocalPath;
|
||||
}
|
||||
|
||||
public void setLocalPath(String localPath) {
|
||||
mLocalPath = localPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the remotePath
|
||||
*/
|
||||
public String getRemotePath() {
|
||||
return mRemotePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param remotePath
|
||||
*/
|
||||
public void setRemotePath(String remotePath) {
|
||||
mRemotePath = remotePath;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return File size
|
||||
*/
|
||||
public long getFileSize() {
|
||||
return mFileSize;
|
||||
}
|
||||
|
||||
public void setFileSize(long fileSize) {
|
||||
mFileSize = fileSize;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the mimeType
|
||||
*/
|
||||
public String getMimeType() {
|
||||
return MimetypeIconUtil.getBestMimeTypeByFilename(mLocalPath);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the localAction
|
||||
*/
|
||||
public int getLocalAction() {
|
||||
return mLocalAction;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param localAction the localAction to set
|
||||
*/
|
||||
public void setLocalAction(int localAction) {
|
||||
this.mLocalAction = localAction;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the forceOverwrite
|
||||
*/
|
||||
public boolean isForceOverwrite() {
|
||||
return mForceOverwrite;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param forceOverwrite the forceOverwrite to set
|
||||
*/
|
||||
public void setForceOverwrite(boolean forceOverwrite) {
|
||||
this.mForceOverwrite = forceOverwrite;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the isCreateRemoteFolder
|
||||
*/
|
||||
public boolean isCreateRemoteFolder() {
|
||||
return mIsCreateRemoteFolder;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param isCreateRemoteFolder the isCreateRemoteFolder to set
|
||||
*/
|
||||
public void setCreateRemoteFolder(boolean isCreateRemoteFolder) {
|
||||
this.mIsCreateRemoteFolder = isCreateRemoteFolder;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the accountName
|
||||
*/
|
||||
public String getAccountName() {
|
||||
return mAccountName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns owncloud account as {@link Account} object.
|
||||
*/
|
||||
public Account getAccount(Context context) {
|
||||
return AccountUtils.getOwnCloudAccountByName(context, getAccountName());
|
||||
}
|
||||
|
||||
public void setCreatedBy(int createdBy) {
|
||||
mCreatedBy = createdBy;
|
||||
}
|
||||
|
||||
public int getCreadtedBy() {
|
||||
return mCreatedBy;
|
||||
}
|
||||
|
||||
public void setUploadEndTimestamp(long uploadEndTimestamp) {
|
||||
mUploadEndTimeStamp = uploadEndTimestamp;
|
||||
}
|
||||
|
||||
public long getUploadEndTimestamp(){
|
||||
return mUploadEndTimeStamp;
|
||||
}
|
||||
|
||||
/**
|
||||
* For debugging purposes only.
|
||||
*/
|
||||
public String toFormattedString() {
|
||||
try {
|
||||
String localPath = getLocalPath() != null ? getLocalPath() : "";
|
||||
return localPath + " status:" + getUploadStatus() + " result:" +
|
||||
(getLastResult() == null ? "null" : getLastResult().getValue());
|
||||
} catch (NullPointerException e){
|
||||
Log_OC.d(TAG, "Exception " + e.toString() );
|
||||
return (e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
/****
|
||||
*
|
||||
*/
|
||||
public static final Parcelable.Creator<OCUpload> CREATOR = new Parcelable.Creator<OCUpload>() {
|
||||
|
||||
@Override
|
||||
public OCUpload createFromParcel(Parcel source) {
|
||||
return new OCUpload(source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public OCUpload[] newArray(int size) {
|
||||
return new OCUpload[size];
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Reconstruct from parcel
|
||||
*
|
||||
* @param source The source parcel
|
||||
*/
|
||||
protected OCUpload(Parcel source) {
|
||||
readFromParcel(source);
|
||||
}
|
||||
|
||||
public void readFromParcel(Parcel source) {
|
||||
mId = source.readLong();
|
||||
mLocalPath = source.readString();
|
||||
mRemotePath = source.readString();
|
||||
mAccountName = source.readString();
|
||||
mLocalAction = source.readInt();
|
||||
mForceOverwrite = (source.readInt() == 1);
|
||||
mIsCreateRemoteFolder = (source.readInt() == 1);
|
||||
try {
|
||||
mUploadStatus = UploadStatus.valueOf(source.readString());
|
||||
} catch (IllegalArgumentException x) {
|
||||
mUploadStatus = UploadStatus.UPLOAD_IN_PROGRESS;
|
||||
}
|
||||
mUploadEndTimeStamp = source.readLong();
|
||||
try {
|
||||
mLastResult = UploadResult.valueOf(source.readString());
|
||||
} catch (IllegalArgumentException x) {
|
||||
mLastResult = UploadResult.UNKNOWN;
|
||||
}
|
||||
mCreatedBy = source.readInt();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return this.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeLong(mId);
|
||||
dest.writeString(mLocalPath);
|
||||
dest.writeString(mRemotePath);
|
||||
dest.writeString(mAccountName);
|
||||
dest.writeInt(mLocalAction);
|
||||
dest.writeInt(mForceOverwrite ? 1 : 0);
|
||||
dest.writeInt(mIsCreateRemoteFolder ? 1 : 0);
|
||||
dest.writeString(mUploadStatus.name());
|
||||
dest.writeLong(mUploadEndTimeStamp);
|
||||
dest.writeString(((mLastResult == null) ? "" : mLastResult.name()));
|
||||
dest.writeInt(mCreatedBy);
|
||||
}
|
||||
|
||||
enum CanUploadFileNowStatus {NOW, LATER, FILE_GONE, ERROR};
|
||||
|
||||
/**
|
||||
* Returns true when the file may be uploaded now. This methods checks all
|
||||
* restraints of the passed {@link OCUpload}, these include
|
||||
* isUseWifiOnly(), check if local file exists, check if file was already
|
||||
* uploaded...
|
||||
*
|
||||
* If return value is CanUploadFileNowStatus.NOW, uploadFile() may be
|
||||
* called.
|
||||
*
|
||||
* @return CanUploadFileNowStatus.NOW is upload may proceed, <br>
|
||||
* CanUploadFileNowStatus.LATER if upload should be performed at a
|
||||
* later time, <br>
|
||||
* CanUploadFileNowStatus.ERROR if a severe error happened, calling
|
||||
* entity should remove upload from queue.
|
||||
*
|
||||
*/
|
||||
private CanUploadFileNowStatus canUploadFileNow(Context context) {
|
||||
|
||||
if (getUploadStatus() == UploadStatus.UPLOAD_SUCCEEDED) {
|
||||
Log_OC.w(TAG, "Already succeeded uploadObject was again scheduled for upload. Fix that!");
|
||||
return CanUploadFileNowStatus.ERROR;
|
||||
}
|
||||
|
||||
if (!new File(getLocalPath()).exists()) {
|
||||
Log_OC.d(TAG, "Do not start upload because local file does not exist.");
|
||||
return CanUploadFileNowStatus.FILE_GONE;
|
||||
}
|
||||
return CanUploadFileNowStatus.NOW;
|
||||
}
|
||||
|
||||
}
|
59
src/com/owncloud/android/db/PreferenceReader.java
Normal file
|
@ -0,0 +1,59 @@
|
|||
/**
|
||||
* ownCloud Android client application
|
||||
*
|
||||
* @author David A. Velasco
|
||||
* Copyright (C) 2016 ownCloud Inc.
|
||||
* <p/>
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
* <p/>
|
||||
* 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 General Public License for more details.
|
||||
* <p/>
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.owncloud.android.db;
|
||||
|
||||
import android.content.Context;
|
||||
import android.preference.PreferenceManager;
|
||||
|
||||
/**
|
||||
* Helper to simplify reading of Preferences all around the app
|
||||
*/
|
||||
|
||||
public class PreferenceReader {
|
||||
|
||||
public static boolean instantPictureUploadEnabled(Context context) {
|
||||
return PreferenceManager.getDefaultSharedPreferences(context).getBoolean(
|
||||
"instant_uploading",
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
public static boolean instantVideoUploadEnabled(Context context) {
|
||||
return PreferenceManager.getDefaultSharedPreferences(context).getBoolean(
|
||||
"instant_video_uploading",
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
public static boolean instantPictureUploadViaWiFiOnly(Context context) {
|
||||
return PreferenceManager.getDefaultSharedPreferences(context).getBoolean(
|
||||
"instant_upload_on_wifi",
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
public static boolean instantVideoUploadViaWiFiOnly(Context context) {
|
||||
return PreferenceManager.getDefaultSharedPreferences(context).getBoolean(
|
||||
"instant_video_upload_on_wifi",
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,133 +1,155 @@
|
|||
/**
|
||||
* ownCloud Android client application
|
||||
*
|
||||
* @author Bartek Przybylski
|
||||
* Copyright (C) 2011 Bartek Przybylski
|
||||
* Copyright (C) 2015 ownCloud Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package com.owncloud.android.db;
|
||||
|
||||
import android.net.Uri;
|
||||
import android.provider.BaseColumns;
|
||||
|
||||
import com.owncloud.android.MainApp;
|
||||
|
||||
/**
|
||||
* Meta-Class that holds various static field information
|
||||
*/
|
||||
public class ProviderMeta {
|
||||
|
||||
public static final String DB_NAME = "filelist";
|
||||
public static final int DB_VERSION = 13;
|
||||
|
||||
private ProviderMeta() {
|
||||
}
|
||||
|
||||
static public class ProviderTableMeta implements BaseColumns {
|
||||
public static final String FILE_TABLE_NAME = "filelist";
|
||||
public static final String OCSHARES_TABLE_NAME = "ocshares";
|
||||
public static final String CAPABILITIES_TABLE_NAME = "capabilities";
|
||||
public static final Uri CONTENT_URI = Uri.parse("content://"
|
||||
+ MainApp.getAuthority() + "/");
|
||||
public static final Uri CONTENT_URI_FILE = Uri.parse("content://"
|
||||
+ MainApp.getAuthority() + "/file");
|
||||
public static final Uri CONTENT_URI_DIR = Uri.parse("content://"
|
||||
+ MainApp.getAuthority() + "/dir");
|
||||
public static final Uri CONTENT_URI_SHARE = Uri.parse("content://"
|
||||
+ MainApp.getAuthority() + "/shares");
|
||||
public static final Uri CONTENT_URI_CAPABILITIES = Uri.parse("content://"
|
||||
+ MainApp.getAuthority() + "/capabilities");
|
||||
|
||||
public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.owncloud.file";
|
||||
public static final String CONTENT_TYPE_ITEM = "vnd.android.cursor.item/vnd.owncloud.file";
|
||||
|
||||
// Columns of filelist table
|
||||
public static final String FILE_PARENT = "parent";
|
||||
public static final String FILE_NAME = "filename";
|
||||
public static final String FILE_CREATION = "created";
|
||||
public static final String FILE_MODIFIED = "modified";
|
||||
public static final String FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA = "modified_at_last_sync_for_data";
|
||||
public static final String FILE_CONTENT_LENGTH = "content_length";
|
||||
public static final String FILE_CONTENT_TYPE = "content_type";
|
||||
public static final String FILE_STORAGE_PATH = "media_path";
|
||||
public static final String FILE_PATH = "path";
|
||||
public static final String FILE_ACCOUNT_OWNER = "file_owner";
|
||||
public static final String FILE_LAST_SYNC_DATE = "last_sync_date";// _for_properties, but let's keep it as it is
|
||||
public static final String FILE_LAST_SYNC_DATE_FOR_DATA = "last_sync_date_for_data";
|
||||
public static final String FILE_KEEP_IN_SYNC = "keep_in_sync";
|
||||
public static final String FILE_ETAG = "etag";
|
||||
public static final String FILE_SHARED_VIA_LINK = "share_by_link";
|
||||
public static final String FILE_SHARED_WITH_SHAREE = "shared_via_users";
|
||||
public static final String FILE_PUBLIC_LINK = "public_link";
|
||||
public static final String FILE_PERMISSIONS = "permissions";
|
||||
public static final String FILE_REMOTE_ID = "remote_id";
|
||||
public static final String FILE_UPDATE_THUMBNAIL = "update_thumbnail";
|
||||
public static final String FILE_IS_DOWNLOADING= "is_downloading";
|
||||
public static final String FILE_ETAG_IN_CONFLICT = "etag_in_conflict";
|
||||
|
||||
public static final String FILE_DEFAULT_SORT_ORDER = FILE_NAME
|
||||
+ " collate nocase asc";
|
||||
|
||||
// Columns of ocshares table
|
||||
public static final String OCSHARES_FILE_SOURCE = "file_source";
|
||||
public static final String OCSHARES_ITEM_SOURCE = "item_source";
|
||||
public static final String OCSHARES_SHARE_TYPE = "share_type";
|
||||
public static final String OCSHARES_SHARE_WITH = "shate_with";
|
||||
public static final String OCSHARES_PATH = "path";
|
||||
public static final String OCSHARES_PERMISSIONS = "permissions";
|
||||
public static final String OCSHARES_SHARED_DATE = "shared_date";
|
||||
public static final String OCSHARES_EXPIRATION_DATE = "expiration_date";
|
||||
public static final String OCSHARES_TOKEN = "token";
|
||||
public static final String OCSHARES_SHARE_WITH_DISPLAY_NAME = "shared_with_display_name";
|
||||
public static final String OCSHARES_IS_DIRECTORY = "is_directory";
|
||||
public static final String OCSHARES_USER_ID = "user_id";
|
||||
public static final String OCSHARES_ID_REMOTE_SHARED = "id_remote_shared";
|
||||
public static final String OCSHARES_ACCOUNT_OWNER = "owner_share";
|
||||
|
||||
public static final String OCSHARES_DEFAULT_SORT_ORDER = OCSHARES_FILE_SOURCE
|
||||
+ " collate nocase asc";
|
||||
|
||||
// Columns of capabilities table
|
||||
public static final String CAPABILITIES_ACCOUNT_NAME = "account";
|
||||
public static final String CAPABILITIES_VERSION_MAYOR = "version_mayor";
|
||||
public static final String CAPABILITIES_VERSION_MINOR = "version_minor";
|
||||
public static final String CAPABILITIES_VERSION_MICRO = "version_micro";
|
||||
public static final String CAPABILITIES_VERSION_STRING = "version_string";
|
||||
public static final String CAPABILITIES_VERSION_EDITION = "version_edition";
|
||||
public static final String CAPABILITIES_CORE_POLLINTERVAL = "core_pollinterval";
|
||||
public static final String CAPABILITIES_SHARING_API_ENABLED = "sharing_api_enabled";
|
||||
public static final String CAPABILITIES_SHARING_PUBLIC_ENABLED = "sharing_public_enabled";
|
||||
public static final String CAPABILITIES_SHARING_PUBLIC_PASSWORD_ENFORCED = "sharing_public_password_enforced";
|
||||
public static final String CAPABILITIES_SHARING_PUBLIC_EXPIRE_DATE_ENABLED =
|
||||
"sharing_public_expire_date_enabled";
|
||||
public static final String CAPABILITIES_SHARING_PUBLIC_EXPIRE_DATE_DAYS =
|
||||
"sharing_public_expire_date_days";
|
||||
public static final String CAPABILITIES_SHARING_PUBLIC_EXPIRE_DATE_ENFORCED =
|
||||
"sharing_public_expire_date_enforced";
|
||||
public static final String CAPABILITIES_SHARING_PUBLIC_SEND_MAIL = "sharing_public_send_mail";
|
||||
public static final String CAPABILITIES_SHARING_PUBLIC_UPLOAD = "sharing_public_upload";
|
||||
public static final String CAPABILITIES_SHARING_USER_SEND_MAIL = "sharing_user_send_mail";
|
||||
public static final String CAPABILITIES_SHARING_RESHARING = "sharing_resharing";
|
||||
public static final String CAPABILITIES_SHARING_FEDERATION_OUTGOING = "sharing_federation_outgoing";
|
||||
public static final String CAPABILITIES_SHARING_FEDERATION_INCOMING = "sharing_federation_incoming";
|
||||
public static final String CAPABILITIES_FILES_BIGFILECHUNKING = "files_bigfilechunking";
|
||||
public static final String CAPABILITIES_FILES_UNDELETE = "files_undelete";
|
||||
public static final String CAPABILITIES_FILES_VERSIONING = "files_versioning";
|
||||
|
||||
public static final String CAPABILITIES_DEFAULT_SORT_ORDER = CAPABILITIES_ACCOUNT_NAME
|
||||
+ " collate nocase asc";
|
||||
}
|
||||
}
|
||||
/**
|
||||
* ownCloud Android client application
|
||||
*
|
||||
* @author Bartek Przybylski
|
||||
* @author David A. Velasco
|
||||
* @author masensio
|
||||
* Copyright (C) 2011 Bartek Przybylski
|
||||
* Copyright (C) 2016 ownCloud Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package com.owncloud.android.db;
|
||||
|
||||
import android.net.Uri;
|
||||
import android.provider.BaseColumns;
|
||||
|
||||
import com.owncloud.android.MainApp;
|
||||
|
||||
/**
|
||||
* Meta-Class that holds various static field information
|
||||
*/
|
||||
public class ProviderMeta {
|
||||
|
||||
public static final String DB_NAME = "filelist";
|
||||
public static final int DB_VERSION = 14;
|
||||
|
||||
private ProviderMeta() {
|
||||
}
|
||||
|
||||
static public class ProviderTableMeta implements BaseColumns {
|
||||
public static final String FILE_TABLE_NAME = "filelist";
|
||||
public static final String OCSHARES_TABLE_NAME = "ocshares";
|
||||
public static final String CAPABILITIES_TABLE_NAME = "capabilities";
|
||||
public static final String UPLOADS_TABLE_NAME = "list_of_uploads";
|
||||
public static final Uri CONTENT_URI = Uri.parse("content://"
|
||||
+ MainApp.getAuthority() + "/");
|
||||
public static final Uri CONTENT_URI_FILE = Uri.parse("content://"
|
||||
+ MainApp.getAuthority() + "/file");
|
||||
public static final Uri CONTENT_URI_DIR = Uri.parse("content://"
|
||||
+ MainApp.getAuthority() + "/dir");
|
||||
public static final Uri CONTENT_URI_SHARE = Uri.parse("content://"
|
||||
+ MainApp.getAuthority() + "/shares");
|
||||
public static final Uri CONTENT_URI_CAPABILITIES = Uri.parse("content://"
|
||||
+ MainApp.getAuthority() + "/capabilities");
|
||||
public static final Uri CONTENT_URI_UPLOADS = Uri.parse("content://"
|
||||
+ MainApp.getAuthority() + "/uploads");
|
||||
|
||||
public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.owncloud.file";
|
||||
public static final String CONTENT_TYPE_ITEM = "vnd.android.cursor.item/vnd.owncloud.file";
|
||||
|
||||
// Columns of filelist table
|
||||
public static final String FILE_PARENT = "parent";
|
||||
public static final String FILE_NAME = "filename";
|
||||
public static final String FILE_CREATION = "created";
|
||||
public static final String FILE_MODIFIED = "modified";
|
||||
public static final String FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA = "modified_at_last_sync_for_data";
|
||||
public static final String FILE_CONTENT_LENGTH = "content_length";
|
||||
public static final String FILE_CONTENT_TYPE = "content_type";
|
||||
public static final String FILE_STORAGE_PATH = "media_path";
|
||||
public static final String FILE_PATH = "path";
|
||||
public static final String FILE_ACCOUNT_OWNER = "file_owner";
|
||||
public static final String FILE_LAST_SYNC_DATE = "last_sync_date";// _for_properties, but let's keep it as it is
|
||||
public static final String FILE_LAST_SYNC_DATE_FOR_DATA = "last_sync_date_for_data";
|
||||
public static final String FILE_KEEP_IN_SYNC = "keep_in_sync";
|
||||
public static final String FILE_ETAG = "etag";
|
||||
public static final String FILE_SHARED_VIA_LINK = "share_by_link";
|
||||
public static final String FILE_SHARED_WITH_SHAREE = "shared_via_users";
|
||||
public static final String FILE_PUBLIC_LINK = "public_link";
|
||||
public static final String FILE_PERMISSIONS = "permissions";
|
||||
public static final String FILE_REMOTE_ID = "remote_id";
|
||||
public static final String FILE_UPDATE_THUMBNAIL = "update_thumbnail";
|
||||
public static final String FILE_IS_DOWNLOADING= "is_downloading";
|
||||
public static final String FILE_ETAG_IN_CONFLICT = "etag_in_conflict";
|
||||
|
||||
public static final String FILE_DEFAULT_SORT_ORDER = FILE_NAME
|
||||
+ " collate nocase asc";
|
||||
|
||||
// Columns of ocshares table
|
||||
public static final String OCSHARES_FILE_SOURCE = "file_source";
|
||||
public static final String OCSHARES_ITEM_SOURCE = "item_source";
|
||||
public static final String OCSHARES_SHARE_TYPE = "share_type";
|
||||
public static final String OCSHARES_SHARE_WITH = "shate_with";
|
||||
public static final String OCSHARES_PATH = "path";
|
||||
public static final String OCSHARES_PERMISSIONS = "permissions";
|
||||
public static final String OCSHARES_SHARED_DATE = "shared_date";
|
||||
public static final String OCSHARES_EXPIRATION_DATE = "expiration_date";
|
||||
public static final String OCSHARES_TOKEN = "token";
|
||||
public static final String OCSHARES_SHARE_WITH_DISPLAY_NAME = "shared_with_display_name";
|
||||
public static final String OCSHARES_IS_DIRECTORY = "is_directory";
|
||||
public static final String OCSHARES_USER_ID = "user_id";
|
||||
public static final String OCSHARES_ID_REMOTE_SHARED = "id_remote_shared";
|
||||
public static final String OCSHARES_ACCOUNT_OWNER = "owner_share";
|
||||
|
||||
public static final String OCSHARES_DEFAULT_SORT_ORDER = OCSHARES_FILE_SOURCE
|
||||
+ " collate nocase asc";
|
||||
|
||||
// Columns of capabilities table
|
||||
public static final String CAPABILITIES_ACCOUNT_NAME = "account";
|
||||
public static final String CAPABILITIES_VERSION_MAYOR = "version_mayor";
|
||||
public static final String CAPABILITIES_VERSION_MINOR = "version_minor";
|
||||
public static final String CAPABILITIES_VERSION_MICRO = "version_micro";
|
||||
public static final String CAPABILITIES_VERSION_STRING = "version_string";
|
||||
public static final String CAPABILITIES_VERSION_EDITION = "version_edition";
|
||||
public static final String CAPABILITIES_CORE_POLLINTERVAL = "core_pollinterval";
|
||||
public static final String CAPABILITIES_SHARING_API_ENABLED = "sharing_api_enabled";
|
||||
public static final String CAPABILITIES_SHARING_PUBLIC_ENABLED = "sharing_public_enabled";
|
||||
public static final String CAPABILITIES_SHARING_PUBLIC_PASSWORD_ENFORCED = "sharing_public_password_enforced";
|
||||
public static final String CAPABILITIES_SHARING_PUBLIC_EXPIRE_DATE_ENABLED =
|
||||
"sharing_public_expire_date_enabled";
|
||||
public static final String CAPABILITIES_SHARING_PUBLIC_EXPIRE_DATE_DAYS =
|
||||
"sharing_public_expire_date_days";
|
||||
public static final String CAPABILITIES_SHARING_PUBLIC_EXPIRE_DATE_ENFORCED =
|
||||
"sharing_public_expire_date_enforced";
|
||||
public static final String CAPABILITIES_SHARING_PUBLIC_SEND_MAIL = "sharing_public_send_mail";
|
||||
public static final String CAPABILITIES_SHARING_PUBLIC_UPLOAD = "sharing_public_upload";
|
||||
public static final String CAPABILITIES_SHARING_USER_SEND_MAIL = "sharing_user_send_mail";
|
||||
public static final String CAPABILITIES_SHARING_RESHARING = "sharing_resharing";
|
||||
public static final String CAPABILITIES_SHARING_FEDERATION_OUTGOING = "sharing_federation_outgoing";
|
||||
public static final String CAPABILITIES_SHARING_FEDERATION_INCOMING = "sharing_federation_incoming";
|
||||
public static final String CAPABILITIES_FILES_BIGFILECHUNKING = "files_bigfilechunking";
|
||||
public static final String CAPABILITIES_FILES_UNDELETE = "files_undelete";
|
||||
public static final String CAPABILITIES_FILES_VERSIONING = "files_versioning";
|
||||
|
||||
public static final String CAPABILITIES_DEFAULT_SORT_ORDER = CAPABILITIES_ACCOUNT_NAME
|
||||
+ " collate nocase asc";
|
||||
|
||||
//Columns of Uploads table
|
||||
public static final String UPLOADS_LOCAL_PATH = "local_path";
|
||||
public static final String UPLOADS_REMOTE_PATH = "remote_path";
|
||||
public static final String UPLOADS_ACCOUNT_NAME = "account_name";
|
||||
public static final String UPLOADS_FILE_SIZE = "file_size";
|
||||
public static final String UPLOADS_STATUS = "status";
|
||||
public static final String UPLOADS_LOCAL_BEHAVIOUR = "local_behaviour";
|
||||
public static final String UPLOADS_UPLOAD_TIME = "upload_time";
|
||||
public static final String UPLOADS_FORCE_OVERWRITE = "force_overwrite";
|
||||
public static final String UPLOADS_IS_CREATE_REMOTE_FOLDER = "is_create_remote_folder";
|
||||
public static final String UPLOADS_UPLOAD_END_TIMESTAMP = "upload_end_timestamp";
|
||||
public static final String UPLOADS_LAST_RESULT = "last_result";
|
||||
public static final String UPLOADS_CREATED_BY = "created_by";
|
||||
|
||||
public static final String UPLOADS_DEFAULT_SORT_ORDER = ProviderTableMeta._ID + " collate nocase desc";
|
||||
|
||||
}
|
||||
}
|
||||
|
|
118
src/com/owncloud/android/db/UploadResult.java
Normal file
|
@ -0,0 +1,118 @@
|
|||
/**
|
||||
* ownCloud Android client application
|
||||
*
|
||||
* @author masensio
|
||||
* Copyright (C) 2016 ownCloud Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.owncloud.android.db;
|
||||
|
||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
|
||||
|
||||
public enum UploadResult {
|
||||
UNKNOWN(-1),
|
||||
UPLOADED(0),
|
||||
NETWORK_CONNECTION(1),
|
||||
CREDENTIAL_ERROR(2),
|
||||
FOLDER_ERROR(3),
|
||||
CONFLICT_ERROR(4),
|
||||
FILE_ERROR(5),
|
||||
PRIVILEDGES_ERROR(6),
|
||||
CANCELLED(7),
|
||||
FILE_NOT_FOUND(8),
|
||||
DELAYED_FOR_WIFI(9),
|
||||
SERVICE_INTERRUPTED(10);
|
||||
|
||||
private final int value;
|
||||
|
||||
UploadResult(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public int getValue() {
|
||||
return value;
|
||||
}
|
||||
public static UploadResult fromValue(int value) {
|
||||
switch (value) {
|
||||
case -1:
|
||||
return UNKNOWN;
|
||||
case 0:
|
||||
return UPLOADED;
|
||||
case 1:
|
||||
return NETWORK_CONNECTION;
|
||||
case 2:
|
||||
return CREDENTIAL_ERROR;
|
||||
case 3:
|
||||
return FOLDER_ERROR;
|
||||
case 4:
|
||||
return CONFLICT_ERROR;
|
||||
case 5:
|
||||
return FILE_ERROR;
|
||||
case 6:
|
||||
return PRIVILEDGES_ERROR;
|
||||
case 7:
|
||||
return CANCELLED;
|
||||
case 8:
|
||||
return FILE_NOT_FOUND;
|
||||
case 9:
|
||||
return DELAYED_FOR_WIFI;
|
||||
case 10:
|
||||
return SERVICE_INTERRUPTED;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static UploadResult fromOperationResult(RemoteOperationResult result){
|
||||
// messy :(
|
||||
switch (result.getCode()){
|
||||
case OK:
|
||||
return UPLOADED;
|
||||
case NO_NETWORK_CONNECTION:
|
||||
case HOST_NOT_AVAILABLE:
|
||||
case TIMEOUT:
|
||||
case WRONG_CONNECTION:
|
||||
case INCORRECT_ADDRESS:
|
||||
case SSL_ERROR:
|
||||
case SSL_RECOVERABLE_PEER_UNVERIFIED:
|
||||
return NETWORK_CONNECTION;
|
||||
case ACCOUNT_EXCEPTION:
|
||||
case UNAUTHORIZED:
|
||||
return CREDENTIAL_ERROR;
|
||||
case FILE_NOT_FOUND:
|
||||
return FOLDER_ERROR;
|
||||
case LOCAL_FILE_NOT_FOUND:
|
||||
return FILE_NOT_FOUND;
|
||||
case CONFLICT:
|
||||
return CONFLICT_ERROR;
|
||||
case LOCAL_STORAGE_NOT_COPIED:
|
||||
return FILE_ERROR;
|
||||
case FORBIDDEN:
|
||||
return PRIVILEDGES_ERROR;
|
||||
case CANCELLED:
|
||||
return CANCELLED;
|
||||
case DELAYED_FOR_WIFI:
|
||||
return DELAYED_FOR_WIFI;
|
||||
case UNKNOWN_ERROR:
|
||||
if (result.getException() instanceof java.io.FileNotFoundException) {
|
||||
return FILE_ERROR;
|
||||
}
|
||||
return UNKNOWN;
|
||||
default:
|
||||
return UNKNOWN;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -20,26 +20,23 @@
|
|||
|
||||
package com.owncloud.android.files;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.content.Context;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
|
||||
import com.owncloud.android.R;
|
||||
import com.owncloud.android.authentication.AccountUtils;
|
||||
import com.owncloud.android.datamodel.OCFile;
|
||||
import com.owncloud.android.files.services.FileDownloader;
|
||||
import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder;
|
||||
import com.owncloud.android.files.services.FileUploader;
|
||||
import com.owncloud.android.files.services.FileUploader.FileUploaderBinder;
|
||||
import com.owncloud.android.lib.resources.status.CapabilityBooleanType;
|
||||
import com.owncloud.android.lib.resources.status.OCCapability;
|
||||
import com.owncloud.android.services.OperationsService.OperationsServiceBinder;
|
||||
import com.owncloud.android.ui.activity.ComponentsGetter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Filters out the file actions available in a given {@link Menu} for a given {@link OCFile}
|
||||
* according to the current state of the latest.
|
||||
|
|
|
@ -29,6 +29,7 @@ import android.content.Intent;
|
|||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.net.Uri;
|
||||
import android.os.Parcelable;
|
||||
import android.support.v4.app.DialogFragment;
|
||||
import android.webkit.MimeTypeMap;
|
||||
import android.widget.Toast;
|
||||
|
@ -36,7 +37,9 @@ import android.widget.Toast;
|
|||
import com.owncloud.android.R;
|
||||
import com.owncloud.android.authentication.AccountUtils;
|
||||
import com.owncloud.android.datamodel.OCFile;
|
||||
import com.owncloud.android.db.OCUpload;
|
||||
import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder;
|
||||
import com.owncloud.android.files.services.FileUploader;
|
||||
import com.owncloud.android.files.services.FileUploader.FileUploaderBinder;
|
||||
import com.owncloud.android.lib.common.network.WebdavUtils;
|
||||
import com.owncloud.android.lib.common.utils.Log_OC;
|
||||
|
@ -50,7 +53,6 @@ import com.owncloud.android.ui.activity.ShareActivity;
|
|||
import com.owncloud.android.ui.dialog.ShareLinkToDialog;
|
||||
import com.owncloud.android.ui.dialog.SharePasswordDialogFragment;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
|
@ -58,8 +60,8 @@ import java.util.List;
|
|||
*/
|
||||
public class FileOperationsHelper {
|
||||
|
||||
private static final String TAG = FileOperationsHelper.class.getName();
|
||||
|
||||
private static final String TAG = FileOperationsHelper.class.getSimpleName();
|
||||
|
||||
private static final String FTAG_CHOOSER_DIALOG = "CHOOSER_DIALOG";
|
||||
|
||||
protected FileActivity mFileActivity = null;
|
||||
|
@ -91,9 +93,8 @@ public class FileOperationsHelper {
|
|||
);
|
||||
if (guessedMimeType != null && !guessedMimeType.equals(file.getMimetype())) {
|
||||
intentForGuessedMimeType = new Intent(Intent.ACTION_VIEW);
|
||||
intentForGuessedMimeType.
|
||||
setDataAndType(Uri.parse("file://"+ encodedStoragePath),
|
||||
guessedMimeType);
|
||||
intentForGuessedMimeType.setDataAndType(Uri.parse("file://" +
|
||||
encodedStoragePath), guessedMimeType);
|
||||
intentForGuessedMimeType.setFlags(
|
||||
Intent.FLAG_GRANT_READ_URI_PERMISSION |
|
||||
Intent.FLAG_GRANT_WRITE_URI_PERMISSION
|
||||
|
@ -235,7 +236,7 @@ public class FileOperationsHelper {
|
|||
if (file != null) {
|
||||
// TODO check capability?
|
||||
mFileActivity.showLoadingDialog(mFileActivity.getApplicationContext().
|
||||
getString(R.string.wait_a_moment));
|
||||
getString(R.string.wait_a_moment));
|
||||
|
||||
Intent service = new Intent(mFileActivity, OperationsService.class);
|
||||
service.setAction(OperationsService.ACTION_CREATE_SHARE_WITH_SHAREE);
|
||||
|
@ -323,7 +324,7 @@ public class FileOperationsHelper {
|
|||
*/
|
||||
public void showShareFile(OCFile file){
|
||||
Intent intent = new Intent(mFileActivity, ShareActivity.class);
|
||||
intent.putExtra(mFileActivity.EXTRA_FILE, file);
|
||||
intent.putExtra(mFileActivity.EXTRA_FILE, (Parcelable) file);
|
||||
intent.putExtra(mFileActivity.EXTRA_ACCOUNT, mFileActivity.getAccount());
|
||||
mFileActivity.startActivity(intent);
|
||||
|
||||
|
@ -342,8 +343,8 @@ public class FileOperationsHelper {
|
|||
SharePasswordDialogFragment dialog =
|
||||
SharePasswordDialogFragment.newInstance(file, createShare);
|
||||
dialog.show(
|
||||
mFileActivity.getSupportFragmentManager(),
|
||||
SharePasswordDialogFragment.PASSWORD_FRAGMENT
|
||||
mFileActivity.getSupportFragmentManager(),
|
||||
SharePasswordDialogFragment.PASSWORD_FRAGMENT
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -475,7 +476,7 @@ public class FileOperationsHelper {
|
|||
intent.putExtra(OperationsService.EXTRA_SYNC_FILE_CONTENTS, true);
|
||||
mWaitingForOpId = mFileActivity.getOperationsServiceBinder().queueNewOperation(intent);
|
||||
mFileActivity.showLoadingDialog(mFileActivity.getApplicationContext().
|
||||
getString(R.string.wait_a_moment));
|
||||
getString(R.string.wait_a_moment));
|
||||
|
||||
} else {
|
||||
Intent intent = new Intent(mFileActivity, OperationsService.class);
|
||||
|
@ -630,4 +631,19 @@ public class FileOperationsHelper {
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts a check of the currenlty stored credentials for the given account.
|
||||
*
|
||||
* @param account OC account which credentials will be checked.
|
||||
*/
|
||||
public void checkCurrentCredentials(Account account) {
|
||||
Intent service = new Intent(mFileActivity, OperationsService.class);
|
||||
service.setAction(OperationsService.ACTION_CHECK_CURRENT_CREDENTIALS);
|
||||
service.putExtra(OperationsService.EXTRA_ACCOUNT, account);
|
||||
mWaitingForOpId = mFileActivity.getOperationsServiceBinder().queueNewOperation(service);
|
||||
|
||||
mFileActivity.showLoadingDialog(
|
||||
mFileActivity.getApplicationContext().getString(R.string.wait_checking_credentials)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,35 +1,26 @@
|
|||
/**
|
||||
* ownCloud Android client application
|
||||
* ownCloud Android client application
|
||||
*
|
||||
* Copyright (C) 2012 Bartek Przybylski
|
||||
* Copyright (C) 2015 ownCloud Inc.
|
||||
* @author Bartek Przybylski
|
||||
* @author David A. Velasco
|
||||
* Copyright (C) 2012 Bartek Przybylski
|
||||
* Copyright (C) 2016 ownCloud Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.owncloud.android.files;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import com.owncloud.android.MainApp;
|
||||
import com.owncloud.android.authentication.AccountUtils;
|
||||
import com.owncloud.android.db.DbHandler;
|
||||
import com.owncloud.android.files.services.FileUploader;
|
||||
import com.owncloud.android.lib.common.utils.Log_OC;
|
||||
import com.owncloud.android.utils.FileStorageUtils;
|
||||
|
||||
|
||||
import android.Manifest;
|
||||
import android.accounts.Account;
|
||||
import android.content.BroadcastReceiver;
|
||||
|
@ -37,13 +28,17 @@ import android.content.Context;
|
|||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.database.Cursor;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.NetworkInfo.State;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.provider.MediaStore.Images;
|
||||
import android.provider.MediaStore.Video;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.webkit.MimeTypeMap;
|
||||
|
||||
import com.owncloud.android.authentication.AccountUtils;
|
||||
import com.owncloud.android.db.PreferenceReader;
|
||||
import com.owncloud.android.files.services.FileUploader;
|
||||
import com.owncloud.android.lib.common.utils.Log_OC;
|
||||
import com.owncloud.android.operations.UploadFileOperation;
|
||||
import com.owncloud.android.utils.FileStorageUtils;
|
||||
|
||||
|
||||
public class InstantUploadBroadcastReceiver extends BroadcastReceiver {
|
||||
|
@ -52,40 +47,47 @@ public class InstantUploadBroadcastReceiver extends BroadcastReceiver {
|
|||
// Image action
|
||||
// Unofficial action, works for most devices but not HTC. See: https://github.com/owncloud/android/issues/6
|
||||
private static String NEW_PHOTO_ACTION_UNOFFICIAL = "com.android.camera.NEW_PICTURE";
|
||||
// Officially supported action since SDK 14: http://developer.android.com/reference/android/hardware/Camera.html#ACTION_NEW_PICTURE
|
||||
// Officially supported action since SDK 14:
|
||||
// http://developer.android.com/reference/android/hardware/Camera.html#ACTION_NEW_PICTURE
|
||||
private static String NEW_PHOTO_ACTION = "android.hardware.action.NEW_PICTURE";
|
||||
// Video action
|
||||
// Officially supported action since SDK 14: http://developer.android.com/reference/android/hardware/Camera.html#ACTION_NEW_VIDEO
|
||||
// Officially supported action since SDK 14:
|
||||
// http://developer.android.com/reference/android/hardware/Camera.html#ACTION_NEW_VIDEO
|
||||
private static String NEW_VIDEO_ACTION = "android.hardware.action.NEW_VIDEO";
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
Log_OC.d(TAG, "Received: " + intent.getAction());
|
||||
if (intent.getAction().equals(android.net.ConnectivityManager.CONNECTIVITY_ACTION)) {
|
||||
handleConnectivityAction(context, intent);
|
||||
}else if (intent.getAction().equals(NEW_PHOTO_ACTION_UNOFFICIAL)) {
|
||||
handleNewPictureAction(context, intent);
|
||||
if (intent.getAction().equals(NEW_PHOTO_ACTION_UNOFFICIAL)) {
|
||||
handleNewPictureAction(context, intent);
|
||||
Log_OC.d(TAG, "UNOFFICIAL processed: com.android.camera.NEW_PICTURE");
|
||||
} else if (intent.getAction().equals(NEW_PHOTO_ACTION)) {
|
||||
handleNewPictureAction(context, intent);
|
||||
handleNewPictureAction(context, intent);
|
||||
Log_OC.d(TAG, "OFFICIAL processed: android.hardware.action.NEW_PICTURE");
|
||||
} else if (intent.getAction().equals(NEW_VIDEO_ACTION)) {
|
||||
Log_OC.d(TAG, "OFFICIAL processed: android.hardware.action.NEW_VIDEO");
|
||||
handleNewVideoAction(context, intent);
|
||||
Log_OC.d(TAG, "OFFICIAL processed: android.hardware.action.NEW_VIDEO");
|
||||
} else {
|
||||
Log_OC.e(TAG, "Incorrect intent sent: " + intent.getAction());
|
||||
Log_OC.e(TAG, "Incorrect intent received: " + intent.getAction());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Because we support NEW_PHOTO_ACTION and NEW_PHOTO_ACTION_UNOFFICIAL it can happen that
|
||||
* handleNewPictureAction is called twice for the same photo. Use this simple static variable to
|
||||
* remember last uploaded photo to filter duplicates. Must not be null!
|
||||
*/
|
||||
static String lastUploadedPhotoPath = "";
|
||||
|
||||
private void handleNewPictureAction(Context context, Intent intent) {
|
||||
Cursor c = null;
|
||||
String file_path = null;
|
||||
String file_name = null;
|
||||
String mime_type = null;
|
||||
|
||||
Log_OC.w(TAG, "New photo received");
|
||||
|
||||
if (!instantPictureUploadEnabled(context)) {
|
||||
Log_OC.i(TAG, "New photo received");
|
||||
|
||||
if (!PreferenceReader.instantPictureUploadEnabled(context)) {
|
||||
Log_OC.d(TAG, "Instant picture upload disabled, ignoring new picture");
|
||||
return;
|
||||
}
|
||||
|
@ -96,7 +98,8 @@ public class InstantUploadBroadcastReceiver extends BroadcastReceiver {
|
|||
return;
|
||||
}
|
||||
|
||||
String[] CONTENT_PROJECTION = { Images.Media.DATA, Images.Media.DISPLAY_NAME, Images.Media.MIME_TYPE, Images.Media.SIZE };
|
||||
String[] CONTENT_PROJECTION = {
|
||||
Images.Media.DATA, Images.Media.DISPLAY_NAME, Images.Media.MIME_TYPE, Images.Media.SIZE };
|
||||
|
||||
int permissionCheck = ContextCompat.checkSelfPermission(context,
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE);
|
||||
|
@ -115,44 +118,43 @@ public class InstantUploadBroadcastReceiver extends BroadcastReceiver {
|
|||
file_name = c.getString(c.getColumnIndex(Images.Media.DISPLAY_NAME));
|
||||
mime_type = c.getString(c.getColumnIndex(Images.Media.MIME_TYPE));
|
||||
c.close();
|
||||
|
||||
Log_OC.d(TAG, file_path + "");
|
||||
|
||||
// save always temporally the picture to upload
|
||||
DbHandler db = new DbHandler(context);
|
||||
db.putFileForLater(file_path, account.name, null);
|
||||
db.close();
|
||||
|
||||
if (!isOnline(context) || (instantPictureUploadViaWiFiOnly(context) && !isConnectedViaWiFi(context))) {
|
||||
if (file_path.equals(lastUploadedPhotoPath)) {
|
||||
Log_OC.d(TAG, "Duplicate detected: " + file_path + ". Ignore.");
|
||||
return;
|
||||
}
|
||||
|
||||
Intent i = new Intent(context, FileUploader.class);
|
||||
i.putExtra(FileUploader.KEY_ACCOUNT, account);
|
||||
i.putExtra(FileUploader.KEY_LOCAL_FILE, file_path);
|
||||
i.putExtra(FileUploader.KEY_REMOTE_FILE, FileStorageUtils.getInstantUploadFilePath(context, file_name));
|
||||
i.putExtra(FileUploader.KEY_UPLOAD_TYPE, FileUploader.UPLOAD_SINGLE_FILE);
|
||||
i.putExtra(FileUploader.KEY_MIME_TYPE, mime_type);
|
||||
i.putExtra(FileUploader.KEY_INSTANT_UPLOAD, true);
|
||||
lastUploadedPhotoPath = file_path;
|
||||
Log_OC.d(TAG, "Path: " + file_path + "");
|
||||
|
||||
// instant upload behaviour
|
||||
i = addInstantUploadBehaviour(i, context);
|
||||
new FileUploader.UploadRequester();
|
||||
|
||||
context.startService(i);
|
||||
int behaviour = getUploadBehaviour(context);
|
||||
FileUploader.UploadRequester requester = new FileUploader.UploadRequester();
|
||||
requester.uploadNewFile(
|
||||
context,
|
||||
account,
|
||||
file_path,
|
||||
FileStorageUtils.getInstantUploadFilePath(context, file_name),
|
||||
behaviour,
|
||||
mime_type,
|
||||
true, // create parent folder if not existent
|
||||
UploadFileOperation.CREATED_AS_INSTANT_PICTURE
|
||||
);
|
||||
}
|
||||
|
||||
private Intent addInstantUploadBehaviour(Intent i, Context context){
|
||||
private Integer getUploadBehaviour(Context context) {
|
||||
SharedPreferences appPreferences = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
String behaviour = appPreferences.getString("prefs_instant_behaviour", "NOTHING");
|
||||
|
||||
if (behaviour.equalsIgnoreCase("NOTHING")) {
|
||||
Log_OC.d(TAG, "upload file and do nothing");
|
||||
i.putExtra(FileUploader.KEY_LOCAL_BEHAVIOUR, FileUploader.LOCAL_BEHAVIOUR_FORGET);
|
||||
return FileUploader.LOCAL_BEHAVIOUR_FORGET;
|
||||
} else if (behaviour.equalsIgnoreCase("MOVE")) {
|
||||
i.putExtra(FileUploader.KEY_LOCAL_BEHAVIOUR, FileUploader.LOCAL_BEHAVIOUR_MOVE);
|
||||
Log_OC.d(TAG, "upload file and move file to oc folder");
|
||||
return FileUploader.LOCAL_BEHAVIOUR_MOVE;
|
||||
}
|
||||
return i;
|
||||
return null;
|
||||
}
|
||||
|
||||
private void handleNewVideoAction(Context context, Intent intent) {
|
||||
|
@ -161,9 +163,9 @@ public class InstantUploadBroadcastReceiver extends BroadcastReceiver {
|
|||
String file_name = null;
|
||||
String mime_type = null;
|
||||
|
||||
Log_OC.w(TAG, "New video received");
|
||||
|
||||
if (!instantVideoUploadEnabled(context)) {
|
||||
Log_OC.i(TAG, "New video received");
|
||||
|
||||
if (!PreferenceReader.instantVideoUploadEnabled(context)) {
|
||||
Log_OC.d(TAG, "Instant video upload disabled, ignoring new video");
|
||||
return;
|
||||
}
|
||||
|
@ -174,133 +176,31 @@ public class InstantUploadBroadcastReceiver extends BroadcastReceiver {
|
|||
return;
|
||||
}
|
||||
|
||||
String[] CONTENT_PROJECTION = { Video.Media.DATA, Video.Media.DISPLAY_NAME, Video.Media.MIME_TYPE, Video.Media.SIZE };
|
||||
String[] CONTENT_PROJECTION = {Video.Media.DATA, Video.Media.DISPLAY_NAME, Video.Media.MIME_TYPE,
|
||||
Video.Media.SIZE};
|
||||
c = context.getContentResolver().query(intent.getData(), CONTENT_PROJECTION, null, null, null);
|
||||
if (!c.moveToFirst()) {
|
||||
Log_OC.e(TAG, "Couldn't resolve given uri: " + intent.getDataString());
|
||||
return;
|
||||
}
|
||||
}
|
||||
file_path = c.getString(c.getColumnIndex(Video.Media.DATA));
|
||||
file_name = c.getString(c.getColumnIndex(Video.Media.DISPLAY_NAME));
|
||||
mime_type = c.getString(c.getColumnIndex(Video.Media.MIME_TYPE));
|
||||
c.close();
|
||||
Log_OC.d(TAG, file_path + "");
|
||||
|
||||
if (!isOnline(context) || (instantVideoUploadViaWiFiOnly(context) && !isConnectedViaWiFi(context))) {
|
||||
return;
|
||||
}
|
||||
|
||||
Intent i = new Intent(context, FileUploader.class);
|
||||
i.putExtra(FileUploader.KEY_ACCOUNT, account);
|
||||
i.putExtra(FileUploader.KEY_LOCAL_FILE, file_path);
|
||||
i.putExtra(FileUploader.KEY_REMOTE_FILE, FileStorageUtils.getInstantVideoUploadFilePath(context, file_name));
|
||||
i.putExtra(FileUploader.KEY_UPLOAD_TYPE, FileUploader.UPLOAD_SINGLE_FILE);
|
||||
i.putExtra(FileUploader.KEY_MIME_TYPE, mime_type);
|
||||
i.putExtra(FileUploader.KEY_INSTANT_UPLOAD, true);
|
||||
|
||||
// instant upload behaviour
|
||||
i = addInstantUploadBehaviour(i, context);
|
||||
|
||||
context.startService(i);
|
||||
|
||||
int behaviour = getUploadBehaviour(context);
|
||||
FileUploader.UploadRequester requester = new FileUploader.UploadRequester();
|
||||
requester.uploadNewFile(
|
||||
context,
|
||||
account,
|
||||
file_path,
|
||||
FileStorageUtils.getInstantVideoUploadFilePath(context, file_name),
|
||||
behaviour,
|
||||
mime_type,
|
||||
true, // create parent folder if not existent
|
||||
UploadFileOperation.CREATED_AS_INSTANT_VIDEO
|
||||
);
|
||||
}
|
||||
|
||||
private void handleConnectivityAction(Context context, Intent intent) {
|
||||
if (!instantPictureUploadEnabled(context)) {
|
||||
Log_OC.d(TAG, "Instant upload disabled, don't upload anything");
|
||||
return;
|
||||
}
|
||||
|
||||
if (instantPictureUploadViaWiFiOnly(context) && !isConnectedViaWiFi(context)){
|
||||
Account account = AccountUtils.getCurrentOwnCloudAccount(context);
|
||||
if (account == null) {
|
||||
Log_OC.w(TAG, "No account found for instant upload, aborting");
|
||||
return;
|
||||
}
|
||||
|
||||
Intent i = new Intent(context, FileUploader.class);
|
||||
i.putExtra(FileUploader.KEY_ACCOUNT, account);
|
||||
i.putExtra(FileUploader.KEY_CANCEL_ALL, true);
|
||||
context.startService(i);
|
||||
}
|
||||
|
||||
if (!intent.hasExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY)
|
||||
&& isOnline(context)
|
||||
&& (!instantPictureUploadViaWiFiOnly(context) || (instantPictureUploadViaWiFiOnly(context) == isConnectedViaWiFi(context) == true))) {
|
||||
DbHandler db = new DbHandler(context);
|
||||
Cursor c = db.getAwaitingFiles();
|
||||
if (c.moveToFirst()) {
|
||||
do {
|
||||
if (instantPictureUploadViaWiFiOnly(context) &&
|
||||
!isConnectedViaWiFi(context)){
|
||||
break;
|
||||
}
|
||||
|
||||
String account_name = c.getString(c.getColumnIndex("account"));
|
||||
String file_path = c.getString(c.getColumnIndex("path"));
|
||||
File f = new File(file_path);
|
||||
if (f.exists()) {
|
||||
Account account = new Account(account_name, MainApp.getAccountType());
|
||||
|
||||
String mimeType = null;
|
||||
try {
|
||||
mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(
|
||||
f.getName().substring(f.getName().lastIndexOf('.') + 1));
|
||||
|
||||
} catch (Throwable e) {
|
||||
Log_OC.e(TAG, "Trying to find out MIME type of a file without extension: " + f.getName());
|
||||
}
|
||||
if (mimeType == null)
|
||||
mimeType = "application/octet-stream";
|
||||
|
||||
Intent i = new Intent(context, FileUploader.class);
|
||||
i.putExtra(FileUploader.KEY_ACCOUNT, account);
|
||||
i.putExtra(FileUploader.KEY_LOCAL_FILE, file_path);
|
||||
i.putExtra(FileUploader.KEY_REMOTE_FILE, FileStorageUtils.getInstantUploadFilePath(context, f.getName()));
|
||||
i.putExtra(FileUploader.KEY_UPLOAD_TYPE, FileUploader.UPLOAD_SINGLE_FILE);
|
||||
i.putExtra(FileUploader.KEY_INSTANT_UPLOAD, true);
|
||||
|
||||
// instant upload behaviour
|
||||
i = addInstantUploadBehaviour(i, context);
|
||||
|
||||
context.startService(i);
|
||||
|
||||
} else {
|
||||
Log_OC.w(TAG, "Instant upload file " + f.getAbsolutePath() + " dont exist anymore");
|
||||
}
|
||||
} while (c.moveToNext());
|
||||
}
|
||||
c.close();
|
||||
db.close();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static boolean isOnline(Context context) {
|
||||
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
return cm.getActiveNetworkInfo() != null && cm.getActiveNetworkInfo().isConnected();
|
||||
}
|
||||
|
||||
public static boolean isConnectedViaWiFi(Context context) {
|
||||
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
return cm != null && cm.getActiveNetworkInfo() != null
|
||||
&& cm.getActiveNetworkInfo().getType() == ConnectivityManager.TYPE_WIFI
|
||||
&& cm.getActiveNetworkInfo().getState() == State.CONNECTED;
|
||||
}
|
||||
|
||||
public static boolean instantPictureUploadEnabled(Context context) {
|
||||
return PreferenceManager.getDefaultSharedPreferences(context).getBoolean("instant_uploading", false);
|
||||
}
|
||||
|
||||
public static boolean instantVideoUploadEnabled(Context context) {
|
||||
return PreferenceManager.getDefaultSharedPreferences(context).getBoolean("instant_video_uploading", false);
|
||||
}
|
||||
|
||||
public static boolean instantPictureUploadViaWiFiOnly(Context context) {
|
||||
return PreferenceManager.getDefaultSharedPreferences(context).getBoolean("instant_upload_on_wifi", false);
|
||||
}
|
||||
|
||||
public static boolean instantVideoUploadViaWiFiOnly(Context context) {
|
||||
return PreferenceManager.getDefaultSharedPreferences(context).getBoolean("instant_video_upload_on_wifi", false);
|
||||
}
|
||||
}
|
||||
|
|
206
src/com/owncloud/android/files/services/ConnectivityActionReceiver.java
Executable file
|
@ -0,0 +1,206 @@
|
|||
/**
|
||||
* ownCloud Android client application
|
||||
*
|
||||
* @author LukeOwncloud
|
||||
* Copyright (C) 2016 ownCloud Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.owncloud.android.files.services;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.net.NetworkInfo;
|
||||
import android.net.wifi.WifiInfo;
|
||||
import android.net.wifi.WifiManager;
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.owncloud.android.db.PreferenceReader;
|
||||
import com.owncloud.android.db.UploadResult;
|
||||
import com.owncloud.android.lib.common.utils.Log_OC;
|
||||
|
||||
/**
|
||||
* Receives all connectivity action from Android OS at all times and performs
|
||||
* required OC actions. For now that are: - Signal connectivity to
|
||||
* {@link FileUploader}.
|
||||
*
|
||||
* Later can be added: - Signal connectivity to download service, deletion
|
||||
* service, ... - Handle offline mode (cf.
|
||||
* https://github.com/owncloud/android/issues/162)
|
||||
*
|
||||
* Have fun with the comments :S
|
||||
*/
|
||||
public class ConnectivityActionReceiver extends BroadcastReceiver {
|
||||
private static final String TAG = ConnectivityActionReceiver.class.getSimpleName();
|
||||
|
||||
/**
|
||||
* Magic keyword, by Google.
|
||||
*
|
||||
* {@See http://developer.android.com/intl/es/reference/android/net/wifi/WifiInfo.html#getSSID()}
|
||||
*/
|
||||
private static final String UNKNOWN_SSID = "<unknown ssid>";
|
||||
|
||||
|
||||
@Override
|
||||
public void onReceive(final Context context, Intent intent) {
|
||||
// LOG ALL EVENTS:
|
||||
Log_OC.v(TAG, "action: " + intent.getAction());
|
||||
Log_OC.v(TAG, "component: " + intent.getComponent());
|
||||
Bundle extras = intent.getExtras();
|
||||
if (extras != null) {
|
||||
for (String key : extras.keySet()) {
|
||||
Log_OC.v(TAG, "key [" + key + "]: " + extras.get(key));
|
||||
}
|
||||
} else {
|
||||
Log_OC.v(TAG, "no extras");
|
||||
}
|
||||
|
||||
/**
|
||||
* There is an interesting mess to process WifiManager.NETWORK_STATE_CHANGED_ACTION and
|
||||
* ConnectivityManager.CONNECTIVITY_ACTION in a simple and reliable way.
|
||||
*
|
||||
* The former triggers much more events than what we really need to know about Wifi connection.
|
||||
*
|
||||
* But there are annoying uncertainties about ConnectivityManager.CONNECTIVITY_ACTION due
|
||||
* to the deprecation of ConnectivityManager.EXTRA_NETWORK_INFO in API level 14, and the absence
|
||||
* of ConnectivityManager.EXTRA_NETWORK_TYPE until API level 17. Dear Google, how should we
|
||||
* handle API levels 14 to 16?
|
||||
*
|
||||
* In the end maybe we need to keep in memory the current knowledge about connectivity
|
||||
* and update it taking into account several Intents received in a row
|
||||
*
|
||||
* But first let's try something "simple" to keep a basic retry of instant uploads in
|
||||
* version 1.9.2, similar to the existent until 1.9.1. To be improved.
|
||||
*/
|
||||
if(intent.getAction().equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
|
||||
NetworkInfo networkInfo =
|
||||
intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
|
||||
WifiInfo wifiInfo =
|
||||
intent.getParcelableExtra(WifiManager.EXTRA_WIFI_INFO);
|
||||
String bssid =
|
||||
intent.getStringExtra(WifiManager.EXTRA_BSSID);
|
||||
if(networkInfo.isConnected() && // not enough; see (*) right below
|
||||
wifiInfo != null &&
|
||||
!UNKNOWN_SSID.equals(wifiInfo.getSSID().toLowerCase()) &&
|
||||
bssid != null
|
||||
) {
|
||||
Log_OC.d(TAG, "WiFi connected");
|
||||
|
||||
wifiConnected(context);
|
||||
} else {
|
||||
// TODO tons of things to check to conclude disconnection;
|
||||
// TODO maybe alternative commented below, based on CONNECTIVITY_ACTION is better
|
||||
Log_OC.d(TAG, "WiFi disconnected ... but don't know if right now");
|
||||
}
|
||||
}
|
||||
// (*) When WiFi is lost, an Intent with network state CONNECTED and SSID "<unknown ssid>" is
|
||||
// received right before another Intent with network state DISCONNECTED; needs to
|
||||
// be differentiated of a new Wifi connection.
|
||||
//
|
||||
// Besides, with a new connection two Intents are received, having only the second the extra
|
||||
// WifiManager.EXTRA_BSSID, with the BSSID of the access point accessed.
|
||||
//
|
||||
// Not sure if this protocol is exact, since it's not documented. Only found mild references in
|
||||
// - http://developer.android.com/intl/es/reference/android/net/wifi/WifiInfo.html#getSSID()
|
||||
// - http://developer.android.com/intl/es/reference/android/net/wifi/WifiManager.html#EXTRA_BSSID
|
||||
// and reproduced in Nexus 5 with Android 6.
|
||||
|
||||
|
||||
/**
|
||||
* Possible alternative attending ConnectivityManager.CONNECTIVITY_ACTION.
|
||||
*
|
||||
* Let's see what QA has to say
|
||||
*
|
||||
if(intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
|
||||
NetworkInfo networkInfo = intent.getParcelableExtra(
|
||||
ConnectivityManager.EXTRA_NETWORK_INFO // deprecated in API 14
|
||||
);
|
||||
int networkType = intent.getIntExtra(
|
||||
ConnectivityManager.EXTRA_NETWORK_TYPE, // only from API level 17
|
||||
-1
|
||||
);
|
||||
boolean couldBeWifiAction =
|
||||
(networkInfo == null && networkType < 0) || // cases of lack of info
|
||||
networkInfo.getType() == ConnectivityManager.TYPE_WIFI ||
|
||||
networkType == ConnectivityManager.TYPE_WIFI;
|
||||
|
||||
if (couldBeWifiAction) {
|
||||
if (ConnectivityUtils.isAppConnectedViaWiFi(context)) {
|
||||
Log_OC.d(TAG, "WiFi connected");
|
||||
wifiConnected(context);
|
||||
} else {
|
||||
Log_OC.d(TAG, "WiFi disconnected");
|
||||
wifiDisconnected(context);
|
||||
}
|
||||
} /* else, CONNECTIVIY_ACTION is (probably) about other network interface (mobile, bluetooth, ...)
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
private void wifiConnected(Context context) {
|
||||
// for the moment, only recovery of instant uploads, similar to behaviour in release 1.9.1
|
||||
if (
|
||||
(PreferenceReader.instantPictureUploadEnabled(context) &&
|
||||
PreferenceReader.instantPictureUploadViaWiFiOnly(context)) ||
|
||||
(PreferenceReader.instantVideoUploadEnabled(context) &&
|
||||
PreferenceReader.instantVideoUploadViaWiFiOnly(context))
|
||||
) {
|
||||
Log_OC.d(TAG, "Requesting retry of instant uploads (& friends)");
|
||||
FileUploader.UploadRequester requester = new FileUploader.UploadRequester();
|
||||
requester.retryFailedUploads(
|
||||
context,
|
||||
null,
|
||||
UploadResult.NETWORK_CONNECTION // for the interrupted when Wifi fell, if any
|
||||
// (side effect: any upload failed due to network error will be retried too, instant or not)
|
||||
);
|
||||
requester.retryFailedUploads(
|
||||
context,
|
||||
null,
|
||||
UploadResult.DELAYED_FOR_WIFI // for the rest of enqueued when Wifi fell
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private void wifiDisconnected(Context context) {
|
||||
// TODO something smart
|
||||
|
||||
// NOTE: explicit cancellation of only-wifi instant uploads is not needed anymore, since currently:
|
||||
// - any upload in progress will be interrupted due to the lack of connectivity while the device
|
||||
// reconnects through other network interface;
|
||||
// - FileUploader checks instant upload settings and connection state before executing each
|
||||
// upload operation, so other pending instant uploads after the current one will not be run
|
||||
// (currently are silently moved to FAILED state)
|
||||
}
|
||||
|
||||
|
||||
static public void enableActionReceiver(Context context) {
|
||||
PackageManager pm = context.getPackageManager();
|
||||
ComponentName compName = new ComponentName(context.getApplicationContext(), ConnectivityActionReceiver.class);
|
||||
pm.setComponentEnabledSetting(compName, PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
|
||||
PackageManager.DONT_KILL_APP);
|
||||
}
|
||||
|
||||
static public void disableActionReceiver(Context context) {
|
||||
PackageManager pm = context.getPackageManager();
|
||||
ComponentName compName = new ComponentName(context.getApplicationContext(), ConnectivityActionReceiver.class);
|
||||
pm.setComponentEnabledSetting(compName, PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
|
||||
PackageManager.DONT_KILL_APP);
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -2,7 +2,7 @@
|
|||
* ownCloud Android client application
|
||||
*
|
||||
* Copyright (C) 2012 Bartek Przybylski
|
||||
* Copyright (C) 2012-2015 ownCloud Inc.
|
||||
* Copyright (C) 2012-2016 ownCloud Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
|
@ -20,36 +20,6 @@
|
|||
|
||||
package com.owncloud.android.files.services;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.AbstractList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Vector;
|
||||
|
||||
import com.owncloud.android.R;
|
||||
import com.owncloud.android.authentication.AccountUtils;
|
||||
import com.owncloud.android.authentication.AuthenticatorActivity;
|
||||
import com.owncloud.android.datamodel.FileDataStorageManager;
|
||||
import com.owncloud.android.datamodel.OCFile;
|
||||
|
||||
import com.owncloud.android.lib.common.network.OnDatatransferProgressListener;
|
||||
import com.owncloud.android.lib.common.OwnCloudAccount;
|
||||
import com.owncloud.android.lib.common.OwnCloudClient;
|
||||
import com.owncloud.android.lib.common.OwnCloudClientManagerFactory;
|
||||
import com.owncloud.android.notifications.NotificationBuilderWithProgressBar;
|
||||
import com.owncloud.android.notifications.NotificationDelayer;
|
||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
|
||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;
|
||||
import com.owncloud.android.lib.common.utils.Log_OC;
|
||||
import com.owncloud.android.lib.resources.files.FileUtils;
|
||||
import com.owncloud.android.operations.DownloadFileOperation;
|
||||
import com.owncloud.android.ui.activity.FileActivity;
|
||||
import com.owncloud.android.ui.activity.FileDisplayActivity;
|
||||
import com.owncloud.android.ui.preview.PreviewImageActivity;
|
||||
import com.owncloud.android.ui.preview.PreviewImageFragment;
|
||||
import com.owncloud.android.utils.ErrorMessageAdapter;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.accounts.AccountManager;
|
||||
import android.accounts.OnAccountsUpdateListener;
|
||||
|
@ -67,6 +37,35 @@ import android.os.Process;
|
|||
import android.support.v4.app.NotificationCompat;
|
||||
import android.util.Pair;
|
||||
|
||||
import com.owncloud.android.R;
|
||||
import com.owncloud.android.authentication.AccountUtils;
|
||||
import com.owncloud.android.authentication.AuthenticatorActivity;
|
||||
import com.owncloud.android.datamodel.FileDataStorageManager;
|
||||
import com.owncloud.android.datamodel.OCFile;
|
||||
import com.owncloud.android.lib.common.OwnCloudAccount;
|
||||
import com.owncloud.android.lib.common.OwnCloudClient;
|
||||
import com.owncloud.android.lib.common.OwnCloudClientManagerFactory;
|
||||
import com.owncloud.android.lib.common.network.OnDatatransferProgressListener;
|
||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
|
||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;
|
||||
import com.owncloud.android.lib.common.utils.Log_OC;
|
||||
import com.owncloud.android.lib.resources.files.FileUtils;
|
||||
import com.owncloud.android.notifications.NotificationBuilderWithProgressBar;
|
||||
import com.owncloud.android.notifications.NotificationDelayer;
|
||||
import com.owncloud.android.operations.DownloadFileOperation;
|
||||
import com.owncloud.android.ui.activity.FileActivity;
|
||||
import com.owncloud.android.ui.activity.FileDisplayActivity;
|
||||
import com.owncloud.android.ui.preview.PreviewImageActivity;
|
||||
import com.owncloud.android.ui.preview.PreviewImageFragment;
|
||||
import com.owncloud.android.utils.ErrorMessageAdapter;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.AbstractList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Vector;
|
||||
|
||||
public class FileDownloader extends Service
|
||||
implements OnDatatransferProgressListener, OnAccountsUpdateListener {
|
||||
|
||||
|
@ -81,7 +80,7 @@ public class FileDownloader extends Service
|
|||
public static final String EXTRA_LINKED_TO_PATH = "LINKED_TO";
|
||||
public static final String ACCOUNT_NAME = "ACCOUNT_NAME";
|
||||
|
||||
private static final String TAG = "FileDownloader";
|
||||
private static final String TAG = FileDownloader.class.getSimpleName();
|
||||
|
||||
private Looper mServiceLooper;
|
||||
private ServiceHandler mServiceHandler;
|
||||
|
@ -172,8 +171,7 @@ public class FileDownloader extends Service
|
|||
newDownload.addDatatransferProgressListener(this);
|
||||
newDownload.addDatatransferProgressListener((FileDownloaderBinder) mBinder);
|
||||
Pair<String, String> putResult = mPendingDownloads.putIfAbsent(
|
||||
account, file.getRemotePath(), newDownload
|
||||
);
|
||||
account.name, file.getRemotePath(), newDownload);
|
||||
if (putResult != null) {
|
||||
String downloadKey = putResult.first;
|
||||
requestedDownloads.add(downloadKey);
|
||||
|
@ -191,7 +189,6 @@ public class FileDownloader extends Service
|
|||
msg.obj = requestedDownloads;
|
||||
mServiceHandler.sendMessage(msg);
|
||||
}
|
||||
//}
|
||||
}
|
||||
|
||||
return START_NOT_STICKY;
|
||||
|
@ -253,7 +250,8 @@ public class FileDownloader extends Service
|
|||
* @param file A file in the queue of pending downloads
|
||||
*/
|
||||
public void cancel(Account account, OCFile file) {
|
||||
Pair<DownloadFileOperation, String> removeResult = mPendingDownloads.remove(account, file.getRemotePath());
|
||||
Pair<DownloadFileOperation, String> removeResult =
|
||||
mPendingDownloads.remove(account.name, file.getRemotePath());
|
||||
DownloadFileOperation download = removeResult.first;
|
||||
if (download != null) {
|
||||
download.cancel();
|
||||
|
@ -301,7 +299,7 @@ public class FileDownloader extends Service
|
|||
*/
|
||||
public boolean isDownloading(Account account, OCFile file) {
|
||||
if (account == null || file == null) return false;
|
||||
return (mPendingDownloads.contains(account, file.getRemotePath()));
|
||||
return (mPendingDownloads.contains(account.name, file.getRemotePath()));
|
||||
}
|
||||
|
||||
|
||||
|
@ -350,7 +348,6 @@ public class FileDownloader extends Service
|
|||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Download worker. Performs the pending downloads in the order they were requested.
|
||||
|
||||
|
@ -432,8 +429,10 @@ public class FileDownloader extends Service
|
|||
|
||||
} finally {
|
||||
Pair<DownloadFileOperation, String> removeResult =
|
||||
mPendingDownloads.removePayload(mCurrentAccount,
|
||||
mCurrentDownload.getRemotePath());
|
||||
mPendingDownloads.removePayload(
|
||||
mCurrentAccount.name,
|
||||
mCurrentDownload.getRemotePath()
|
||||
);
|
||||
|
||||
/// notify result
|
||||
notifyDownloadResult(mCurrentDownload, downloadResult);
|
||||
|
@ -546,10 +545,7 @@ public class FileDownloader extends Service
|
|||
int tickerId = (downloadResult.isSuccess()) ? R.string.downloader_download_succeeded_ticker :
|
||||
R.string.downloader_download_failed_ticker;
|
||||
|
||||
boolean needsToUpdateCredentials = (
|
||||
downloadResult.getCode() == ResultCode.UNAUTHORIZED ||
|
||||
downloadResult.isIdPRedirection()
|
||||
);
|
||||
boolean needsToUpdateCredentials = (ResultCode.UNAUTHORIZED.equals(downloadResult.getCode()));
|
||||
tickerId = (needsToUpdateCredentials) ?
|
||||
R.string.downloader_download_failed_credentials_error : tickerId;
|
||||
|
||||
|
@ -653,6 +649,6 @@ public class FileDownloader extends Service
|
|||
*/
|
||||
private void cancelDownloadsForAccount(Account account) {
|
||||
// Cancel pending downloads
|
||||
mPendingDownloads.remove(account);
|
||||
mPendingDownloads.remove(account.name);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* ownCloud Android client application
|
||||
*
|
||||
* @author David A. Velasco
|
||||
* Copyright (C) 2015 ownCloud Inc.
|
||||
* Copyright (C) 2016 ownCloud Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
|
@ -20,7 +20,6 @@
|
|||
|
||||
package com.owncloud.android.files.services;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.util.Pair;
|
||||
|
||||
import com.owncloud.android.datamodel.OCFile;
|
||||
|
@ -98,8 +97,9 @@ public class IndexedForest<V> {
|
|||
}
|
||||
|
||||
|
||||
public /* synchronized */ Pair<String, String> putIfAbsent(Account account, String remotePath, V value) {
|
||||
String targetKey = buildKey(account, remotePath);
|
||||
public /* synchronized */ Pair<String, String> putIfAbsent(String accountName, String remotePath, V value) {
|
||||
String targetKey = buildKey(accountName, remotePath);
|
||||
|
||||
Node<V> valuedNode = new Node(targetKey, value);
|
||||
Node<V> previousValue = mMap.putIfAbsent(
|
||||
targetKey,
|
||||
|
@ -119,7 +119,7 @@ public class IndexedForest<V> {
|
|||
if (!parentPath.endsWith(OCFile.PATH_SEPARATOR)) {
|
||||
parentPath += OCFile.PATH_SEPARATOR;
|
||||
}
|
||||
parentKey = buildKey(account, parentPath);
|
||||
parentKey = buildKey(accountName, parentPath);
|
||||
parentNode = mMap.get(parentKey);
|
||||
if (parentNode == null) {
|
||||
parentNode = new Node(parentKey, null);
|
||||
|
@ -135,7 +135,7 @@ public class IndexedForest<V> {
|
|||
|
||||
String linkedTo = OCFile.ROOT_PATH;
|
||||
if (linked) {
|
||||
linkedTo = parentNode.getKey().substring(account.name.length());
|
||||
linkedTo = parentNode.getKey().substring(accountName.length());
|
||||
}
|
||||
|
||||
return new Pair<String, String>(targetKey, linkedTo);
|
||||
|
@ -143,21 +143,21 @@ public class IndexedForest<V> {
|
|||
};
|
||||
|
||||
|
||||
public Pair<V, String> removePayload(Account account, String remotePath) {
|
||||
String targetKey = buildKey(account, remotePath);
|
||||
public Pair<V, String> removePayload(String accountName, String remotePath) {
|
||||
String targetKey = buildKey(accountName, remotePath);
|
||||
Node<V> target = mMap.get(targetKey);
|
||||
if (target != null) {
|
||||
target.clearPayload();
|
||||
if (!target.hasChildren()) {
|
||||
return remove(account, remotePath);
|
||||
return remove(accountName, remotePath);
|
||||
}
|
||||
}
|
||||
return new Pair<V, String>(null, null);
|
||||
}
|
||||
|
||||
|
||||
public /* synchronized */ Pair<V, String> remove(Account account, String remotePath) {
|
||||
String targetKey = buildKey(account, remotePath);
|
||||
public /* synchronized */ Pair<V, String> remove(String accountName, String remotePath) {
|
||||
String targetKey = buildKey(accountName, remotePath);
|
||||
Node<V> firstRemoved = mMap.remove(targetKey);
|
||||
String unlinkedFrom = null;
|
||||
|
||||
|
@ -180,7 +180,7 @@ public class IndexedForest<V> {
|
|||
}
|
||||
|
||||
if (parent != null) {
|
||||
unlinkedFrom = parent.getKey().substring(account.name.length());
|
||||
unlinkedFrom = parent.getKey().substring(accountName.length());
|
||||
}
|
||||
|
||||
return new Pair<V, String>(firstRemoved.getPayload(), unlinkedFrom);
|
||||
|
@ -199,8 +199,8 @@ public class IndexedForest<V> {
|
|||
}
|
||||
}
|
||||
|
||||
public boolean contains(Account account, String remotePath) {
|
||||
String targetKey = buildKey(account, remotePath);
|
||||
public boolean contains(String accountName, String remotePath) {
|
||||
String targetKey = buildKey(accountName, remotePath);
|
||||
return mMap.containsKey(targetKey);
|
||||
}
|
||||
|
||||
|
@ -213,22 +213,22 @@ public class IndexedForest<V> {
|
|||
}
|
||||
}
|
||||
|
||||
public V get(Account account, String remotePath) {
|
||||
String key = buildKey(account, remotePath);
|
||||
public V get(String accountName, String remotePath) {
|
||||
String key = buildKey(accountName, remotePath);
|
||||
return get(key);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Remove the elements that contains account as a part of its key
|
||||
* @param account
|
||||
* @param accountName
|
||||
*/
|
||||
public void remove(Account account){
|
||||
public void remove(String accountName){
|
||||
Iterator<String> it = mMap.keySet().iterator();
|
||||
while (it.hasNext()) {
|
||||
String key = it.next();
|
||||
Log_OC.d("IndexedForest", "Number of pending downloads= " + mMap.size());
|
||||
if (key.startsWith(account.name)) {
|
||||
if (key.startsWith(accountName)) {
|
||||
mMap.remove(key);
|
||||
}
|
||||
}
|
||||
|
@ -237,11 +237,11 @@ public class IndexedForest<V> {
|
|||
/**
|
||||
* Builds a key to index files
|
||||
*
|
||||
* @param account Account where the file to download is stored
|
||||
* @param remotePath Path of the file in the server
|
||||
* @param accountName Local name of the ownCloud account where the file to download is stored.
|
||||
* @param remotePath Path of the file in the server.
|
||||
*/
|
||||
private String buildKey(Account account, String remotePath) {
|
||||
return account.name + remotePath;
|
||||
private String buildKey(String accountName, String remotePath) {
|
||||
return accountName + remotePath;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* ownCloud Android client application
|
||||
*
|
||||
* @author David A. Velasco
|
||||
* Copyright (C) 2015 ownCloud Inc.
|
||||
* Copyright (C) 2016 ownCloud Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
|
@ -21,7 +21,6 @@
|
|||
package com.owncloud.android.media;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.Service;
|
||||
|
@ -39,14 +38,14 @@ import android.os.PowerManager;
|
|||
import android.support.v7.app.NotificationCompat;
|
||||
import android.widget.Toast;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import com.owncloud.android.R;
|
||||
import com.owncloud.android.datamodel.OCFile;
|
||||
import com.owncloud.android.lib.common.utils.Log_OC;
|
||||
import com.owncloud.android.ui.activity.FileActivity;
|
||||
import com.owncloud.android.ui.activity.FileDisplayActivity;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
|
||||
/**
|
||||
* Service that handles media playback, both audio and video.
|
||||
|
@ -59,7 +58,8 @@ public class MediaService extends Service implements OnCompletionListener, OnPre
|
|||
|
||||
private static final String TAG = MediaService.class.getSimpleName();
|
||||
|
||||
private static final String MY_PACKAGE = MediaService.class.getPackage() != null ? MediaService.class.getPackage().getName() : "com.owncloud.android.media";
|
||||
private static final String MY_PACKAGE = MediaService.class.getPackage() != null ?
|
||||
MediaService.class.getPackage().getName() : "com.owncloud.android.media";
|
||||
|
||||
/// Intent actions that we are prepared to handle
|
||||
public static final String ACTION_PLAY_FILE = MY_PACKAGE + ".action.PLAY_FILE";
|
||||
|
@ -162,7 +162,8 @@ public class MediaService extends Service implements OnCompletionListener, OnPre
|
|||
|
||||
} else if (extra == MediaPlayer.MEDIA_ERROR_UNSUPPORTED) {
|
||||
/* Added in API level 17
|
||||
Bitstream is conforming to the related coding standard or file spec, but the media framework does not support the feature.
|
||||
Bitstream is conforming to the related coding standard or file spec,
|
||||
but the media framework does not support the feature.
|
||||
Constant Value: -1010 (0xfffffc0e)
|
||||
*/
|
||||
messageId = R.string.media_err_unsupported;
|
||||
|
@ -190,7 +191,8 @@ public class MediaService extends Service implements OnCompletionListener, OnPre
|
|||
|
||||
} else if (what == MediaPlayer.MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK) {
|
||||
/* Added in API level 3
|
||||
The video is streamed and its container is not valid for progressive playback i.e the video's index (e.g moov atom) is not at the start of the file.
|
||||
The video is streamed and its container is not valid for progressive playback i.e the video's index
|
||||
(e.g moov atom) is not at the start of the file.
|
||||
Constant Value: 200 (0x000000c8)
|
||||
*/
|
||||
messageId = R.string.media_err_invalid_progressive_playback;
|
||||
|
@ -203,7 +205,8 @@ public class MediaService extends Service implements OnCompletionListener, OnPre
|
|||
*/
|
||||
/* MediaPlayer.MEDIA_ERROR_SERVER_DIED)
|
||||
Added in API level 1
|
||||
Media server died. In this case, the application must release the MediaPlayer object and instantiate a new one.
|
||||
Media server died. In this case, the application must release the MediaPlayer
|
||||
object and instantiate a new one.
|
||||
Constant Value: 100 (0x00000064)
|
||||
*/
|
||||
messageId = R.string.media_err_unknown;
|
||||
|
@ -471,22 +474,26 @@ public class MediaService extends Service implements OnCompletionListener, OnPre
|
|||
|
||||
} catch (SecurityException e) {
|
||||
Log_OC.e(TAG, "SecurityException playing " + mAccount.name + mFile.getRemotePath(), e);
|
||||
Toast.makeText(this, String.format(getString(R.string.media_err_security_ex), mFile.getFileName()), Toast.LENGTH_LONG).show();
|
||||
Toast.makeText(this, String.format(getString(R.string.media_err_security_ex), mFile.getFileName()),
|
||||
Toast.LENGTH_LONG).show();
|
||||
processStopRequest(true);
|
||||
|
||||
} catch (IOException e) {
|
||||
Log_OC.e(TAG, "IOException playing " + mAccount.name + mFile.getRemotePath(), e);
|
||||
Toast.makeText(this, String.format(getString(R.string.media_err_io_ex), mFile.getFileName()), Toast.LENGTH_LONG).show();
|
||||
Toast.makeText(this, String.format(getString(R.string.media_err_io_ex), mFile.getFileName()),
|
||||
Toast.LENGTH_LONG).show();
|
||||
processStopRequest(true);
|
||||
|
||||
} catch (IllegalStateException e) {
|
||||
Log_OC.e(TAG, "IllegalStateException " + mAccount.name + mFile.getRemotePath(), e);
|
||||
Toast.makeText(this, String.format(getString(R.string.media_err_unexpected), mFile.getFileName()), Toast.LENGTH_LONG).show();
|
||||
Toast.makeText(this, String.format(getString(R.string.media_err_unexpected), mFile.getFileName()),
|
||||
Toast.LENGTH_LONG).show();
|
||||
processStopRequest(true);
|
||||
|
||||
} catch (IllegalArgumentException e) {
|
||||
Log_OC.e(TAG, "IllegalArgumentException " + mAccount.name + mFile.getRemotePath(), e);
|
||||
Toast.makeText(this, String.format(getString(R.string.media_err_unexpected), mFile.getFileName()), Toast.LENGTH_LONG).show();
|
||||
Toast.makeText(this, String.format(getString(R.string.media_err_unexpected), mFile.getFileName()),
|
||||
Toast.LENGTH_LONG).show();
|
||||
processStopRequest(true);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* ownCloud Android client application
|
||||
*
|
||||
* @author David A. Velasco
|
||||
* Copyright (C) 2015 ownCloud Inc.
|
||||
* Copyright (C) 2016 ownCloud Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
|
@ -21,16 +21,16 @@
|
|||
package com.owncloud.android.media;
|
||||
|
||||
|
||||
import com.owncloud.android.datamodel.OCFile;
|
||||
import com.owncloud.android.lib.common.utils.Log_OC;
|
||||
import com.owncloud.android.media.MediaService.State;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.content.Intent;
|
||||
import android.media.MediaPlayer;
|
||||
import android.os.Binder;
|
||||
import android.widget.MediaController;
|
||||
|
||||
import com.owncloud.android.datamodel.OCFile;
|
||||
import com.owncloud.android.lib.common.utils.Log_OC;
|
||||
import com.owncloud.android.media.MediaService.State;
|
||||
|
||||
|
||||
/**
|
||||
* Binder allowing client components to perform operations on on the MediaPlayer managed by a MediaService instance.
|
||||
|
@ -94,8 +94,7 @@ public class MediaServiceBinder extends Binder implements MediaController.MediaP
|
|||
public int getCurrentPosition() {
|
||||
MediaPlayer currentPlayer = mService.getPlayer();
|
||||
if (currentPlayer != null) {
|
||||
int pos = currentPlayer.getCurrentPosition();
|
||||
return pos;
|
||||
return currentPlayer.getCurrentPosition();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
@ -105,8 +104,7 @@ public class MediaServiceBinder extends Binder implements MediaController.MediaP
|
|||
public int getDuration() {
|
||||
MediaPlayer currentPlayer = mService.getPlayer();
|
||||
if (currentPlayer != null) {
|
||||
int dur = currentPlayer.getDuration();
|
||||
return dur;
|
||||
return currentPlayer.getDuration();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
/**
|
||||
* ownCloud Android client application
|
||||
*
|
||||
* @author David A. Velasco
|
||||
* Copyright (C) 2016 ownCloud Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.owncloud.android.operations;
|
||||
|
||||
import android.accounts.Account;
|
||||
|
||||
import com.owncloud.android.datamodel.OCFile;
|
||||
import com.owncloud.android.lib.common.OwnCloudClient;
|
||||
import com.owncloud.android.lib.common.operations.RemoteOperation;
|
||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
|
||||
import com.owncloud.android.lib.resources.files.ExistenceCheckRemoteOperation;
|
||||
import com.owncloud.android.operations.common.SyncOperation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Checks validity of currently stored credentials for a given OC account
|
||||
*/
|
||||
public class CheckCurrentCredentialsOperation extends SyncOperation {
|
||||
|
||||
private Account mAccount = null;
|
||||
|
||||
public CheckCurrentCredentialsOperation(Account account) {
|
||||
if (account == null) {
|
||||
throw new IllegalArgumentException("NULL account");
|
||||
}
|
||||
mAccount = account;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RemoteOperationResult run(OwnCloudClient client) {
|
||||
RemoteOperationResult result = null;
|
||||
if (!getStorageManager().getAccount().name.equals(mAccount.name)) {
|
||||
result = new RemoteOperationResult(new IllegalStateException(
|
||||
"Account to validate is not the account connected to!")
|
||||
);
|
||||
} else {
|
||||
RemoteOperation check = new ExistenceCheckRemoteOperation(OCFile.ROOT_PATH, false);
|
||||
result = check.execute(client);
|
||||
ArrayList<Object> data = new ArrayList<Object>();
|
||||
data.add(mAccount);
|
||||
result.setData(data);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
|
@ -34,6 +34,8 @@ import com.owncloud.android.lib.resources.files.ExistenceCheckRemoteOperation;
|
|||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
|
||||
import org.apache.commons.httpclient.HttpStatus;
|
||||
|
||||
/**
|
||||
* Operation to find out what authentication method requires
|
||||
* the server to access files.
|
||||
|
@ -99,7 +101,7 @@ public class DetectAuthenticationMethodOperation extends RemoteOperation {
|
|||
}
|
||||
|
||||
// analyze response
|
||||
if (result.getCode() == ResultCode.UNAUTHORIZED) {
|
||||
if (result.getHttpCode() == HttpStatus.SC_UNAUTHORIZED) {
|
||||
String authRequest = ((result.getAuthenticateHeader()).trim()).toLowerCase();
|
||||
if (authRequest.startsWith("basic")) {
|
||||
authMethod = AuthenticationMethod.BASIC_HTTP_AUTH;
|
||||
|
|
|
@ -1,43 +1,42 @@
|
|||
/**
|
||||
* ownCloud Android client application
|
||||
* ownCloud Android client application
|
||||
*
|
||||
* @author David A. Velasco
|
||||
* @author masensio
|
||||
* Copyright (C) 2012 Bartek Przybylski
|
||||
* Copyright (C) 2015 ownCloud Inc.
|
||||
* @author David A. Velasco
|
||||
* @author masensio
|
||||
* Copyright (C) 2012 Bartek Przybylski
|
||||
* Copyright (C) 2015 ownCloud Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.owncloud.android.operations;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
import com.owncloud.android.datamodel.OCFile;
|
||||
import com.owncloud.android.files.services.FileDownloader;
|
||||
import com.owncloud.android.files.services.FileUploader;
|
||||
import com.owncloud.android.lib.common.OwnCloudClient;
|
||||
import com.owncloud.android.lib.resources.files.RemoteFile;
|
||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
|
||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;
|
||||
import com.owncloud.android.lib.common.utils.Log_OC;
|
||||
import com.owncloud.android.lib.resources.files.ReadRemoteFileOperation;
|
||||
import com.owncloud.android.lib.resources.files.RemoteFile;
|
||||
import com.owncloud.android.operations.common.SyncOperation;
|
||||
import com.owncloud.android.utils.FileStorageUtils;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
/**
|
||||
* Remote operation performing the read of remote file in the ownCloud server.
|
||||
*/
|
||||
|
@ -45,44 +44,44 @@ import android.content.Intent;
|
|||
public class SynchronizeFileOperation extends SyncOperation {
|
||||
|
||||
private String TAG = SynchronizeFileOperation.class.getSimpleName();
|
||||
|
||||
|
||||
private OCFile mLocalFile;
|
||||
private String mRemotePath;
|
||||
private OCFile mServerFile;
|
||||
private Account mAccount;
|
||||
private boolean mSyncFileContents;
|
||||
private Context mContext;
|
||||
|
||||
|
||||
private boolean mTransferWasRequested = false;
|
||||
|
||||
/**
|
||||
* When 'false', uploads to the server are not done; only downloads or conflict detection.
|
||||
* This is a temporal field.
|
||||
/**
|
||||
* When 'false', uploads to the server are not done; only downloads or conflict detection.
|
||||
* This is a temporal field.
|
||||
* TODO Remove when 'folder synchronization' replaces 'folder download'.
|
||||
*/
|
||||
*/
|
||||
private boolean mAllowUploads;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Constructor for "full synchronization mode".
|
||||
*
|
||||
* <p/>
|
||||
* Uses remotePath to retrieve all the data both in local cache and in the remote OC server
|
||||
* when the operation is executed, instead of reusing {@link OCFile} instances.
|
||||
*
|
||||
* <p/>
|
||||
* Useful for direct synchronization of a single file.
|
||||
*
|
||||
* @param
|
||||
* @param account ownCloud account holding the file.
|
||||
* @param syncFileContents When 'true', transference of data will be started by the
|
||||
* operation if needed and no conflict is detected.
|
||||
* @param context Android context; needed to start transfers.
|
||||
*
|
||||
* @param
|
||||
* @param account ownCloud account holding the file.
|
||||
* @param syncFileContents When 'true', transference of data will be started by the
|
||||
* operation if needed and no conflict is detected.
|
||||
* @param context Android context; needed to start transfers.
|
||||
*/
|
||||
public SynchronizeFileOperation(
|
||||
String remotePath,
|
||||
Account account,
|
||||
String remotePath,
|
||||
Account account,
|
||||
boolean syncFileContents,
|
||||
Context context) {
|
||||
|
||||
|
||||
mRemotePath = remotePath;
|
||||
mLocalFile = null;
|
||||
mServerFile = null;
|
||||
|
@ -92,33 +91,33 @@ public class SynchronizeFileOperation extends SyncOperation {
|
|||
mAllowUploads = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Constructor allowing to reuse {@link OCFile} instances just queried from local cache or
|
||||
* from remote OC server.
|
||||
*
|
||||
*
|
||||
* Useful to include this operation as part of the synchronization of a folder
|
||||
* (or a full account), avoiding the repetition of fetch operations (both in local database
|
||||
* or remote server).
|
||||
*
|
||||
*
|
||||
* At least one of localFile or serverFile MUST NOT BE NULL. If you don't have none of them,
|
||||
* use the other constructor.
|
||||
*
|
||||
* @param localFile Data of file (just) retrieved from local cache/database.
|
||||
* @param serverFile Data of file (just) retrieved from a remote server. If null,
|
||||
* will be retrieved from network by the operation when executed.
|
||||
* @param account ownCloud account holding the file.
|
||||
* @param syncFileContents When 'true', transference of data will be started by the
|
||||
* operation if needed and no conflict is detected.
|
||||
* @param context Android context; needed to start transfers.
|
||||
*
|
||||
* @param localFile Data of file (just) retrieved from local cache/database.
|
||||
* @param serverFile Data of file (just) retrieved from a remote server. If null,
|
||||
* will be retrieved from network by the operation when executed.
|
||||
* @param account ownCloud account holding the file.
|
||||
* @param syncFileContents When 'true', transference of data will be started by the
|
||||
* operation if needed and no conflict is detected.
|
||||
* @param context Android context; needed to start transfers.
|
||||
*/
|
||||
public SynchronizeFileOperation(
|
||||
OCFile localFile,
|
||||
OCFile serverFile,
|
||||
Account account,
|
||||
OCFile serverFile,
|
||||
Account account,
|
||||
boolean syncFileContents,
|
||||
Context context) {
|
||||
|
||||
|
||||
mLocalFile = localFile;
|
||||
mServerFile = serverFile;
|
||||
if (mLocalFile != null) {
|
||||
|
@ -137,55 +136,55 @@ public class SynchronizeFileOperation extends SyncOperation {
|
|||
mContext = context;
|
||||
mAllowUploads = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Temporal constructor.
|
||||
*
|
||||
*
|
||||
* Extends the previous one to allow constrained synchronizations where uploads are never
|
||||
* performed - only downloads or conflict detection.
|
||||
*
|
||||
*
|
||||
* Do not use unless you are involved in 'folder synchronization' or 'folder download' work
|
||||
* in progress.
|
||||
*
|
||||
*
|
||||
* TODO Remove when 'folder synchronization' replaces 'folder download'.
|
||||
*
|
||||
* @param localFile Data of file (just) retrieved from local cache/database.
|
||||
* MUSTN't be null.
|
||||
* @param serverFile Data of file (just) retrieved from a remote server.
|
||||
* If null, will be retrieved from network by the operation
|
||||
* when executed.
|
||||
* @param account ownCloud account holding the file.
|
||||
* @param syncFileContents When 'true', transference of data will be started by the
|
||||
* operation if needed and no conflict is detected.
|
||||
* @param allowUploads When 'false', uploads to the server are not done;
|
||||
* only downloads or conflict detection.
|
||||
* @param context Android context; needed to start transfers.
|
||||
*
|
||||
* @param localFile Data of file (just) retrieved from local cache/database.
|
||||
* MUSTN't be null.
|
||||
* @param serverFile Data of file (just) retrieved from a remote server.
|
||||
* If null, will be retrieved from network by the operation
|
||||
* when executed.
|
||||
* @param account ownCloud account holding the file.
|
||||
* @param syncFileContents When 'true', transference of data will be started by the
|
||||
* operation if needed and no conflict is detected.
|
||||
* @param allowUploads When 'false', uploads to the server are not done;
|
||||
* only downloads or conflict detection.
|
||||
* @param context Android context; needed to start transfers.
|
||||
*/
|
||||
public SynchronizeFileOperation(
|
||||
OCFile localFile,
|
||||
OCFile serverFile,
|
||||
Account account,
|
||||
OCFile serverFile,
|
||||
Account account,
|
||||
boolean syncFileContents,
|
||||
boolean allowUploads,
|
||||
boolean allowUploads,
|
||||
Context context) {
|
||||
|
||||
|
||||
this(localFile, serverFile, account, syncFileContents, context);
|
||||
mAllowUploads = allowUploads;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
protected RemoteOperationResult run(OwnCloudClient client) {
|
||||
|
||||
RemoteOperationResult result = null;
|
||||
mTransferWasRequested = false;
|
||||
|
||||
|
||||
if (mLocalFile == null) {
|
||||
// Get local file from the DB
|
||||
mLocalFile = getStorageManager().getFileByPath(mRemotePath);
|
||||
}
|
||||
|
||||
|
||||
if (!mLocalFile.isDown()) {
|
||||
/// easy decision
|
||||
requestForDownload(mLocalFile);
|
||||
|
@ -197,13 +196,13 @@ public class SynchronizeFileOperation extends SyncOperation {
|
|||
if (mServerFile == null) {
|
||||
ReadRemoteFileOperation operation = new ReadRemoteFileOperation(mRemotePath);
|
||||
result = operation.execute(client);
|
||||
if (result.isSuccess()){
|
||||
if (result.isSuccess()) {
|
||||
mServerFile = FileStorageUtils.fillOCFile((RemoteFile) result.getData().get(0));
|
||||
mServerFile.setLastSyncDateForProperties(System.currentTimeMillis());
|
||||
}
|
||||
}
|
||||
|
||||
if (mServerFile != null) {
|
||||
if (mServerFile != null) {
|
||||
|
||||
/// check changes in server and local file
|
||||
boolean serverChanged = false;
|
||||
|
@ -215,7 +214,7 @@ public class SynchronizeFileOperation extends SyncOperation {
|
|||
serverChanged = (!mServerFile.getEtag().equals(mLocalFile.getEtag()));
|
||||
}
|
||||
boolean localChanged = (
|
||||
mLocalFile.getLocalModificationTimestamp() > mLocalFile.getLastSyncDateForData()
|
||||
mLocalFile.getLocalModificationTimestamp() > mLocalFile.getLastSyncDateForData()
|
||||
);
|
||||
|
||||
/// decide action to perform depending upon changes
|
||||
|
@ -240,7 +239,7 @@ public class SynchronizeFileOperation extends SyncOperation {
|
|||
|
||||
} else if (serverChanged) {
|
||||
mLocalFile.setRemoteId(mServerFile.getRemoteId());
|
||||
|
||||
|
||||
if (mSyncFileContents) {
|
||||
requestForDownload(mLocalFile); // local, not server; we won't to keep
|
||||
// the value of favorite!
|
||||
|
@ -277,31 +276,24 @@ public class SynchronizeFileOperation extends SyncOperation {
|
|||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Requests for an upload to the FileUploader service
|
||||
*
|
||||
* @param file OCFile object representing the file to upload
|
||||
*
|
||||
* @param file OCFile object representing the file to upload
|
||||
*/
|
||||
private void requestForUpload(OCFile file) {
|
||||
Intent i = new Intent(mContext, FileUploader.class);
|
||||
i.putExtra(FileUploader.KEY_ACCOUNT, mAccount);
|
||||
i.putExtra(FileUploader.KEY_FILE, file);
|
||||
/*i.putExtra(FileUploader.KEY_REMOTE_FILE, mRemotePath);
|
||||
// doing this we would lose the value of isFavorite in the road, and maybe
|
||||
// it's not updated in the database when the FileUploader service gets it!
|
||||
i.putExtra(FileUploader.KEY_LOCAL_FILE, localFile.getStoragePath());*/
|
||||
i.putExtra(FileUploader.KEY_UPLOAD_TYPE, FileUploader.UPLOAD_SINGLE_FILE);
|
||||
i.putExtra(FileUploader.KEY_FORCE_OVERWRITE, true);
|
||||
mContext.startService(i);
|
||||
FileUploader.UploadRequester requester = new FileUploader.UploadRequester();
|
||||
requester.uploadUpdate(mContext, mAccount, file, FileUploader.LOCAL_BEHAVIOUR_MOVE, true);
|
||||
|
||||
mTransferWasRequested = true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Requests for a download to the FileDownloader service
|
||||
*
|
||||
* @param file OCFile object representing the file to download
|
||||
*
|
||||
* @param file OCFile object representing the file to download
|
||||
*/
|
||||
private void requestForDownload(OCFile file) {
|
||||
Intent i = new Intent(mContext, FileDownloader.class);
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* ownCloud Android client application
|
||||
*
|
||||
* @author David A. Velasco
|
||||
* Copyright (C) 2015 ownCloud Inc.
|
||||
* Copyright (C) 2016 ownCloud Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
|
@ -50,8 +50,6 @@ import com.owncloud.android.utils.FileStorageUtils;
|
|||
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
//import android.support.v4.content.LocalBroadcastManager;
|
||||
|
||||
|
||||
/**
|
||||
* Remote operation performing the synchronization of the list of files contained
|
||||
|
@ -479,6 +477,18 @@ public class SynchronizeFolderOperation extends SyncOperation {
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates and populates a new {@link com.owncloud.android.datamodel.OCFile}
|
||||
* object with the data read from the server.
|
||||
*
|
||||
* @param remote remote file read from the server (remote file or folder).
|
||||
* @return New OCFile instance representing the remote resource described by we.
|
||||
*/
|
||||
private OCFile fillOCFile(RemoteFile remote) {
|
||||
return FileStorageUtils.fillOCFile(remote);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Scans the default location for saving local copies of files searching for
|
||||
* a 'lost' file with the same full name as the {@link com.owncloud.android.datamodel.OCFile}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* ownCloud Android client application
|
||||
*
|
||||
* @author David A. Velasco
|
||||
* Copyright (C) 2015 ownCloud Inc.
|
||||
* Copyright (C) 2016 ownCloud Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
|
@ -20,6 +20,37 @@
|
|||
|
||||
package com.owncloud.android.operations;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
|
||||
import com.owncloud.android.datamodel.FileDataStorageManager;
|
||||
import com.owncloud.android.datamodel.OCFile;
|
||||
import com.owncloud.android.db.OCUpload;
|
||||
import com.owncloud.android.db.PreferenceReader;
|
||||
import com.owncloud.android.files.services.FileUploader;
|
||||
import com.owncloud.android.lib.common.OwnCloudClient;
|
||||
import com.owncloud.android.lib.common.network.OnDatatransferProgressListener;
|
||||
import com.owncloud.android.lib.common.network.ProgressiveDataTransferer;
|
||||
import com.owncloud.android.lib.common.operations.OperationCancelledException;
|
||||
import com.owncloud.android.lib.common.operations.RemoteOperation;
|
||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
|
||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;
|
||||
import com.owncloud.android.lib.common.utils.Log_OC;
|
||||
import com.owncloud.android.lib.resources.files.ChunkedUploadRemoteFileOperation;
|
||||
import com.owncloud.android.lib.resources.files.ExistenceCheckRemoteOperation;
|
||||
import com.owncloud.android.lib.resources.files.ReadRemoteFileOperation;
|
||||
import com.owncloud.android.lib.resources.files.RemoteFile;
|
||||
import com.owncloud.android.lib.resources.files.UploadRemoteFileOperation;
|
||||
import com.owncloud.android.operations.common.SyncOperation;
|
||||
import com.owncloud.android.utils.ConnectivityUtils;
|
||||
import com.owncloud.android.utils.FileStorageUtils;
|
||||
import com.owncloud.android.utils.MimetypeIconUtil;
|
||||
import com.owncloud.android.utils.UriUtils;
|
||||
|
||||
import org.apache.commons.httpclient.HttpStatus;
|
||||
import org.apache.commons.httpclient.methods.RequestEntity;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
|
@ -32,67 +63,116 @@ import java.util.Iterator;
|
|||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import org.apache.commons.httpclient.HttpStatus;
|
||||
import org.apache.commons.httpclient.methods.RequestEntity;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
|
||||
import com.owncloud.android.MainApp;
|
||||
import com.owncloud.android.datamodel.FileDataStorageManager;
|
||||
import com.owncloud.android.datamodel.OCFile;
|
||||
import com.owncloud.android.files.services.FileUploader;
|
||||
import com.owncloud.android.lib.common.OwnCloudClient;
|
||||
import com.owncloud.android.lib.common.network.OnDatatransferProgressListener;
|
||||
import com.owncloud.android.lib.common.network.ProgressiveDataTransferer;
|
||||
import com.owncloud.android.lib.common.operations.OperationCancelledException;
|
||||
import com.owncloud.android.lib.common.operations.RemoteOperation;
|
||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
|
||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;
|
||||
import com.owncloud.android.lib.common.utils.Log_OC;
|
||||
import com.owncloud.android.lib.resources.files.ChunkedUploadRemoteFileOperation;
|
||||
import com.owncloud.android.lib.resources.files.ExistenceCheckRemoteOperation;
|
||||
import com.owncloud.android.lib.resources.files.UploadRemoteFileOperation;
|
||||
import com.owncloud.android.utils.FileStorageUtils;
|
||||
import com.owncloud.android.utils.UriUtils;
|
||||
|
||||
|
||||
/**
|
||||
* Remote operation performing the upload of a file to an ownCloud server
|
||||
* Operation performing the update in the ownCloud server
|
||||
* of a file that was modified locally.
|
||||
*/
|
||||
public class UploadFileOperation extends RemoteOperation {
|
||||
public class UploadFileOperation extends SyncOperation {
|
||||
|
||||
|
||||
private static final String MIME_TYPE_PDF = "application/pdf";
|
||||
private static final String FILE_EXTENSION_PDF = ".pdf";
|
||||
|
||||
public static final int CREATED_BY_USER = 0;
|
||||
public static final int CREATED_AS_INSTANT_PICTURE = 1;
|
||||
public static final int CREATED_AS_INSTANT_VIDEO = 2;
|
||||
|
||||
|
||||
/**
|
||||
* Checks if content provider, using the content:// scheme, returns a file with mime-type
|
||||
* 'application/pdf' but file has not extension
|
||||
* @param localPath Full path to a file in the local file system.
|
||||
* @param mimeType MIME type of the file.
|
||||
* @return true if is needed to add the pdf file extension to the file
|
||||
*
|
||||
* TODO - move to OCFile or Utils class
|
||||
*/
|
||||
private static boolean isPdfFileFromContentProviderWithoutExtension(String localPath,
|
||||
String mimeType) {
|
||||
return localPath.startsWith(UriUtils.URI_CONTENT_SCHEME) &&
|
||||
mimeType.equals(MIME_TYPE_PDF) &&
|
||||
!localPath.endsWith(FILE_EXTENSION_PDF);
|
||||
}
|
||||
|
||||
public static OCFile obtainNewOCFileToUpload(String remotePath, String localPath, String mimeType) {
|
||||
|
||||
// MIME type
|
||||
if (mimeType == null || mimeType.length() <= 0) {
|
||||
mimeType = MimetypeIconUtil.getBestMimeTypeByFilename(localPath);
|
||||
}
|
||||
|
||||
// TODO - this is a horrible special case that should not be handled this way
|
||||
if (isPdfFileFromContentProviderWithoutExtension(localPath, mimeType)){
|
||||
remotePath += FILE_EXTENSION_PDF;
|
||||
}
|
||||
|
||||
OCFile newFile = new OCFile(remotePath);
|
||||
newFile.setStoragePath(localPath);
|
||||
newFile.setLastSyncDateForProperties(0);
|
||||
newFile.setLastSyncDateForData(0);
|
||||
|
||||
// size
|
||||
if (localPath != null && localPath.length() > 0) {
|
||||
File localFile = new File(localPath);
|
||||
newFile.setFileLength(localFile.length());
|
||||
newFile.setLastSyncDateForData(localFile.lastModified());
|
||||
} // don't worry about not assigning size, the problems with localPath
|
||||
// are checked when the UploadFileOperation instance is created
|
||||
|
||||
|
||||
newFile.setMimetype(mimeType);
|
||||
|
||||
return newFile;
|
||||
}
|
||||
|
||||
|
||||
|
||||
private static final String TAG = UploadFileOperation.class.getSimpleName();
|
||||
|
||||
private Account mAccount;
|
||||
/**
|
||||
* OCFile which is to be uploaded.
|
||||
*/
|
||||
private OCFile mFile;
|
||||
/**
|
||||
* Original OCFile which is to be uploaded in case file had to be renamed
|
||||
* (if forceOverwrite==false and remote file already exists).
|
||||
*/
|
||||
private OCFile mOldFile;
|
||||
private String mRemotePath = null;
|
||||
private boolean mChunked = false;
|
||||
private boolean mIsInstant = false;
|
||||
private boolean mRemoteFolderToBeCreated = false;
|
||||
private boolean mForceOverwrite = false;
|
||||
private int mLocalBehaviour = FileUploader.LOCAL_BEHAVIOUR_COPY;
|
||||
private int mCreatedBy = CREATED_BY_USER;
|
||||
|
||||
private boolean mWasRenamed = false;
|
||||
private String mOriginalFileName = null;
|
||||
private long mOCUploadId = -1;
|
||||
/**
|
||||
* Local path to file which is to be uploaded (before any possible renaming or moving).
|
||||
*/
|
||||
private String mOriginalStoragePath = null;
|
||||
private Set<OnDatatransferProgressListener> mDataTransferListeners = new HashSet<OnDatatransferProgressListener>();
|
||||
private AtomicBoolean mCancellationRequested = new AtomicBoolean(false);
|
||||
private OnRenameListener mRenameUploadListener;
|
||||
|
||||
private final AtomicBoolean mCancellationRequested = new AtomicBoolean(false);
|
||||
private final AtomicBoolean mUploadStarted = new AtomicBoolean(false);
|
||||
|
||||
private Context mContext;
|
||||
|
||||
|
||||
private UploadRemoteFileOperation mUploadOperation;
|
||||
|
||||
protected RequestEntity mEntity = null;
|
||||
|
||||
|
||||
public UploadFileOperation( Account account,
|
||||
OCFile file,
|
||||
boolean chunked,
|
||||
boolean isInstant,
|
||||
boolean forceOverwrite,
|
||||
int localBehaviour,
|
||||
Context context) {
|
||||
public UploadFileOperation(Account account,
|
||||
OCFile file,
|
||||
boolean chunked,
|
||||
boolean forceOverwrite,
|
||||
int localBehaviour,
|
||||
Context context
|
||||
) {
|
||||
if (account == null)
|
||||
throw new IllegalArgumentException("Illegal NULL account in UploadFileOperation " +
|
||||
"creation");
|
||||
|
@ -108,7 +188,6 @@ public class UploadFileOperation extends RemoteOperation {
|
|||
mFile = file;
|
||||
mRemotePath = file.getRemotePath();
|
||||
mChunked = chunked;
|
||||
mIsInstant = isInstant;
|
||||
mForceOverwrite = forceOverwrite;
|
||||
mLocalBehaviour = localBehaviour;
|
||||
mOriginalStoragePath = mFile.getStoragePath();
|
||||
|
@ -116,6 +195,42 @@ public class UploadFileOperation extends RemoteOperation {
|
|||
mContext = context;
|
||||
}
|
||||
|
||||
public UploadFileOperation(Account account,
|
||||
OCUpload upload,
|
||||
boolean chunked,
|
||||
boolean forceOverwrite,
|
||||
int localBehaviour,
|
||||
Context context
|
||||
) {
|
||||
if (account == null)
|
||||
throw new IllegalArgumentException("Illegal NULL account in UploadFileOperation " +
|
||||
"creation");
|
||||
if (upload == null)
|
||||
throw new IllegalArgumentException("Illegal NULL file in UploadFileOperation creation");
|
||||
if (upload.getLocalPath() == null || upload.getLocalPath().length() <= 0) {
|
||||
throw new IllegalArgumentException(
|
||||
"Illegal file in UploadFileOperation; storage path invalid: "
|
||||
+ upload.getLocalPath());
|
||||
}
|
||||
|
||||
mAccount = account;
|
||||
mFile = obtainNewOCFileToUpload(
|
||||
upload.getRemotePath(),
|
||||
upload.getLocalPath(),
|
||||
upload.getMimeType()
|
||||
);
|
||||
mRemotePath = upload.getRemotePath();
|
||||
mChunked = chunked;
|
||||
mForceOverwrite = forceOverwrite;
|
||||
mLocalBehaviour = localBehaviour;
|
||||
mOriginalStoragePath = mFile.getStoragePath();
|
||||
mOriginalFileName = mFile.getFileName();
|
||||
mContext = context;
|
||||
mOCUploadId = upload.getUploadId();
|
||||
mCreatedBy = upload.getCreadtedBy();
|
||||
mRemoteFolderToBeCreated = upload.isCreateRemoteFolder();
|
||||
}
|
||||
|
||||
public Account getAccount() {
|
||||
return mAccount;
|
||||
}
|
||||
|
@ -128,6 +243,10 @@ public class UploadFileOperation extends RemoteOperation {
|
|||
return mFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* If remote file was renamed, return original OCFile which was uploaded. Is
|
||||
* null is file was not renamed.
|
||||
*/
|
||||
public OCFile getOldFile() {
|
||||
return mOldFile;
|
||||
}
|
||||
|
@ -148,30 +267,48 @@ public class UploadFileOperation extends RemoteOperation {
|
|||
return mFile.getMimetype();
|
||||
}
|
||||
|
||||
public boolean isInstant() {
|
||||
return mIsInstant;
|
||||
}
|
||||
|
||||
public boolean isRemoteFolderToBeCreated() {
|
||||
return mRemoteFolderToBeCreated;
|
||||
public int getLocalBehaviour() {
|
||||
return mLocalBehaviour;
|
||||
}
|
||||
|
||||
public void setRemoteFolderToBeCreated() {
|
||||
mRemoteFolderToBeCreated = true;
|
||||
}
|
||||
|
||||
public boolean getForceOverwrite() {
|
||||
return mForceOverwrite;
|
||||
}
|
||||
|
||||
public boolean wasRenamed() {
|
||||
return mWasRenamed;
|
||||
}
|
||||
|
||||
public void setCreatedBy(int createdBy) {
|
||||
mCreatedBy = createdBy;
|
||||
if (createdBy < CREATED_BY_USER || CREATED_AS_INSTANT_VIDEO < createdBy) {
|
||||
mCreatedBy = CREATED_BY_USER;
|
||||
}
|
||||
}
|
||||
|
||||
public int getCreatedBy () {
|
||||
return mCreatedBy;
|
||||
}
|
||||
|
||||
public boolean isInstantPicture() {
|
||||
return mCreatedBy == CREATED_AS_INSTANT_PICTURE;
|
||||
}
|
||||
|
||||
public boolean isInstantVideo() {
|
||||
return mCreatedBy == CREATED_AS_INSTANT_VIDEO;
|
||||
}
|
||||
|
||||
public void setOCUploadId(long id){
|
||||
mOCUploadId = id;
|
||||
}
|
||||
public long getOCUploadId() {
|
||||
return mOCUploadId;
|
||||
}
|
||||
|
||||
public Set<OnDatatransferProgressListener> getDataTransferListeners() {
|
||||
return mDataTransferListeners;
|
||||
}
|
||||
|
||||
|
||||
public void addDatatransferProgressListener (OnDatatransferProgressListener listener) {
|
||||
synchronized (mDataTransferListeners) {
|
||||
mDataTransferListeners.add(listener);
|
||||
|
@ -179,8 +316,11 @@ public class UploadFileOperation extends RemoteOperation {
|
|||
if (mEntity != null) {
|
||||
((ProgressiveDataTransferer)mEntity).addDatatransferProgressListener(listener);
|
||||
}
|
||||
if(mUploadOperation != null){
|
||||
mUploadOperation.addDatatransferProgressListener(listener);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void removeDatatransferProgressListener(OnDatatransferProgressListener listener) {
|
||||
synchronized (mDataTransferListeners) {
|
||||
mDataTransferListeners.remove(listener);
|
||||
|
@ -188,125 +328,87 @@ public class UploadFileOperation extends RemoteOperation {
|
|||
if (mEntity != null) {
|
||||
((ProgressiveDataTransferer)mEntity).removeDatatransferProgressListener(listener);
|
||||
}
|
||||
if(mUploadOperation != null){
|
||||
mUploadOperation.removeDatatransferProgressListener(listener);
|
||||
}
|
||||
}
|
||||
|
||||
public void addRenameUploadListener (OnRenameListener listener) {
|
||||
mRenameUploadListener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RemoteOperationResult run(OwnCloudClient client) {
|
||||
mCancellationRequested.set(false);
|
||||
mUploadStarted.set(true);
|
||||
RemoteOperationResult result = null;
|
||||
boolean localCopyPassed = false, nameCheckPassed = false;
|
||||
File temporalFile = null, originalFile = new File(mOriginalStoragePath), expectedFile = null;
|
||||
|
||||
try {
|
||||
// / rename the file to upload, if necessary
|
||||
|
||||
/// Check that connectivity conditions are met and delays the upload otherwise
|
||||
if (delayForWifi()) {
|
||||
Log_OC.d(TAG, "Upload delayed until WiFi is available: " + getRemotePath());
|
||||
return new RemoteOperationResult(ResultCode.DELAYED_FOR_WIFI);
|
||||
}
|
||||
|
||||
/// check if the file continues existing before schedule the operation
|
||||
if (!originalFile.exists()) {
|
||||
Log_OC.d(TAG, mOriginalStoragePath.toString() + " not exists anymore");
|
||||
return new RemoteOperationResult(ResultCode.LOCAL_FILE_NOT_FOUND);
|
||||
}
|
||||
|
||||
/// check the existence of the parent folder for the file to upload
|
||||
String remoteParentPath = new File(getRemotePath()).getParent();
|
||||
remoteParentPath = remoteParentPath.endsWith(OCFile.PATH_SEPARATOR) ?
|
||||
remoteParentPath : remoteParentPath + OCFile.PATH_SEPARATOR;
|
||||
result = grantFolderExistence(remoteParentPath, client);
|
||||
if (!result.isSuccess()) {
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// set parent local id in uploading file
|
||||
OCFile parent = getStorageManager().getFileByPath(remoteParentPath);
|
||||
mFile.setParentId(parent.getFileId());
|
||||
|
||||
/// automatic rename of file to upload in case of name collision in server
|
||||
Log_OC.d(TAG, "Checking name collision in server");
|
||||
if (!mForceOverwrite) {
|
||||
String remotePath = getAvailableRemotePath(client, mRemotePath);
|
||||
mWasRenamed = !remotePath.equals(mRemotePath);
|
||||
if (mWasRenamed) {
|
||||
createNewOCFile(remotePath);
|
||||
Log_OC.d(TAG, "File renamed as " + remotePath);
|
||||
}
|
||||
mRemotePath = remotePath;
|
||||
mRenameUploadListener.onRenameUpload();
|
||||
}
|
||||
nameCheckPassed = true;
|
||||
|
||||
String expectedPath = FileStorageUtils.getDefaultSavePathFor(mAccount.name, mFile); // /
|
||||
// not
|
||||
// before
|
||||
// getAvailableRemotePath()
|
||||
// !!!
|
||||
if (mCancellationRequested.get()) {
|
||||
throw new OperationCancelledException();
|
||||
}
|
||||
|
||||
String expectedPath = FileStorageUtils.getDefaultSavePathFor(mAccount.name, mFile);
|
||||
expectedFile = new File(expectedPath);
|
||||
|
||||
// check location of local file; if not the expected, copy to a
|
||||
// temporal file before upload (if COPY is the expected behaviour)
|
||||
if (!mOriginalStoragePath.equals(expectedPath) &&
|
||||
mLocalBehaviour == FileUploader.LOCAL_BEHAVIOUR_COPY) {
|
||||
/// copy the file locally before uploading
|
||||
if (mLocalBehaviour == FileUploader.LOCAL_BEHAVIOUR_COPY &&
|
||||
!mOriginalStoragePath.equals(expectedPath)) {
|
||||
|
||||
if (FileStorageUtils.getUsableSpace(mAccount.name) < originalFile.length()) {
|
||||
result = new RemoteOperationResult(ResultCode.LOCAL_STORAGE_FULL);
|
||||
return result; // error condition when the file should be
|
||||
// copied
|
||||
String temporalPath = FileStorageUtils.getTemporalPath(mAccount.name) + mFile.getRemotePath();
|
||||
mFile.setStoragePath(temporalPath);
|
||||
temporalFile = new File(temporalPath);
|
||||
|
||||
} else {
|
||||
|
||||
String temporalPath = FileStorageUtils.getTemporalPath(mAccount.name) +
|
||||
mFile.getRemotePath();
|
||||
mFile.setStoragePath(temporalPath);
|
||||
temporalFile = new File(temporalPath);
|
||||
|
||||
File temporalParent = temporalFile.getParentFile();
|
||||
temporalParent.mkdirs();
|
||||
if (!temporalParent.isDirectory()) {
|
||||
throw new IOException("Unexpected error: parent directory could not be created");
|
||||
}
|
||||
temporalFile.createNewFile();
|
||||
if (!temporalFile.isFile()) {
|
||||
throw new IOException("Unexpected error: target file could not be created");
|
||||
}
|
||||
|
||||
InputStream in = null;
|
||||
OutputStream out = null;
|
||||
|
||||
try {
|
||||
|
||||
// In case document provider schema as 'content://'
|
||||
if (mOriginalStoragePath.startsWith(UriUtils.URI_CONTENT_SCHEME)) {
|
||||
|
||||
Uri uri = Uri.parse(mOriginalStoragePath);
|
||||
|
||||
in = MainApp.getAppContext().getContentResolver().openInputStream(uri);
|
||||
out = new FileOutputStream(temporalFile);
|
||||
|
||||
int nRead;
|
||||
byte[] data = new byte[16384];
|
||||
|
||||
while (!mCancellationRequested.get() &&
|
||||
(nRead = in.read(data, 0, data.length)) != -1) {
|
||||
out.write(data, 0, nRead);
|
||||
}
|
||||
out.flush();
|
||||
|
||||
} else {
|
||||
if (!mOriginalStoragePath.equals(temporalPath)) { // preventing
|
||||
// weird
|
||||
// but
|
||||
// possible
|
||||
// situation
|
||||
|
||||
in = new FileInputStream(originalFile);
|
||||
out = new FileOutputStream(temporalFile);
|
||||
byte[] buf = new byte[1024];
|
||||
int len;
|
||||
while (!mCancellationRequested.get() && (len = in.read(buf)) > 0) {
|
||||
out.write(buf, 0, len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mCancellationRequested.get()) {
|
||||
result = new RemoteOperationResult(new OperationCancelledException());
|
||||
}
|
||||
|
||||
|
||||
} catch (Exception e) {
|
||||
result = new RemoteOperationResult(ResultCode.LOCAL_STORAGE_NOT_COPIED);
|
||||
return result;
|
||||
|
||||
} finally {
|
||||
try {
|
||||
if (in != null)
|
||||
in.close();
|
||||
} catch (Exception e) {
|
||||
Log_OC.d(TAG, "Weird exception while closing input stream for " +
|
||||
mOriginalStoragePath + " (ignoring)", e);
|
||||
}
|
||||
try {
|
||||
if (out != null)
|
||||
out.close();
|
||||
} catch (Exception e) {
|
||||
Log_OC.d(TAG, "Weird exception while closing output stream for " +
|
||||
expectedPath + " (ignoring)", e);
|
||||
}
|
||||
}
|
||||
result = copy(originalFile, temporalFile);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
localCopyPassed = (result == null);
|
||||
|
||||
if (mCancellationRequested.get()) {
|
||||
throw new OperationCancelledException();
|
||||
}
|
||||
|
||||
/// perform the upload
|
||||
if ( mChunked &&
|
||||
|
@ -322,6 +424,7 @@ public class UploadFileOperation extends RemoteOperation {
|
|||
while (listener.hasNext()) {
|
||||
mUploadOperation.addDatatransferProgressListener(listener.next());
|
||||
}
|
||||
|
||||
if (mCancellationRequested.get()) {
|
||||
throw new OperationCancelledException();
|
||||
}
|
||||
|
@ -335,53 +438,17 @@ public class UploadFileOperation extends RemoteOperation {
|
|||
mFile.setStoragePath("");
|
||||
} else {
|
||||
mFile.setStoragePath(expectedPath);
|
||||
File fileToMove = null;
|
||||
if (temporalFile != null) { // FileUploader.LOCAL_BEHAVIOUR_COPY
|
||||
// ; see where temporalFile was
|
||||
// set
|
||||
File fileToMove;
|
||||
if (temporalFile != null) { // FileUploader.LOCAL_BEHAVIOUR_COPY
|
||||
fileToMove = temporalFile;
|
||||
} else { // FileUploader.LOCAL_BEHAVIOUR_MOVE
|
||||
} else { // FileUploader.LOCAL_BEHAVIOUR_MOVE
|
||||
fileToMove = originalFile;
|
||||
}
|
||||
if (!expectedFile.equals(fileToMove)) {
|
||||
File expectedFolder = expectedFile.getParentFile();
|
||||
expectedFolder.mkdirs();
|
||||
|
||||
if (expectedFolder.isDirectory()){
|
||||
if (!fileToMove.renameTo(expectedFile)){
|
||||
// try to copy and then delete
|
||||
expectedFile.createNewFile();
|
||||
FileChannel inChannel = new FileInputStream(fileToMove).getChannel();
|
||||
FileChannel outChannel = new FileOutputStream(expectedFile).getChannel();
|
||||
|
||||
try {
|
||||
inChannel.transferTo(0, inChannel.size(), outChannel);
|
||||
fileToMove.delete();
|
||||
} catch (Exception e){
|
||||
mFile.setStoragePath(null); // forget the local file
|
||||
// by now, treat this as a success; the file was
|
||||
// uploaded; the user won't like that the local file
|
||||
// is not linked, but this should be a very rare
|
||||
// fail;
|
||||
// the best option could be show a warning message
|
||||
// (but not a fail)
|
||||
// result = new
|
||||
// RemoteOperationResult(ResultCode.LOCAL_STORAGE_NOT_MOVED);
|
||||
// return result;
|
||||
}
|
||||
finally {
|
||||
if (inChannel != null) inChannel.close();
|
||||
if (outChannel != null) outChannel.close();
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
mFile.setStoragePath(null);
|
||||
}
|
||||
}
|
||||
move(fileToMove, expectedFile);
|
||||
}
|
||||
FileDataStorageManager.triggerMediaScan(originalFile.getAbsolutePath());
|
||||
FileDataStorageManager.triggerMediaScan(expectedFile.getAbsolutePath());
|
||||
|
||||
} else if (result.getHttpCode() == HttpStatus.SC_PRECONDITION_FAILED ) {
|
||||
result = new RemoteOperationResult(ResultCode.SYNC_CONFLICT);
|
||||
}
|
||||
|
@ -390,6 +457,7 @@ public class UploadFileOperation extends RemoteOperation {
|
|||
result = new RemoteOperationResult(e);
|
||||
|
||||
} finally {
|
||||
mUploadStarted.set(false);
|
||||
if (temporalFile != null && !originalFile.equals(temporalFile)) {
|
||||
temporalFile.delete();
|
||||
}
|
||||
|
@ -401,16 +469,14 @@ public class UploadFileOperation extends RemoteOperation {
|
|||
result.getLogMessage());
|
||||
} else {
|
||||
if (result.getException() != null) {
|
||||
String complement = "";
|
||||
if (!nameCheckPassed) {
|
||||
complement = " (while checking file existence in server)";
|
||||
} else if (!localCopyPassed) {
|
||||
complement = " (while copying local file to " +
|
||||
FileStorageUtils.getSavePath(mAccount.name)
|
||||
+ ")";
|
||||
if(result.isCancelled()){
|
||||
Log_OC.w(TAG, "Upload of " + mOriginalStoragePath + " to " + mRemotePath +
|
||||
": " + result.getLogMessage());
|
||||
} else {
|
||||
Log_OC.e(TAG, "Upload of " + mOriginalStoragePath + " to " + mRemotePath +
|
||||
": " + result.getLogMessage(), result.getException());
|
||||
}
|
||||
Log_OC.e(TAG, "Upload of " + mOriginalStoragePath + " to " + mRemotePath +
|
||||
": " + result.getLogMessage() + complement, result.getException());
|
||||
|
||||
} else {
|
||||
Log_OC.e(TAG, "Upload of " + mOriginalStoragePath + " to " + mRemotePath +
|
||||
": " + result.getLogMessage());
|
||||
|
@ -418,9 +484,93 @@ public class UploadFileOperation extends RemoteOperation {
|
|||
}
|
||||
}
|
||||
|
||||
if (result.isSuccess()) {
|
||||
saveUploadedFile(client);
|
||||
|
||||
} else if (result.getCode() == ResultCode.SYNC_CONFLICT) {
|
||||
getStorageManager().saveConflict(mFile, mFile.getEtagInConflict());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Checks origin of current upload and network type to decide if should be delayed, according to
|
||||
* current user preferences.
|
||||
*
|
||||
* @return 'True' if the upload was delayed until WiFi connectivity is available, 'false' otherwise.
|
||||
*/
|
||||
private boolean delayForWifi() {
|
||||
boolean delayInstantPicture = (
|
||||
isInstantPicture() && PreferenceReader.instantPictureUploadViaWiFiOnly(mContext)
|
||||
);
|
||||
boolean delayInstantVideo = (
|
||||
isInstantVideo() && PreferenceReader.instantVideoUploadViaWiFiOnly(mContext)
|
||||
);
|
||||
return (
|
||||
(delayInstantPicture || delayInstantVideo) &&
|
||||
!ConnectivityUtils.isAppConnectedViaWiFi(mContext)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Checks the existence of the folder where the current file will be uploaded both
|
||||
* in the remote server and in the local database.
|
||||
* <p/>
|
||||
* If the upload is set to enforce the creation of the folder, the method tries to
|
||||
* create it both remote and locally.
|
||||
*
|
||||
* @param pathToGrant Full remote path whose existence will be granted.
|
||||
* @return An {@link OCFile} instance corresponding to the folder where the file
|
||||
* will be uploaded.
|
||||
*/
|
||||
private RemoteOperationResult grantFolderExistence(String pathToGrant, OwnCloudClient client) {
|
||||
RemoteOperation operation = new ExistenceCheckRemoteOperation(pathToGrant, mContext, false);
|
||||
RemoteOperationResult result = operation.execute(client);
|
||||
if (!result.isSuccess() && result.getCode() == ResultCode.FILE_NOT_FOUND && mRemoteFolderToBeCreated) {
|
||||
SyncOperation syncOp = new CreateFolderOperation(pathToGrant, true);
|
||||
result = syncOp.execute(client, getStorageManager());
|
||||
}
|
||||
if (result.isSuccess()) {
|
||||
OCFile parentDir = getStorageManager().getFileByPath(pathToGrant);
|
||||
if (parentDir == null) {
|
||||
parentDir = createLocalFolder(pathToGrant);
|
||||
}
|
||||
if (parentDir != null) {
|
||||
result = new RemoteOperationResult(ResultCode.OK);
|
||||
} else {
|
||||
result = new RemoteOperationResult(ResultCode.UNKNOWN_ERROR);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private OCFile createLocalFolder(String remotePath) {
|
||||
String parentPath = new File(remotePath).getParent();
|
||||
parentPath = parentPath.endsWith(OCFile.PATH_SEPARATOR) ?
|
||||
parentPath : parentPath + OCFile.PATH_SEPARATOR;
|
||||
OCFile parent = getStorageManager().getFileByPath(parentPath);
|
||||
if (parent == null) {
|
||||
parent = createLocalFolder(parentPath);
|
||||
}
|
||||
if (parent != null) {
|
||||
OCFile createdFolder = new OCFile(remotePath);
|
||||
createdFolder.setMimetype("DIR");
|
||||
createdFolder.setParentId(parent.getFileId());
|
||||
getStorageManager().saveFile(createdFolder);
|
||||
return createdFolder;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a new OCFile mFile with new remote path. This is required if forceOverwrite==false.
|
||||
* New file is stored as mFile, original as mOldFile.
|
||||
* @param newRemotePath new remote path
|
||||
*/
|
||||
private void createNewOCFile(String newRemotePath) {
|
||||
// a new OCFile instance must be created for a new remote path
|
||||
OCFile newFile = new OCFile(newRemotePath);
|
||||
|
@ -429,7 +579,8 @@ public class UploadFileOperation extends RemoteOperation {
|
|||
newFile.setMimetype(mFile.getMimetype());
|
||||
newFile.setModificationTimestamp(mFile.getModificationTimestamp());
|
||||
newFile.setModificationTimestampAtLastSyncForData(
|
||||
mFile.getModificationTimestampAtLastSyncForData());
|
||||
mFile.getModificationTimestampAtLastSyncForData()
|
||||
);
|
||||
newFile.setEtag(mFile.getEtag());
|
||||
newFile.setFavorite(mFile.isFavorite());
|
||||
newFile.setLastSyncDateForProperties(mFile.getLastSyncDateForProperties());
|
||||
|
@ -443,12 +594,12 @@ public class UploadFileOperation extends RemoteOperation {
|
|||
/**
|
||||
* Checks if remotePath does not exist in the server and returns it, or adds
|
||||
* a suffix to it in order to avoid the server file is overwritten.
|
||||
*
|
||||
*
|
||||
* @param wc
|
||||
* @param remotePath
|
||||
* @return
|
||||
*/
|
||||
private String getAvailableRemotePath(OwnCloudClient wc, String remotePath) throws Exception {
|
||||
private String getAvailableRemotePath(OwnCloudClient wc, String remotePath) {
|
||||
boolean check = existsFile(wc, remotePath);
|
||||
if (!check) {
|
||||
return remotePath;
|
||||
|
@ -486,11 +637,224 @@ public class UploadFileOperation extends RemoteOperation {
|
|||
RemoteOperationResult result = existsOperation.execute(client);
|
||||
return result.isSuccess();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Allows to cancel the actual upload operation. If actual upload operating
|
||||
* is in progress it is cancelled, if upload preparation is being performed
|
||||
* upload will not take place.
|
||||
*/
|
||||
public void cancel() {
|
||||
mCancellationRequested = new AtomicBoolean(true);
|
||||
if (mUploadOperation != null) {
|
||||
if (mUploadOperation == null) {
|
||||
if (mUploadStarted.get()) {
|
||||
Log_OC.d(TAG, "Cancelling upload during upload preparations.");
|
||||
mCancellationRequested.set(true);
|
||||
} else {
|
||||
Log_OC.e(TAG, "No upload in progress. This should not happen.");
|
||||
}
|
||||
} else {
|
||||
Log_OC.d(TAG, "Cancelling upload during actual upload operation.");
|
||||
mUploadOperation.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* As soon as this method return true, upload can be cancel via cancel().
|
||||
*/
|
||||
public boolean isUploadInProgress() {
|
||||
return mUploadStarted.get();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO rewrite with homogeneous fail handling, remove dependency on {@link RemoteOperationResult},
|
||||
* TODO use Exceptions instead
|
||||
*
|
||||
* @param sourceFile Source file to copy.
|
||||
* @param targetFile Target location to copy the file.
|
||||
* @return {@link RemoteOperationResult}
|
||||
* @throws IOException
|
||||
*/
|
||||
private RemoteOperationResult copy(File sourceFile, File targetFile) throws IOException {
|
||||
Log_OC.d(TAG, "Copying local file");
|
||||
|
||||
RemoteOperationResult result = null;
|
||||
|
||||
if (FileStorageUtils.getUsableSpace(mAccount.name) < sourceFile.length()) {
|
||||
result = new RemoteOperationResult(ResultCode.LOCAL_STORAGE_FULL);
|
||||
return result; // error condition when the file should be copied
|
||||
|
||||
} else {
|
||||
Log_OC.d(TAG, "Creating temporal folder");
|
||||
File temporalParent = targetFile.getParentFile();
|
||||
temporalParent.mkdirs();
|
||||
if (!temporalParent.isDirectory()) {
|
||||
throw new IOException(
|
||||
"Unexpected error: parent directory could not be created");
|
||||
}
|
||||
Log_OC.d(TAG, "Creating temporal file");
|
||||
targetFile.createNewFile();
|
||||
if (!targetFile.isFile()) {
|
||||
throw new IOException(
|
||||
"Unexpected error: target file could not be created");
|
||||
}
|
||||
|
||||
Log_OC.d(TAG, "Copying file contents");
|
||||
InputStream in = null;
|
||||
OutputStream out = null;
|
||||
|
||||
try {
|
||||
if (!mOriginalStoragePath.equals(targetFile.getAbsolutePath())) {
|
||||
// In case document provider schema as 'content://'
|
||||
if (mOriginalStoragePath.startsWith(UriUtils.URI_CONTENT_SCHEME)) {
|
||||
Uri uri = Uri.parse(mOriginalStoragePath);
|
||||
in = mContext.getContentResolver().openInputStream(uri);
|
||||
} else {
|
||||
in = new FileInputStream(sourceFile);
|
||||
}
|
||||
out = new FileOutputStream(targetFile);
|
||||
int nRead;
|
||||
byte[] buf = new byte[4096];
|
||||
while (!mCancellationRequested.get() &&
|
||||
(nRead = in.read(buf)) > -1) {
|
||||
out.write(buf, 0, nRead);
|
||||
}
|
||||
out.flush();
|
||||
|
||||
} // else: weird but possible situation, nothing to copy
|
||||
|
||||
if (mCancellationRequested.get()) {
|
||||
result = new RemoteOperationResult(new OperationCancelledException());
|
||||
return result;
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
result = new RemoteOperationResult(ResultCode.LOCAL_STORAGE_NOT_COPIED);
|
||||
return result;
|
||||
|
||||
} finally {
|
||||
try {
|
||||
if (in != null)
|
||||
in.close();
|
||||
} catch (Exception e) {
|
||||
Log_OC.d(TAG, "Weird exception while closing input stream for " +
|
||||
mOriginalStoragePath + " (ignoring)", e);
|
||||
}
|
||||
try {
|
||||
if (out != null)
|
||||
out.close();
|
||||
} catch (Exception e) {
|
||||
Log_OC.d(TAG, "Weird exception while closing output stream for " +
|
||||
targetFile.getAbsolutePath() + " (ignoring)", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* TODO rewrite with homogeneous fail handling, remove dependency on {@link RemoteOperationResult},
|
||||
* TODO use Exceptions instead
|
||||
*
|
||||
* TODO refactor both this and 'copy' in a single method
|
||||
*
|
||||
* @param sourceFile Source file to move.
|
||||
* @param targetFile Target location to move the file.
|
||||
* @return {@link RemoteOperationResult}
|
||||
* @throws IOException
|
||||
*/
|
||||
private void move(File sourceFile, File targetFile) throws IOException {
|
||||
|
||||
if (!targetFile.equals(sourceFile)) {
|
||||
File expectedFolder = targetFile.getParentFile();
|
||||
expectedFolder.mkdirs();
|
||||
|
||||
if (expectedFolder.isDirectory()){
|
||||
if (!sourceFile.renameTo(targetFile)){
|
||||
// try to copy and then delete
|
||||
targetFile.createNewFile();
|
||||
FileChannel inChannel = new FileInputStream(sourceFile).getChannel();
|
||||
FileChannel outChannel = new FileOutputStream(targetFile).getChannel();
|
||||
try {
|
||||
inChannel.transferTo(0, inChannel.size(), outChannel);
|
||||
sourceFile.delete();
|
||||
} catch (Exception e){
|
||||
mFile.setStoragePath(""); // forget the local file
|
||||
// by now, treat this as a success; the file was uploaded
|
||||
// the best option could be show a warning message
|
||||
}
|
||||
finally {
|
||||
if (inChannel != null) inChannel.close();
|
||||
if (outChannel != null) outChannel.close();
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
mFile.setStoragePath("");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves a OC File after a successful upload.
|
||||
* <p/>
|
||||
* A PROPFIND is necessary to keep the props in the local database
|
||||
* synchronized with the server, specially the modification time and Etag
|
||||
* (where available)
|
||||
* <p/>
|
||||
*/
|
||||
private void saveUploadedFile(OwnCloudClient client) {
|
||||
OCFile file = mFile;
|
||||
if (file.fileExists()) {
|
||||
file = getStorageManager().getFileById(file.getFileId());
|
||||
}
|
||||
long syncDate = System.currentTimeMillis();
|
||||
file.setLastSyncDateForData(syncDate);
|
||||
|
||||
// new PROPFIND to keep data consistent with server
|
||||
// in theory, should return the same we already have
|
||||
// TODO from the appropriate OC server version, get data from last PUT response headers, instead
|
||||
// TODO of a new PROPFIND; the latter may fail, specially for chunked uploads
|
||||
ReadRemoteFileOperation operation = new ReadRemoteFileOperation(getRemotePath());
|
||||
RemoteOperationResult result = operation.execute(client);
|
||||
if (result.isSuccess()) {
|
||||
updateOCFile(file, (RemoteFile) result.getData().get(0));
|
||||
file.setLastSyncDateForProperties(syncDate);
|
||||
} else {
|
||||
Log_OC.e(TAG, "Error reading properties of file after successful upload; this is gonna hurt...");
|
||||
}
|
||||
|
||||
if (mWasRenamed) {
|
||||
OCFile oldFile = mOldFile;
|
||||
if (oldFile.fileExists()) {
|
||||
oldFile.setStoragePath(null);
|
||||
getStorageManager().saveFile(oldFile);
|
||||
getStorageManager().saveConflict(oldFile, null);
|
||||
}
|
||||
// else: it was just an automatic renaming due to a name
|
||||
// coincidence; nothing else is needed, the storagePath is right
|
||||
// in the instance returned by mCurrentUpload.getFile()
|
||||
}
|
||||
file.setNeedsUpdateThumbnail(true);
|
||||
getStorageManager().saveFile(file);
|
||||
getStorageManager().saveConflict(file, null);
|
||||
|
||||
FileDataStorageManager.triggerMediaScan(file.getStoragePath());
|
||||
}
|
||||
|
||||
private void updateOCFile(OCFile file, RemoteFile remoteFile) {
|
||||
file.setCreationTimestamp(remoteFile.getCreationTimestamp());
|
||||
file.setFileLength(remoteFile.getLength());
|
||||
file.setMimetype(remoteFile.getMimeType());
|
||||
file.setModificationTimestamp(remoteFile.getModifiedTimestamp());
|
||||
file.setModificationTimestampAtLastSyncForData(remoteFile.getModifiedTimestamp());
|
||||
file.setEtag(remoteFile.getEtag());
|
||||
file.setRemoteId(remoteFile.getRemoteId());
|
||||
}
|
||||
|
||||
public interface OnRenameListener {
|
||||
|
||||
void onRenameUpload();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -3,8 +3,9 @@
|
|||
*
|
||||
* @author Bartek Przybylski
|
||||
* @author David A. Velasco
|
||||
* @author masensio
|
||||
* Copyright (C) 2011 Bartek Przybylski
|
||||
* Copyright (C) 2015 ownCloud Inc.
|
||||
* Copyright (C) 2016 ownCloud Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
|
@ -43,6 +44,7 @@ import android.text.TextUtils;
|
|||
import com.owncloud.android.MainApp;
|
||||
import com.owncloud.android.R;
|
||||
import com.owncloud.android.datamodel.OCFile;
|
||||
import com.owncloud.android.datamodel.UploadsStorageManager;
|
||||
import com.owncloud.android.db.ProviderMeta;
|
||||
import com.owncloud.android.db.ProviderMeta.ProviderTableMeta;
|
||||
import com.owncloud.android.lib.common.accounts.AccountUtils;
|
||||
|
@ -65,9 +67,12 @@ public class FileContentProvider extends ContentProvider {
|
|||
private static final int ROOT_DIRECTORY = 3;
|
||||
private static final int SHARES = 4;
|
||||
private static final int CAPABILITIES = 5;
|
||||
private static final int UPLOADS = 6;
|
||||
|
||||
private static final String TAG = FileContentProvider.class.getSimpleName();
|
||||
|
||||
private final String MAX_SUCCESSFUL_UPLOADS = "30";
|
||||
|
||||
private UriMatcher mUriMatcher;
|
||||
|
||||
@Override
|
||||
|
@ -89,25 +94,25 @@ public class FileContentProvider extends ContentProvider {
|
|||
private int delete(SQLiteDatabase db, Uri uri, String where, String[] whereArgs) {
|
||||
int count = 0;
|
||||
switch (mUriMatcher.match(uri)) {
|
||||
case SINGLE_FILE:
|
||||
Cursor c = query(db, uri, null, where, whereArgs, null);
|
||||
String remoteId = "";
|
||||
if (c != null && c.moveToFirst()) {
|
||||
remoteId = c.getString(c.getColumnIndex(ProviderTableMeta.FILE_REMOTE_ID));
|
||||
//ThumbnailsCacheManager.removeFileFromCache(remoteId);
|
||||
c.close();
|
||||
}
|
||||
Log_OC.d(TAG, "Removing FILE " + remoteId);
|
||||
case SINGLE_FILE:
|
||||
Cursor c = query(db, uri, null, where, whereArgs, null);
|
||||
String remoteId = "";
|
||||
if (c != null && c.moveToFirst()) {
|
||||
remoteId = c.getString(c.getColumnIndex(ProviderTableMeta.FILE_REMOTE_ID));
|
||||
//ThumbnailsCacheManager.removeFileFromCache(remoteId);
|
||||
c.close();
|
||||
}
|
||||
Log_OC.d(TAG, "Removing FILE " + remoteId);
|
||||
|
||||
count = db.delete(ProviderTableMeta.FILE_TABLE_NAME,
|
||||
ProviderTableMeta._ID
|
||||
+ "="
|
||||
+ uri.getPathSegments().get(1)
|
||||
+ (!TextUtils.isEmpty(where) ? " AND (" + where
|
||||
+ ")" : ""), whereArgs);
|
||||
break;
|
||||
case DIRECTORY:
|
||||
// deletion of folder is recursive
|
||||
count = db.delete(ProviderTableMeta.FILE_TABLE_NAME,
|
||||
ProviderTableMeta._ID
|
||||
+ "="
|
||||
+ uri.getPathSegments().get(1)
|
||||
+ (!TextUtils.isEmpty(where) ? " AND (" + where
|
||||
+ ")" : ""), whereArgs);
|
||||
break;
|
||||
case DIRECTORY:
|
||||
// deletion of folder is recursive
|
||||
/*
|
||||
Uri folderUri = ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_FILE, Long.parseLong(uri.getPathSegments().get(1)));
|
||||
Cursor folder = query(db, folderUri, null, null, null, null);
|
||||
|
@ -116,63 +121,66 @@ public class FileContentProvider extends ContentProvider {
|
|||
folderName = folder.getString(folder.getColumnIndex(ProviderTableMeta.FILE_PATH));
|
||||
}
|
||||
*/
|
||||
Cursor children = query(uri, null, null, null, null);
|
||||
if (children != null && children.moveToFirst()) {
|
||||
long childId;
|
||||
boolean isDir;
|
||||
while (!children.isAfterLast()) {
|
||||
childId = children.getLong(children.getColumnIndex(ProviderTableMeta._ID));
|
||||
isDir = "DIR".equals(children.getString(
|
||||
children.getColumnIndex(ProviderTableMeta.FILE_CONTENT_TYPE)
|
||||
));
|
||||
//remotePath = children.getString(children.getColumnIndex(ProviderTableMeta.FILE_PATH));
|
||||
if (isDir) {
|
||||
count += delete(
|
||||
db,
|
||||
ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_DIR, childId),
|
||||
null,
|
||||
null
|
||||
);
|
||||
} else {
|
||||
count += delete(
|
||||
db,
|
||||
ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_FILE, childId),
|
||||
null,
|
||||
null
|
||||
);
|
||||
Cursor children = query(uri, null, null, null, null);
|
||||
if (children != null && children.moveToFirst()) {
|
||||
long childId;
|
||||
boolean isDir;
|
||||
while (!children.isAfterLast()) {
|
||||
childId = children.getLong(children.getColumnIndex(ProviderTableMeta._ID));
|
||||
isDir = "DIR".equals(children.getString(
|
||||
children.getColumnIndex(ProviderTableMeta.FILE_CONTENT_TYPE)
|
||||
));
|
||||
//remotePath = children.getString(children.getColumnIndex(ProviderTableMeta.FILE_PATH));
|
||||
if (isDir) {
|
||||
count += delete(
|
||||
db,
|
||||
ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_DIR, childId),
|
||||
null,
|
||||
null
|
||||
);
|
||||
} else {
|
||||
count += delete(
|
||||
db,
|
||||
ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_FILE, childId),
|
||||
null,
|
||||
null
|
||||
);
|
||||
}
|
||||
children.moveToNext();
|
||||
}
|
||||
children.moveToNext();
|
||||
}
|
||||
children.close();
|
||||
} /*else {
|
||||
children.close();
|
||||
} /*else {
|
||||
Log_OC.d(TAG, "No child to remove in DIRECTORY " + folderName);
|
||||
}
|
||||
Log_OC.d(TAG, "Removing DIRECTORY " + folderName + " (or maybe not) ");
|
||||
*/
|
||||
count += db.delete(ProviderTableMeta.FILE_TABLE_NAME,
|
||||
ProviderTableMeta._ID
|
||||
+ "="
|
||||
+ uri.getPathSegments().get(1)
|
||||
+ (!TextUtils.isEmpty(where) ? " AND (" + where
|
||||
+ ")" : ""), whereArgs);
|
||||
count += db.delete(ProviderTableMeta.FILE_TABLE_NAME,
|
||||
ProviderTableMeta._ID
|
||||
+ "="
|
||||
+ uri.getPathSegments().get(1)
|
||||
+ (!TextUtils.isEmpty(where) ? " AND (" + where
|
||||
+ ")" : ""), whereArgs);
|
||||
/* Just for log
|
||||
if (folder != null) {
|
||||
folder.close();
|
||||
}*/
|
||||
break;
|
||||
case ROOT_DIRECTORY:
|
||||
//Log_OC.d(TAG, "Removing ROOT!");
|
||||
count = db.delete(ProviderTableMeta.FILE_TABLE_NAME, where, whereArgs);
|
||||
break;
|
||||
case SHARES:
|
||||
count = db.delete(ProviderTableMeta.OCSHARES_TABLE_NAME, where, whereArgs);
|
||||
break;
|
||||
case CAPABILITIES:
|
||||
count = db.delete(ProviderTableMeta.CAPABILITIES_TABLE_NAME, where, whereArgs);
|
||||
break;
|
||||
default:
|
||||
//Log_OC.e(TAG, "Unknown uri " + uri);
|
||||
throw new IllegalArgumentException("Unknown uri: " + uri.toString());
|
||||
break;
|
||||
case ROOT_DIRECTORY:
|
||||
//Log_OC.d(TAG, "Removing ROOT!");
|
||||
count = db.delete(ProviderTableMeta.FILE_TABLE_NAME, where, whereArgs);
|
||||
break;
|
||||
case SHARES:
|
||||
count = db.delete(ProviderTableMeta.OCSHARES_TABLE_NAME, where, whereArgs);
|
||||
break;
|
||||
case CAPABILITIES:
|
||||
count = db.delete(ProviderTableMeta.CAPABILITIES_TABLE_NAME, where, whereArgs);
|
||||
break;
|
||||
case UPLOADS:
|
||||
count = db.delete(ProviderTableMeta.UPLOADS_TABLE_NAME, where, whereArgs);
|
||||
break;
|
||||
default:
|
||||
//Log_OC.e(TAG, "Unknown uri " + uri);
|
||||
throw new IllegalArgumentException("Unknown uri: " + uri.toString());
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
@ -207,68 +215,80 @@ public class FileContentProvider extends ContentProvider {
|
|||
|
||||
private Uri insert(SQLiteDatabase db, Uri uri, ContentValues values) {
|
||||
switch (mUriMatcher.match(uri)){
|
||||
case ROOT_DIRECTORY:
|
||||
case SINGLE_FILE:
|
||||
String remotePath = values.getAsString(ProviderTableMeta.FILE_PATH);
|
||||
String accountName = values.getAsString(ProviderTableMeta.FILE_ACCOUNT_OWNER);
|
||||
String[] projection = new String[] {
|
||||
ProviderTableMeta._ID, ProviderTableMeta.FILE_PATH,
|
||||
ProviderTableMeta.FILE_ACCOUNT_OWNER
|
||||
};
|
||||
String where = ProviderTableMeta.FILE_PATH + "=? AND " +
|
||||
ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?";
|
||||
String[] whereArgs = new String[] {remotePath, accountName};
|
||||
Cursor doubleCheck = query(db, uri, projection, where, whereArgs, null);
|
||||
// ugly patch; serious refactorization is needed to reduce work in
|
||||
// FileDataStorageManager and bring it to FileContentProvider
|
||||
if (doubleCheck == null || !doubleCheck.moveToFirst()) {
|
||||
if (doubleCheck != null) {
|
||||
case ROOT_DIRECTORY:
|
||||
case SINGLE_FILE:
|
||||
String remotePath = values.getAsString(ProviderTableMeta.FILE_PATH);
|
||||
String accountName = values.getAsString(ProviderTableMeta.FILE_ACCOUNT_OWNER);
|
||||
String[] projection = new String[] {
|
||||
ProviderTableMeta._ID, ProviderTableMeta.FILE_PATH,
|
||||
ProviderTableMeta.FILE_ACCOUNT_OWNER
|
||||
};
|
||||
String where = ProviderTableMeta.FILE_PATH + "=? AND " +
|
||||
ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?";
|
||||
String[] whereArgs = new String[] {remotePath, accountName};
|
||||
Cursor doubleCheck = query(db, uri, projection, where, whereArgs, null);
|
||||
// ugly patch; serious refactorization is needed to reduce work in
|
||||
// FileDataStorageManager and bring it to FileContentProvider
|
||||
if (doubleCheck == null || !doubleCheck.moveToFirst()) {
|
||||
if (doubleCheck != null) {
|
||||
doubleCheck.close();
|
||||
}
|
||||
long rowId = db.insert(ProviderTableMeta.FILE_TABLE_NAME, null, values);
|
||||
if (rowId > 0) {
|
||||
return ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_FILE, rowId);
|
||||
} else {
|
||||
throw new SQLException("ERROR " + uri);
|
||||
}
|
||||
} else {
|
||||
// file is already inserted; race condition, let's avoid a duplicated entry
|
||||
Uri insertedFileUri = ContentUris.withAppendedId(
|
||||
ProviderTableMeta.CONTENT_URI_FILE,
|
||||
doubleCheck.getLong(doubleCheck.getColumnIndex(ProviderTableMeta._ID))
|
||||
);
|
||||
doubleCheck.close();
|
||||
|
||||
return insertedFileUri;
|
||||
}
|
||||
long rowId = db.insert(ProviderTableMeta.FILE_TABLE_NAME, null, values);
|
||||
if (rowId > 0) {
|
||||
return ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_FILE, rowId);
|
||||
|
||||
case SHARES:
|
||||
Uri insertedShareUri = null;
|
||||
long rowId = db.insert(ProviderTableMeta.OCSHARES_TABLE_NAME, null, values);
|
||||
if (rowId >0) {
|
||||
insertedShareUri =
|
||||
ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_SHARE, rowId);
|
||||
} else {
|
||||
throw new SQLException("ERROR " + uri);
|
||||
|
||||
}
|
||||
} else {
|
||||
// file is already inserted; race condition, let's avoid a duplicated entry
|
||||
Uri insertedFileUri = ContentUris.withAppendedId(
|
||||
ProviderTableMeta.CONTENT_URI_FILE,
|
||||
doubleCheck.getLong(doubleCheck.getColumnIndex(ProviderTableMeta._ID))
|
||||
);
|
||||
doubleCheck.close();
|
||||
updateFilesTableAccordingToShareInsertion(db, values);
|
||||
return insertedShareUri;
|
||||
|
||||
return insertedFileUri;
|
||||
}
|
||||
case CAPABILITIES:
|
||||
Uri insertedCapUri = null;
|
||||
long id = db.insert(ProviderTableMeta.CAPABILITIES_TABLE_NAME, null, values);
|
||||
if (id >0) {
|
||||
insertedCapUri =
|
||||
ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_CAPABILITIES, id);
|
||||
} else {
|
||||
throw new SQLException("ERROR " + uri);
|
||||
|
||||
case SHARES:
|
||||
Uri insertedShareUri = null;
|
||||
long rowId = db.insert(ProviderTableMeta.OCSHARES_TABLE_NAME, null, values);
|
||||
if (rowId >0) {
|
||||
insertedShareUri =
|
||||
ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_SHARE, rowId);
|
||||
} else {
|
||||
throw new SQLException("ERROR " + uri);
|
||||
}
|
||||
return insertedCapUri;
|
||||
|
||||
}
|
||||
updateFilesTableAccordingToShareInsertion(db, values);
|
||||
return insertedShareUri;
|
||||
case UPLOADS:
|
||||
Uri insertedUploadUri = null;
|
||||
long uploadId = db.insert(ProviderTableMeta.UPLOADS_TABLE_NAME, null, values);
|
||||
if (uploadId >0) {
|
||||
insertedUploadUri =
|
||||
ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_UPLOADS, uploadId);
|
||||
trimSuccessfulUploads(db);
|
||||
} else {
|
||||
throw new SQLException("ERROR " + uri);
|
||||
|
||||
case CAPABILITIES:
|
||||
Uri insertedCapUri = null;
|
||||
long id = db.insert(ProviderTableMeta.CAPABILITIES_TABLE_NAME, null, values);
|
||||
if (id >0) {
|
||||
insertedCapUri =
|
||||
ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_CAPABILITIES, id);
|
||||
} else {
|
||||
throw new SQLException("ERROR " + uri);
|
||||
|
||||
}
|
||||
return insertedCapUri;
|
||||
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown uri id: " + uri);
|
||||
}
|
||||
return insertedUploadUri;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown uri id: " + uri);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -312,6 +332,8 @@ public class FileContentProvider extends ContentProvider {
|
|||
mUriMatcher.addURI(authority, "shares/#", SHARES);
|
||||
mUriMatcher.addURI(authority, "capabilities/", CAPABILITIES);
|
||||
mUriMatcher.addURI(authority, "capabilities/#", CAPABILITIES);
|
||||
mUriMatcher.addURI(authority, "uploads/", UPLOADS);
|
||||
mUriMatcher.addURI(authority, "uploads/#", UPLOADS);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -352,35 +374,42 @@ public class FileContentProvider extends ContentProvider {
|
|||
sqlQuery.setTables(ProviderTableMeta.FILE_TABLE_NAME);
|
||||
|
||||
switch (mUriMatcher.match(uri)) {
|
||||
case ROOT_DIRECTORY:
|
||||
break;
|
||||
case DIRECTORY:
|
||||
String folderId = uri.getPathSegments().get(1);
|
||||
sqlQuery.appendWhere(ProviderTableMeta.FILE_PARENT + "="
|
||||
+ folderId);
|
||||
break;
|
||||
case SINGLE_FILE:
|
||||
if (uri.getPathSegments().size() > 1) {
|
||||
sqlQuery.appendWhere(ProviderTableMeta._ID + "="
|
||||
+ uri.getPathSegments().get(1));
|
||||
}
|
||||
break;
|
||||
case SHARES:
|
||||
sqlQuery.setTables(ProviderTableMeta.OCSHARES_TABLE_NAME);
|
||||
if (uri.getPathSegments().size() > 1) {
|
||||
sqlQuery.appendWhere(ProviderTableMeta._ID + "="
|
||||
+ uri.getPathSegments().get(1));
|
||||
}
|
||||
break;
|
||||
case CAPABILITIES:
|
||||
sqlQuery.setTables(ProviderTableMeta.CAPABILITIES_TABLE_NAME);
|
||||
if (uri.getPathSegments().size() > 1) {
|
||||
sqlQuery.appendWhere(ProviderTableMeta._ID + "="
|
||||
+ uri.getPathSegments().get(1));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown uri id: " + uri);
|
||||
case ROOT_DIRECTORY:
|
||||
break;
|
||||
case DIRECTORY:
|
||||
String folderId = uri.getPathSegments().get(1);
|
||||
sqlQuery.appendWhere(ProviderTableMeta.FILE_PARENT + "="
|
||||
+ folderId);
|
||||
break;
|
||||
case SINGLE_FILE:
|
||||
if (uri.getPathSegments().size() > 1) {
|
||||
sqlQuery.appendWhere(ProviderTableMeta._ID + "="
|
||||
+ uri.getPathSegments().get(1));
|
||||
}
|
||||
break;
|
||||
case SHARES:
|
||||
sqlQuery.setTables(ProviderTableMeta.OCSHARES_TABLE_NAME);
|
||||
if (uri.getPathSegments().size() > 1) {
|
||||
sqlQuery.appendWhere(ProviderTableMeta._ID + "="
|
||||
+ uri.getPathSegments().get(1));
|
||||
}
|
||||
break;
|
||||
case CAPABILITIES:
|
||||
sqlQuery.setTables(ProviderTableMeta.CAPABILITIES_TABLE_NAME);
|
||||
if (uri.getPathSegments().size() > 1) {
|
||||
sqlQuery.appendWhere(ProviderTableMeta._ID + "="
|
||||
+ uri.getPathSegments().get(1));
|
||||
}
|
||||
break;
|
||||
case UPLOADS:
|
||||
sqlQuery.setTables(ProviderTableMeta.UPLOADS_TABLE_NAME);
|
||||
if (uri.getPathSegments().size() > 1) {
|
||||
sqlQuery.appendWhere(ProviderTableMeta._ID + "="
|
||||
+ uri.getPathSegments().get(1));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown uri id: " + uri);
|
||||
}
|
||||
|
||||
String order;
|
||||
|
@ -392,6 +421,9 @@ public class FileContentProvider extends ContentProvider {
|
|||
case CAPABILITIES:
|
||||
order = ProviderTableMeta.CAPABILITIES_DEFAULT_SORT_ORDER;
|
||||
break;
|
||||
case UPLOADS:
|
||||
order = ProviderTableMeta.UPLOADS_DEFAULT_SORT_ORDER;
|
||||
break;
|
||||
default: // Files
|
||||
order = ProviderTableMeta.FILE_DEFAULT_SORT_ORDER;
|
||||
break;
|
||||
|
@ -443,6 +475,12 @@ public class FileContentProvider extends ContentProvider {
|
|||
return db.update(
|
||||
ProviderTableMeta.CAPABILITIES_TABLE_NAME, values, selection, selectionArgs
|
||||
);
|
||||
case UPLOADS:
|
||||
int ret = db.update(
|
||||
ProviderTableMeta.UPLOADS_TABLE_NAME, values, selection, selectionArgs
|
||||
);
|
||||
trimSuccessfulUploads(db);
|
||||
return ret;
|
||||
default:
|
||||
return db.update(
|
||||
ProviderTableMeta.FILE_TABLE_NAME, values, selection, selectionArgs
|
||||
|
@ -485,53 +523,17 @@ public class FileContentProvider extends ContentProvider {
|
|||
public void onCreate(SQLiteDatabase db) {
|
||||
// files table
|
||||
Log_OC.i("SQL", "Entering in onCreate");
|
||||
db.execSQL("CREATE TABLE " + ProviderTableMeta.FILE_TABLE_NAME + "("
|
||||
+ ProviderTableMeta._ID + " INTEGER PRIMARY KEY, "
|
||||
+ ProviderTableMeta.FILE_NAME + " TEXT, "
|
||||
+ ProviderTableMeta.FILE_PATH + " TEXT, "
|
||||
+ ProviderTableMeta.FILE_PARENT + " INTEGER, "
|
||||
+ ProviderTableMeta.FILE_CREATION + " INTEGER, "
|
||||
+ ProviderTableMeta.FILE_MODIFIED + " INTEGER, "
|
||||
+ ProviderTableMeta.FILE_CONTENT_TYPE + " TEXT, "
|
||||
+ ProviderTableMeta.FILE_CONTENT_LENGTH + " INTEGER, "
|
||||
+ ProviderTableMeta.FILE_STORAGE_PATH + " TEXT, "
|
||||
+ ProviderTableMeta.FILE_ACCOUNT_OWNER + " TEXT, "
|
||||
+ ProviderTableMeta.FILE_LAST_SYNC_DATE + " INTEGER, "
|
||||
+ ProviderTableMeta.FILE_KEEP_IN_SYNC + " INTEGER, "
|
||||
+ ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA + " INTEGER, "
|
||||
+ ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA + " INTEGER, "
|
||||
+ ProviderTableMeta.FILE_ETAG + " TEXT, "
|
||||
+ ProviderTableMeta.FILE_SHARED_VIA_LINK + " INTEGER, "
|
||||
+ ProviderTableMeta.FILE_PUBLIC_LINK + " TEXT, "
|
||||
+ ProviderTableMeta.FILE_PERMISSIONS + " TEXT null,"
|
||||
+ ProviderTableMeta.FILE_REMOTE_ID + " TEXT null,"
|
||||
+ ProviderTableMeta.FILE_UPDATE_THUMBNAIL + " INTEGER," //boolean
|
||||
+ ProviderTableMeta.FILE_IS_DOWNLOADING + " INTEGER," //boolean
|
||||
+ ProviderTableMeta.FILE_ETAG_IN_CONFLICT + " TEXT,"
|
||||
+ ProviderTableMeta.FILE_SHARED_WITH_SHAREE + " INTEGER);"
|
||||
);
|
||||
createFilesTable(db);
|
||||
|
||||
// Create table ocshares
|
||||
db.execSQL("CREATE TABLE " + ProviderTableMeta.OCSHARES_TABLE_NAME + "("
|
||||
+ ProviderTableMeta._ID + " INTEGER PRIMARY KEY, "
|
||||
+ ProviderTableMeta.OCSHARES_FILE_SOURCE + " INTEGER, "
|
||||
+ ProviderTableMeta.OCSHARES_ITEM_SOURCE + " INTEGER, "
|
||||
+ ProviderTableMeta.OCSHARES_SHARE_TYPE + " INTEGER, "
|
||||
+ ProviderTableMeta.OCSHARES_SHARE_WITH + " TEXT, "
|
||||
+ ProviderTableMeta.OCSHARES_PATH + " TEXT, "
|
||||
+ ProviderTableMeta.OCSHARES_PERMISSIONS+ " INTEGER, "
|
||||
+ ProviderTableMeta.OCSHARES_SHARED_DATE + " INTEGER, "
|
||||
+ ProviderTableMeta.OCSHARES_EXPIRATION_DATE + " INTEGER, "
|
||||
+ ProviderTableMeta.OCSHARES_TOKEN + " TEXT, "
|
||||
+ ProviderTableMeta.OCSHARES_SHARE_WITH_DISPLAY_NAME + " TEXT, "
|
||||
+ ProviderTableMeta.OCSHARES_IS_DIRECTORY + " INTEGER, " // boolean
|
||||
+ ProviderTableMeta.OCSHARES_USER_ID + " INTEGER, "
|
||||
+ ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED + " INTEGER,"
|
||||
+ ProviderTableMeta.OCSHARES_ACCOUNT_OWNER + " TEXT );" );
|
||||
// Create ocshares table
|
||||
createOCSharesTable(db);
|
||||
|
||||
// Create table capabilities
|
||||
// Create capabilities table
|
||||
createCapabilitiesTable(db);
|
||||
|
||||
// Create uploads table
|
||||
createUploadsTable(db);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -619,22 +621,7 @@ public class FileContentProvider extends ContentProvider {
|
|||
" DEFAULT NULL");
|
||||
|
||||
// Create table ocshares
|
||||
db.execSQL("CREATE TABLE " + ProviderTableMeta.OCSHARES_TABLE_NAME + "("
|
||||
+ ProviderTableMeta._ID + " INTEGER PRIMARY KEY, "
|
||||
+ ProviderTableMeta.OCSHARES_FILE_SOURCE + " INTEGER, "
|
||||
+ ProviderTableMeta.OCSHARES_ITEM_SOURCE + " INTEGER, "
|
||||
+ ProviderTableMeta.OCSHARES_SHARE_TYPE + " INTEGER, "
|
||||
+ ProviderTableMeta.OCSHARES_SHARE_WITH + " TEXT, "
|
||||
+ ProviderTableMeta.OCSHARES_PATH + " TEXT, "
|
||||
+ ProviderTableMeta.OCSHARES_PERMISSIONS + " INTEGER, "
|
||||
+ ProviderTableMeta.OCSHARES_SHARED_DATE + " INTEGER, "
|
||||
+ ProviderTableMeta.OCSHARES_EXPIRATION_DATE + " INTEGER, "
|
||||
+ ProviderTableMeta.OCSHARES_TOKEN + " TEXT, "
|
||||
+ ProviderTableMeta.OCSHARES_SHARE_WITH_DISPLAY_NAME + " TEXT, "
|
||||
+ ProviderTableMeta.OCSHARES_IS_DIRECTORY + " INTEGER, " // boolean
|
||||
+ ProviderTableMeta.OCSHARES_USER_ID + " INTEGER, "
|
||||
+ ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED + " INTEGER,"
|
||||
+ ProviderTableMeta.OCSHARES_ACCOUNT_OWNER + " TEXT );");
|
||||
createOCSharesTable(db);
|
||||
|
||||
upgraded = true;
|
||||
db.setTransactionSuccessful();
|
||||
|
@ -760,6 +747,22 @@ public class FileContentProvider extends ContentProvider {
|
|||
db.endTransaction();
|
||||
}
|
||||
}
|
||||
|
||||
if (oldVersion < 14 && newVersion >= 14) {
|
||||
Log_OC.i("SQL", "Entering in the #14 ADD in onUpgrade");
|
||||
db.beginTransaction();
|
||||
try {
|
||||
// drop old instant_upload table
|
||||
db.execSQL("DROP TABLE IF EXISTS " + "instant_upload" + ";");
|
||||
// Create uploads table
|
||||
createUploadsTable(db);
|
||||
upgraded = true;
|
||||
db.setTransactionSuccessful();
|
||||
} finally {
|
||||
db.endTransaction();
|
||||
}
|
||||
}
|
||||
|
||||
if (!upgraded)
|
||||
Log_OC.i("SQL", "OUT of the ADD in onUpgrade; oldVersion == " + oldVersion +
|
||||
", newVersion == " + newVersion);
|
||||
|
@ -767,8 +770,56 @@ public class FileContentProvider extends ContentProvider {
|
|||
}
|
||||
}
|
||||
|
||||
private void createFilesTable(SQLiteDatabase db){
|
||||
db.execSQL("CREATE TABLE " + ProviderTableMeta.FILE_TABLE_NAME + "("
|
||||
+ ProviderTableMeta._ID + " INTEGER PRIMARY KEY, "
|
||||
+ ProviderTableMeta.FILE_NAME + " TEXT, "
|
||||
+ ProviderTableMeta.FILE_PATH + " TEXT, "
|
||||
+ ProviderTableMeta.FILE_PARENT + " INTEGER, "
|
||||
+ ProviderTableMeta.FILE_CREATION + " INTEGER, "
|
||||
+ ProviderTableMeta.FILE_MODIFIED + " INTEGER, "
|
||||
+ ProviderTableMeta.FILE_CONTENT_TYPE + " TEXT, "
|
||||
+ ProviderTableMeta.FILE_CONTENT_LENGTH + " INTEGER, "
|
||||
+ ProviderTableMeta.FILE_STORAGE_PATH + " TEXT, "
|
||||
+ ProviderTableMeta.FILE_ACCOUNT_OWNER + " TEXT, "
|
||||
+ ProviderTableMeta.FILE_LAST_SYNC_DATE + " INTEGER, "
|
||||
+ ProviderTableMeta.FILE_KEEP_IN_SYNC + " INTEGER, "
|
||||
+ ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA + " INTEGER, "
|
||||
+ ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA + " INTEGER, "
|
||||
+ ProviderTableMeta.FILE_ETAG + " TEXT, "
|
||||
+ ProviderTableMeta.FILE_SHARED_VIA_LINK + " INTEGER, "
|
||||
+ ProviderTableMeta.FILE_PUBLIC_LINK + " TEXT, "
|
||||
+ ProviderTableMeta.FILE_PERMISSIONS + " TEXT null,"
|
||||
+ ProviderTableMeta.FILE_REMOTE_ID + " TEXT null,"
|
||||
+ ProviderTableMeta.FILE_UPDATE_THUMBNAIL + " INTEGER," //boolean
|
||||
+ ProviderTableMeta.FILE_IS_DOWNLOADING + " INTEGER," //boolean
|
||||
+ ProviderTableMeta.FILE_ETAG_IN_CONFLICT + " TEXT,"
|
||||
+ ProviderTableMeta.FILE_SHARED_WITH_SHAREE + " INTEGER);"
|
||||
);
|
||||
}
|
||||
|
||||
private void createOCSharesTable(SQLiteDatabase db) {
|
||||
// Create ocshares table
|
||||
db.execSQL("CREATE TABLE " + ProviderTableMeta.OCSHARES_TABLE_NAME + "("
|
||||
+ ProviderTableMeta._ID + " INTEGER PRIMARY KEY, "
|
||||
+ ProviderTableMeta.OCSHARES_FILE_SOURCE + " INTEGER, "
|
||||
+ ProviderTableMeta.OCSHARES_ITEM_SOURCE + " INTEGER, "
|
||||
+ ProviderTableMeta.OCSHARES_SHARE_TYPE + " INTEGER, "
|
||||
+ ProviderTableMeta.OCSHARES_SHARE_WITH + " TEXT, "
|
||||
+ ProviderTableMeta.OCSHARES_PATH + " TEXT, "
|
||||
+ ProviderTableMeta.OCSHARES_PERMISSIONS+ " INTEGER, "
|
||||
+ ProviderTableMeta.OCSHARES_SHARED_DATE + " INTEGER, "
|
||||
+ ProviderTableMeta.OCSHARES_EXPIRATION_DATE + " INTEGER, "
|
||||
+ ProviderTableMeta.OCSHARES_TOKEN + " TEXT, "
|
||||
+ ProviderTableMeta.OCSHARES_SHARE_WITH_DISPLAY_NAME + " TEXT, "
|
||||
+ ProviderTableMeta.OCSHARES_IS_DIRECTORY + " INTEGER, " // boolean
|
||||
+ ProviderTableMeta.OCSHARES_USER_ID + " INTEGER, "
|
||||
+ ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED + " INTEGER,"
|
||||
+ ProviderTableMeta.OCSHARES_ACCOUNT_OWNER + " TEXT );" );
|
||||
}
|
||||
|
||||
private void createCapabilitiesTable(SQLiteDatabase db){
|
||||
// Create table capabilities
|
||||
// Create capabilities table
|
||||
db.execSQL("CREATE TABLE " + ProviderTableMeta.CAPABILITIES_TABLE_NAME + "("
|
||||
+ ProviderTableMeta._ID + " INTEGER PRIMARY KEY, "
|
||||
+ ProviderTableMeta.CAPABILITIES_ACCOUNT_NAME + " TEXT, "
|
||||
|
@ -795,6 +846,35 @@ public class FileContentProvider extends ContentProvider {
|
|||
+ ProviderTableMeta.CAPABILITIES_FILES_VERSIONING + " INTEGER );" ); // boolean
|
||||
}
|
||||
|
||||
private void createUploadsTable(SQLiteDatabase db){
|
||||
// Create uploads table
|
||||
db.execSQL("CREATE TABLE " + ProviderTableMeta.UPLOADS_TABLE_NAME + "("
|
||||
+ ProviderTableMeta._ID + " INTEGER PRIMARY KEY, "
|
||||
+ ProviderTableMeta.UPLOADS_LOCAL_PATH + " TEXT, "
|
||||
+ ProviderTableMeta.UPLOADS_REMOTE_PATH + " TEXT, "
|
||||
+ ProviderTableMeta.UPLOADS_ACCOUNT_NAME + " TEXT, "
|
||||
+ ProviderTableMeta.UPLOADS_FILE_SIZE + " LONG, "
|
||||
+ ProviderTableMeta.UPLOADS_STATUS + " INTEGER, " // UploadStatus
|
||||
+ ProviderTableMeta.UPLOADS_LOCAL_BEHAVIOUR + " INTEGER, " // Upload LocalBehaviour
|
||||
+ ProviderTableMeta.UPLOADS_UPLOAD_TIME + " INTEGER, "
|
||||
+ ProviderTableMeta.UPLOADS_FORCE_OVERWRITE + " INTEGER, " // boolean
|
||||
+ ProviderTableMeta.UPLOADS_IS_CREATE_REMOTE_FOLDER + " INTEGER, " // boolean
|
||||
+ ProviderTableMeta.UPLOADS_UPLOAD_END_TIMESTAMP + " INTEGER, "
|
||||
+ ProviderTableMeta.UPLOADS_LAST_RESULT + " INTEGER, " // Upload LastResult
|
||||
+ ProviderTableMeta.UPLOADS_CREATED_BY + " INTEGER );" // Upload createdBy
|
||||
);
|
||||
|
||||
|
||||
/* before:
|
||||
// PRIMARY KEY should always imply NOT NULL. Unfortunately, due to a
|
||||
// bug in some early versions, this is not the case in SQLite.
|
||||
//db.execSQL("CREATE TABLE " + TABLE_UPLOAD + " (" + " path TEXT PRIMARY KEY NOT NULL UNIQUE,"
|
||||
// + " uploadStatus INTEGER NOT NULL, uploadObject TEXT NOT NULL);");
|
||||
// uploadStatus is used to easy filtering, it has precedence over
|
||||
// uploadObject.getUploadStatus()
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* Version 10 of database does not modify its scheme. It coincides with the upgrade of the ownCloud account names
|
||||
* structure to include in it the path to the server instance. Updating the account names and path to local files
|
||||
|
@ -805,7 +885,7 @@ public class FileContentProvider extends ContentProvider {
|
|||
* @param db Database where table of files is included.
|
||||
*/
|
||||
private void updateAccountName(SQLiteDatabase db){
|
||||
Log_OC.d("SQL", "THREAD: "+ Thread.currentThread().getName());
|
||||
Log_OC.d("SQL", "THREAD: " + Thread.currentThread().getName());
|
||||
AccountManager ama = AccountManager.get(getContext());
|
||||
try {
|
||||
// get accounts from AccountManager ; we can't be sure if accounts in it are updated or not although
|
||||
|
@ -866,10 +946,10 @@ public class FileContentProvider extends ContentProvider {
|
|||
ProviderTableMeta.FILE_STORAGE_PATH + " IS NOT NULL";
|
||||
|
||||
Cursor c = db.query(ProviderTableMeta.FILE_TABLE_NAME,
|
||||
null,
|
||||
whereClause,
|
||||
new String[] { newAccountName },
|
||||
null, null, null);
|
||||
null,
|
||||
whereClause,
|
||||
new String[]{newAccountName},
|
||||
null, null, null);
|
||||
|
||||
try {
|
||||
if (c.moveToFirst()) {
|
||||
|
@ -909,4 +989,43 @@ public class FileContentProvider extends ContentProvider {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Grants that total count of successful uploads stored is not greater than MAX_SUCCESSFUL_UPLOADS.
|
||||
*
|
||||
* Removes older uploads if needed.
|
||||
*/
|
||||
private void trimSuccessfulUploads(SQLiteDatabase db) {
|
||||
Cursor c = null;
|
||||
try {
|
||||
c = db.rawQuery(
|
||||
"delete from " + ProviderTableMeta.UPLOADS_TABLE_NAME +
|
||||
" where " + ProviderTableMeta.UPLOADS_STATUS + " == "
|
||||
+ UploadsStorageManager.UploadStatus.UPLOAD_SUCCEEDED.getValue() +
|
||||
" and " + ProviderTableMeta._ID +
|
||||
" not in (select " + ProviderTableMeta._ID +
|
||||
" from " + ProviderTableMeta.UPLOADS_TABLE_NAME +
|
||||
" where " + ProviderTableMeta.UPLOADS_STATUS + " == "
|
||||
+ UploadsStorageManager.UploadStatus.UPLOAD_SUCCEEDED.getValue() +
|
||||
" order by " + ProviderTableMeta.UPLOADS_UPLOAD_END_TIMESTAMP +
|
||||
" desc limit " + MAX_SUCCESSFUL_UPLOADS +
|
||||
")",
|
||||
null
|
||||
);
|
||||
c.moveToFirst(); // do something with the cursor, or deletion doesn't happen; true story
|
||||
|
||||
} catch (Exception e) {
|
||||
Log_OC.e(
|
||||
TAG,
|
||||
"Something wrong trimming successful uploads, database could grow more than expected",
|
||||
e
|
||||
);
|
||||
|
||||
} finally {
|
||||
if (c!= null) {
|
||||
c.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -52,6 +52,7 @@ import com.owncloud.android.lib.common.utils.Log_OC;
|
|||
import com.owncloud.android.lib.resources.shares.ShareType;
|
||||
import com.owncloud.android.lib.resources.status.OwnCloudVersion;
|
||||
import com.owncloud.android.lib.resources.users.GetRemoteUserNameOperation;
|
||||
import com.owncloud.android.operations.CheckCurrentCredentialsOperation;
|
||||
import com.owncloud.android.operations.CopyFileOperation;
|
||||
import com.owncloud.android.operations.CreateFolderOperation;
|
||||
import com.owncloud.android.operations.CreateShareViaLinkOperation;
|
||||
|
@ -114,6 +115,7 @@ public class OperationsService extends Service {
|
|||
public static final String ACTION_SYNC_FOLDER = "SYNC_FOLDER";
|
||||
public static final String ACTION_MOVE_FILE = "MOVE_FILE";
|
||||
public static final String ACTION_COPY_FILE = "COPY_FILE";
|
||||
public static final String ACTION_CHECK_CURRENT_CREDENTIALS = "CHECK_CURRENT_CREDENTIALS";
|
||||
|
||||
public static final String ACTION_OPERATION_ADDED = OperationsService.class.getName() +
|
||||
".OPERATION_ADDED";
|
||||
|
@ -693,6 +695,10 @@ public class OperationsService extends Service {
|
|||
String remotePath = operationIntent.getStringExtra(EXTRA_REMOTE_PATH);
|
||||
String newParentPath = operationIntent.getStringExtra(EXTRA_NEW_PARENT_PATH);
|
||||
operation = new CopyFileOperation(remotePath, newParentPath, account);
|
||||
|
||||
} else if (action.equals(ACTION_CHECK_CURRENT_CREDENTIALS)) {
|
||||
// Check validity of currently stored credentials for a given account
|
||||
operation = new CheckCurrentCredentialsOperation(account);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
* ownCloud Android client application
|
||||
*
|
||||
* Copyright (C) 2015 ownCloud Inc.
|
||||
* Copyright (C) 2016 ownCloud Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
|
@ -27,7 +27,6 @@ import android.os.Looper;
|
|||
import android.os.Message;
|
||||
import android.util.Pair;
|
||||
|
||||
import com.owncloud.android.MainApp;
|
||||
import com.owncloud.android.datamodel.FileDataStorageManager;
|
||||
import com.owncloud.android.datamodel.OCFile;
|
||||
import com.owncloud.android.files.services.FileDownloader;
|
||||
|
@ -82,7 +81,7 @@ class SyncFolderHandler extends Handler {
|
|||
*/
|
||||
public boolean isSynchronizing(Account account, String remotePath) {
|
||||
if (account == null || remotePath == null) return false;
|
||||
return (mPendingOperations.contains(account, remotePath));
|
||||
return (mPendingOperations.contains(account.name, remotePath));
|
||||
}
|
||||
|
||||
|
||||
|
@ -100,7 +99,7 @@ class SyncFolderHandler extends Handler {
|
|||
*/
|
||||
private void doOperation(Account account, String remotePath) {
|
||||
|
||||
mCurrentSyncOperation = mPendingOperations.get(account, remotePath);
|
||||
mCurrentSyncOperation = mPendingOperations.get(account.name, remotePath);
|
||||
|
||||
if (mCurrentSyncOperation != null) {
|
||||
RemoteOperationResult result = null;
|
||||
|
@ -127,7 +126,7 @@ class SyncFolderHandler extends Handler {
|
|||
} catch (IOException e) {
|
||||
Log_OC.e(TAG, "Error while trying to get authorization", e);
|
||||
} finally {
|
||||
mPendingOperations.removePayload(account, remotePath);
|
||||
mPendingOperations.removePayload(account.name, remotePath);
|
||||
|
||||
mService.dispatchResultToOperationListeners(mCurrentSyncOperation, result);
|
||||
|
||||
|
@ -139,7 +138,7 @@ class SyncFolderHandler extends Handler {
|
|||
public void add(Account account, String remotePath,
|
||||
SynchronizeFolderOperation syncFolderOperation){
|
||||
Pair<String, String> putResult =
|
||||
mPendingOperations.putIfAbsent(account, remotePath, syncFolderOperation);
|
||||
mPendingOperations.putIfAbsent(account.name, remotePath, syncFolderOperation);
|
||||
if (putResult != null) {
|
||||
sendBroadcastNewSyncFolder(account, remotePath); // TODO upgrade!
|
||||
}
|
||||
|
@ -149,7 +148,7 @@ class SyncFolderHandler extends Handler {
|
|||
/**
|
||||
* Cancels a pending or current sync' operation.
|
||||
*
|
||||
* @param account ownCloud account where the remote file is stored.
|
||||
* @param account ownCloud {@link Account} where the remote file is stored.
|
||||
* @param file A file in the queue of pending synchronizations
|
||||
*/
|
||||
public void cancel(Account account, OCFile file){
|
||||
|
@ -158,7 +157,7 @@ class SyncFolderHandler extends Handler {
|
|||
return;
|
||||
}
|
||||
Pair<SynchronizeFolderOperation, String> removeResult =
|
||||
mPendingOperations.remove(account, file.getRemotePath());
|
||||
mPendingOperations.remove(account.name, file.getRemotePath());
|
||||
SynchronizeFolderOperation synchronization = removeResult.first;
|
||||
if (synchronization != null) {
|
||||
synchronization.cancel();
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
*
|
||||
* @author David A. Velasco
|
||||
* Copyright (C) 2012 Bartek Przybylski
|
||||
* Copyright (C) 2015 ownCloud Inc.
|
||||
* Copyright (C) 2016 ownCloud Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* ownCloud Android client application
|
||||
*
|
||||
* @author David A. Velasco
|
||||
* Copyright (C) 2015 ownCloud Inc.
|
||||
* Copyright (C) 2016 ownCloud Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
|
|
|
@ -300,9 +300,7 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter {
|
|||
|
||||
} else if (result.getCode() != ResultCode.FILE_NOT_FOUND) {
|
||||
// in failures, the statistics for the global result are updated
|
||||
if ( result.getCode() == RemoteOperationResult.ResultCode.UNAUTHORIZED ||
|
||||
result.isIdPRedirection()
|
||||
) {
|
||||
if (RemoteOperationResult.ResultCode.UNAUTHORIZED.equals(result.getCode())) {
|
||||
mSyncResult.stats.numAuthExceptions++;
|
||||
|
||||
} else if (result.getException() instanceof DavException) {
|
||||
|
@ -395,10 +393,8 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter {
|
|||
private void notifyFailedSynchronization() {
|
||||
NotificationCompat.Builder notificationBuilder = createNotificationBuilder();
|
||||
boolean needsToUpdateCredentials = (
|
||||
mLastFailedResult != null && (
|
||||
mLastFailedResult.getCode() == ResultCode.UNAUTHORIZED ||
|
||||
mLastFailedResult.isIdPRedirection()
|
||||
)
|
||||
mLastFailedResult != null &&
|
||||
ResultCode.UNAUTHORIZED.equals(mLastFailedResult.getCode())
|
||||
);
|
||||
if (needsToUpdateCredentials) {
|
||||
// let the user update credentials with one click
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* ownCloud Android client application
|
||||
*
|
||||
* Copyright (C) 2012 Bartek Przybylski
|
||||
* Copyright (C) 2015 ownCloud Inc.
|
||||
* Copyright (C) 2016 ownCloud Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
|
@ -29,19 +29,22 @@ import com.owncloud.android.services.OperationsService.OperationsServiceBinder;
|
|||
public interface ComponentsGetter {
|
||||
|
||||
/**
|
||||
* To be invoked when the parent activity is fully created to get a reference to the FileDownloader service API.
|
||||
* To be invoked when the parent activity is fully created to get a reference
|
||||
* to the FileDownloader service API.
|
||||
*/
|
||||
public FileDownloaderBinder getFileDownloaderBinder();
|
||||
|
||||
|
||||
/**
|
||||
* To be invoked when the parent activity is fully created to get a reference to the FileUploader service API.
|
||||
* To be invoked when the parent activity is fully created to get a reference
|
||||
* to the FileUploader service API.
|
||||
*/
|
||||
public FileUploaderBinder getFileUploaderBinder();
|
||||
|
||||
|
||||
/**
|
||||
* To be invoked when the parent activity is fully created to get a reference to the OperationsSerivce service API.
|
||||
* To be invoked when the parent activity is fully created to get a reference
|
||||
* to the OperationsSerivce service API.
|
||||
*/
|
||||
public OperationsServiceBinder getOperationsServiceBinder();
|
||||
|
||||
|
|
|
@ -1,23 +1,22 @@
|
|||
/**
|
||||
* ownCloud Android client application
|
||||
* ownCloud Android client application
|
||||
*
|
||||
* @author Bartek Przybylski
|
||||
* @author David A. Velasco
|
||||
* Copyright (C) 2012 Bartek Przybylski
|
||||
* Copyright (C) 2015 ownCloud Inc.
|
||||
* @author Bartek Przybylski
|
||||
* @author David A. Velasco
|
||||
* Copyright (C) 2012 Bartek Przybylski
|
||||
* Copyright (C) 2016 ownCloud Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 General Public License for more details.
|
||||
* <p/>
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.owncloud.android.ui.activity;
|
||||
|
@ -33,6 +32,7 @@ import com.owncloud.android.ui.dialog.ConflictsResolveDialog;
|
|||
import com.owncloud.android.ui.dialog.ConflictsResolveDialog.Decision;
|
||||
import com.owncloud.android.ui.dialog.ConflictsResolveDialog.OnConflictDecisionMadeListener;
|
||||
|
||||
|
||||
/**
|
||||
* Wrapper activity which will be launched if keep-in-sync file will be modified by external
|
||||
* application.
|
||||
|
@ -40,7 +40,7 @@ import com.owncloud.android.ui.dialog.ConflictsResolveDialog.OnConflictDecisionM
|
|||
public class ConflictsResolveActivity extends FileActivity implements OnConflictDecisionMadeListener {
|
||||
|
||||
private String TAG = ConflictsResolveActivity.class.getSimpleName();
|
||||
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
@ -48,18 +48,20 @@ public class ConflictsResolveActivity extends FileActivity implements OnConflict
|
|||
|
||||
@Override
|
||||
public void conflictDecisionMade(Decision decision) {
|
||||
Intent i = new Intent(getApplicationContext(), FileUploader.class);
|
||||
|
||||
|
||||
Integer behaviour = null;
|
||||
Boolean forceOverwrite = null;
|
||||
|
||||
switch (decision) {
|
||||
case CANCEL:
|
||||
finish();
|
||||
return;
|
||||
case OVERWRITE:
|
||||
// use local version -> overwrite on server
|
||||
i.putExtra(FileUploader.KEY_FORCE_OVERWRITE, true);
|
||||
forceOverwrite = true;
|
||||
break;
|
||||
case KEEP_BOTH:
|
||||
i.putExtra(FileUploader.KEY_LOCAL_BEHAVIOUR, FileUploader.LOCAL_BEHAVIOUR_MOVE);
|
||||
behaviour = FileUploader.LOCAL_BEHAVIOUR_MOVE;
|
||||
break;
|
||||
case SERVER:
|
||||
// use server version -> delete local, request download
|
||||
|
@ -73,11 +75,9 @@ public class ConflictsResolveActivity extends FileActivity implements OnConflict
|
|||
Log_OC.wtf(TAG, "Unhandled conflict decision " + decision);
|
||||
return;
|
||||
}
|
||||
i.putExtra(FileUploader.KEY_ACCOUNT, getAccount());
|
||||
i.putExtra(FileUploader.KEY_FILE, getFile());
|
||||
i.putExtra(FileUploader.KEY_UPLOAD_TYPE, FileUploader.UPLOAD_SINGLE_FILE);
|
||||
|
||||
startService(i);
|
||||
|
||||
FileUploader.UploadRequester requester = new FileUploader.UploadRequester();
|
||||
requester.uploadUpdate(this, getAccount(), getFile(), behaviour, forceOverwrite);
|
||||
finish();
|
||||
}
|
||||
|
||||
|
@ -91,21 +91,22 @@ public class ConflictsResolveActivity extends FileActivity implements OnConflict
|
|||
finish();
|
||||
} else {
|
||||
/// Check whether the 'main' OCFile handled by the Activity is contained in the current Account
|
||||
file = getStorageManager().getFileByPath(file.getRemotePath()); // file = null if not in the current Account
|
||||
file = getStorageManager().getFileByPath(file.getRemotePath()); // file = null if not in the
|
||||
// current Account
|
||||
if (file != null) {
|
||||
setFile(file);
|
||||
ConflictsResolveDialog d = ConflictsResolveDialog.newInstance(file.getRemotePath(), this);
|
||||
d.showDialog(this);
|
||||
|
||||
|
||||
} else {
|
||||
// account was changed to a different one - just finish
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
finish();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
*
|
||||
* @author David A. Velasco
|
||||
* Copyright (C) 2011 Bartek Przybylski
|
||||
* Copyright (C) 2015 ownCloud Inc.
|
||||
* Copyright (C) 2016 ownCloud Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
|
@ -111,8 +111,10 @@ public class FileActivity extends AppCompatActivity
|
|||
private static final String DIALOG_SHARE_PASSWORD = "DIALOG_SHARE_PASSWORD";
|
||||
private static final String KEY_ACTION_BAR_TITLE = "ACTION_BAR_TITLE";
|
||||
|
||||
protected static final long DELAY_TO_REQUEST_OPERATIONS_LATER = 200;
|
||||
public static final int REQUEST_CODE__UPDATE_CREDENTIALS = 0;
|
||||
public static final int REQUEST_CODE__LAST_SHARED = REQUEST_CODE__UPDATE_CREDENTIALS;
|
||||
|
||||
protected static final long DELAY_TO_REQUEST_OPERATIONS_LATER = 200;
|
||||
|
||||
/** OwnCloud {@link Account} where the main {@link OCFile} handled by the activity is located.*/
|
||||
private Account mAccount;
|
||||
|
@ -278,7 +280,6 @@ public class FileActivity extends AppCompatActivity
|
|||
super.onPause();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
if (mOperationsServiceConnection != null) {
|
||||
|
@ -400,13 +401,18 @@ public class FileActivity extends AppCompatActivity
|
|||
//mDrawerItems.add(new NavigationDrawerItem(mDrawerTitles[2],
|
||||
// mDrawerContentDescriptions[2]));
|
||||
|
||||
// Uploads
|
||||
mDrawerItems.add(new NavigationDrawerItem(mDrawerTitles[1], mDrawerContentDescriptions[2],
|
||||
R.drawable.ic_uploads));
|
||||
|
||||
// Settings
|
||||
mDrawerItems.add(new NavigationDrawerItem(mDrawerTitles[1], mDrawerContentDescriptions[1],
|
||||
mDrawerItems.add(new NavigationDrawerItem(mDrawerTitles[2], mDrawerContentDescriptions[1],
|
||||
R.drawable.ic_settings));
|
||||
|
||||
// Logs
|
||||
if (BuildConfig.DEBUG) {
|
||||
mDrawerItems.add(new NavigationDrawerItem(mDrawerTitles[2],
|
||||
mDrawerContentDescriptions[2],R.drawable.ic_log));
|
||||
mDrawerItems.add(new NavigationDrawerItem(mDrawerTitles[3],
|
||||
mDrawerContentDescriptions[3], R.drawable.ic_log));
|
||||
}
|
||||
|
||||
// setting the nav drawer list adapter
|
||||
|
@ -417,6 +423,7 @@ public class FileActivity extends AppCompatActivity
|
|||
|
||||
mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout,R.string.drawer_open,R.string.drawer_close) {
|
||||
|
||||
|
||||
/** Called when a drawer has settled in a completely closed state. */
|
||||
public void onDrawerClosed(View view) {
|
||||
super.onDrawerClosed(view);
|
||||
|
@ -448,7 +455,7 @@ public class FileActivity extends AppCompatActivity
|
|||
* @param navigationDrawerLayout the drawer layout to be used
|
||||
* @param account the account to be set in the drawer
|
||||
*/
|
||||
protected void setUsernameInDrawer(RelativeLayout navigationDrawerLayout, Account account) {
|
||||
protected void setUsernameInDrawer(View navigationDrawerLayout, Account account) {
|
||||
if (navigationDrawerLayout != null && account != null) {
|
||||
TextView username = (TextView) navigationDrawerLayout.findViewById(R.id.drawer_username);
|
||||
int lastAtPos = account.name.lastIndexOf("@");
|
||||
|
@ -462,7 +469,7 @@ public class FileActivity extends AppCompatActivity
|
|||
* Assumes that navigation drawer is NOT visible.
|
||||
*/
|
||||
protected void updateActionBarTitleAndHomeButton(OCFile chosenFile) {
|
||||
String title = getString(R.string.default_display_name_for_root_folder); // default
|
||||
String title = getDefaultTitle(); // default
|
||||
boolean inRoot;
|
||||
|
||||
/// choose the appropiate title
|
||||
|
@ -495,6 +502,9 @@ public class FileActivity extends AppCompatActivity
|
|||
|
||||
}
|
||||
|
||||
protected String getDefaultTitle() {
|
||||
return getString(R.string.default_display_name_for_root_folder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets and validates the ownCloud {@link Account} associated to the Activity.
|
||||
|
@ -725,7 +735,7 @@ public class FileActivity extends AppCompatActivity
|
|||
|
||||
/**
|
||||
*
|
||||
* @param operation Removal operation performed.
|
||||
* @param operation Operation performed.
|
||||
* @param result Result of the removal.
|
||||
*/
|
||||
@Override
|
||||
|
@ -739,14 +749,12 @@ public class FileActivity extends AppCompatActivity
|
|||
|
||||
if (!result.isSuccess() && (
|
||||
result.getCode() == ResultCode.UNAUTHORIZED ||
|
||||
result.isIdPRedirection() ||
|
||||
(result.isException() && result.getException() instanceof AuthenticatorException)
|
||||
)) {
|
||||
|
||||
requestCredentialsUpdate(this);
|
||||
|
||||
if (result.getCode() == ResultCode.UNAUTHORIZED) {
|
||||
dismissLoadingDialog();
|
||||
Toast t = Toast.makeText(this, ErrorMessageAdapter.getErrorCauseMessage(result,
|
||||
operation, getResources()),
|
||||
Toast.LENGTH_LONG);
|
||||
|
@ -793,16 +801,34 @@ public class FileActivity extends AppCompatActivity
|
|||
* Invalidates the credentials stored for the current OC account and requests new credentials to the user,
|
||||
* navigating to {@link AuthenticatorActivity}
|
||||
*
|
||||
* Equivalent to call requestCredentialsUpdate(context, null);
|
||||
*
|
||||
* @param context Android Context needed to access the {@link AccountManager}. Received as a parameter
|
||||
* to make the method accessible to {@link android.content.BroadcastReceiver}s.
|
||||
*/
|
||||
protected void requestCredentialsUpdate(Context context) {
|
||||
requestCredentialsUpdate(context, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidates the credentials stored for the given OC account and requests new credentials to the user,
|
||||
* navigating to {@link AuthenticatorActivity}
|
||||
*
|
||||
* @param context Android Context needed to access the {@link AccountManager}. Received as a parameter
|
||||
* to make the method accessible to {@link android.content.BroadcastReceiver}s.
|
||||
* @param account Stored OC account to request credentials update for. If null, current account will
|
||||
* be used.
|
||||
*/
|
||||
protected void requestCredentialsUpdate(Context context, Account account) {
|
||||
|
||||
try {
|
||||
/// step 1 - invalidate credentials of current account
|
||||
if (account == null) {
|
||||
account = getAccount();
|
||||
}
|
||||
OwnCloudClient client;
|
||||
OwnCloudAccount ocAccount =
|
||||
new OwnCloudAccount(getAccount(), context);
|
||||
new OwnCloudAccount(account, context);
|
||||
client = (OwnCloudClientManagerFactory.getDefaultSingleton().
|
||||
removeClientFor(ocAccount));
|
||||
if (client != null) {
|
||||
|
@ -811,23 +837,23 @@ public class FileActivity extends AppCompatActivity
|
|||
AccountManager am = AccountManager.get(context);
|
||||
if (cred.authTokenExpires()) {
|
||||
am.invalidateAuthToken(
|
||||
getAccount().type,
|
||||
account.type,
|
||||
cred.getAuthToken()
|
||||
);
|
||||
} else {
|
||||
am.clearPassword(getAccount());
|
||||
am.clearPassword(account);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// step 2 - request credentials to user
|
||||
Intent updateAccountCredentials = new Intent(this, AuthenticatorActivity.class);
|
||||
updateAccountCredentials.putExtra(AuthenticatorActivity.EXTRA_ACCOUNT, getAccount());
|
||||
updateAccountCredentials.putExtra(AuthenticatorActivity.EXTRA_ACCOUNT, account);
|
||||
updateAccountCredentials.putExtra(
|
||||
AuthenticatorActivity.EXTRA_ACTION,
|
||||
AuthenticatorActivity.ACTION_UPDATE_EXPIRED_TOKEN);
|
||||
updateAccountCredentials.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
|
||||
startActivity(updateAccountCredentials);
|
||||
startActivityForResult(updateAccountCredentials, REQUEST_CODE__UPDATE_CREDENTIALS);
|
||||
|
||||
} catch (com.owncloud.android.lib.common.accounts.AccountUtils.AccountNotFoundException e) {
|
||||
Toast.makeText(context, R.string.auth_account_does_not_exist, Toast.LENGTH_SHORT).show();
|
||||
|
@ -997,11 +1023,6 @@ public class FileActivity extends AppCompatActivity
|
|||
startActivity(i);
|
||||
}
|
||||
|
||||
// TODO re-enable when "Accounts" is available in Navigation Drawer
|
||||
// public void closeDrawer() {
|
||||
// mDrawerLayout.closeDrawers();
|
||||
// }
|
||||
|
||||
public void allFilesOption(){
|
||||
restart();
|
||||
}
|
||||
|
@ -1023,29 +1044,34 @@ public class FileActivity extends AppCompatActivity
|
|||
|
||||
case 0: // All Files
|
||||
allFilesOption();
|
||||
mDrawerLayout.closeDrawers();
|
||||
break;
|
||||
|
||||
// TODO Enable when "On Device" is recovered ?
|
||||
// case 2:
|
||||
// MainApp.showOnlyFilesOnDevice(true);
|
||||
// mDrawerLayout.closeDrawers();
|
||||
// break;
|
||||
|
||||
case 1: // Settings
|
||||
case 1: // Uploads
|
||||
Intent uploadListIntent = new Intent(getApplicationContext(),
|
||||
UploadListActivity.class);
|
||||
uploadListIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||
startActivity(uploadListIntent);
|
||||
break;
|
||||
|
||||
case 2: // Settings
|
||||
Intent settingsIntent = new Intent(getApplicationContext(),
|
||||
Preferences.class);
|
||||
startActivity(settingsIntent);
|
||||
mDrawerLayout.closeDrawers();
|
||||
break;
|
||||
|
||||
case 2: // Logs
|
||||
case 3: // Logs
|
||||
Intent loggerIntent = new Intent(getApplicationContext(),
|
||||
LogHistoryActivity.class);
|
||||
startActivity(loggerIntent);
|
||||
mDrawerLayout.closeDrawers();
|
||||
break;
|
||||
}
|
||||
mDrawerLayout.closeDrawers();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,23 +1,22 @@
|
|||
/**
|
||||
* ownCloud Android client application
|
||||
* ownCloud Android client application
|
||||
*
|
||||
* @author Bartek Przybylski
|
||||
* @author David A. Velasco
|
||||
* Copyright (C) 2011 Bartek Przybylski
|
||||
* Copyright (C) 2015 ownCloud Inc.
|
||||
* @author Bartek Przybylski
|
||||
* @author David A. Velasco
|
||||
* Copyright (C) 2011 Bartek Przybylski
|
||||
* Copyright (C) 2016 ownCloud Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.owncloud.android.ui.activity;
|
||||
|
@ -57,7 +56,6 @@ import android.view.MenuInflater;
|
|||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.owncloud.android.MainApp;
|
||||
|
@ -80,10 +78,10 @@ import com.owncloud.android.operations.RefreshFolderOperation;
|
|||
import com.owncloud.android.operations.RemoveFileOperation;
|
||||
import com.owncloud.android.operations.RenameFileOperation;
|
||||
import com.owncloud.android.operations.SynchronizeFileOperation;
|
||||
import com.owncloud.android.operations.UploadFileOperation;
|
||||
import com.owncloud.android.services.observer.FileObserverService;
|
||||
import com.owncloud.android.syncadapter.FileSyncAdapter;
|
||||
import com.owncloud.android.ui.dialog.ConfirmationDialogFragment;
|
||||
import com.owncloud.android.ui.dialog.CreateFolderDialogFragment;
|
||||
import com.owncloud.android.ui.dialog.SslUntrustedCertDialog;
|
||||
import com.owncloud.android.ui.dialog.SslUntrustedCertDialog.OnSslUntrustedCertListener;
|
||||
import com.owncloud.android.ui.fragment.FileDetailFragment;
|
||||
|
@ -103,11 +101,11 @@ import com.owncloud.android.utils.UriUtils;
|
|||
import java.io.File;
|
||||
|
||||
/**
|
||||
* Displays, what files the user has available in his ownCloud.
|
||||
* Displays, what files the user has available in his ownCloud. This is the main view.
|
||||
*/
|
||||
|
||||
public class FileDisplayActivity extends HookActivity
|
||||
implements FileFragment.ContainerActivity,
|
||||
public class FileDisplayActivity extends HookActivity implements
|
||||
FileFragment.ContainerActivity,
|
||||
OnSslUntrustedCertListener, OnEnforceableRefreshListener {
|
||||
|
||||
private SyncBroadcastReceiver mSyncBroadcastReceiver;
|
||||
|
@ -126,10 +124,10 @@ public class FileDisplayActivity extends HookActivity
|
|||
|
||||
public static final String ACTION_DETAILS = "com.owncloud.android.ui.activity.action.DETAILS";
|
||||
|
||||
public static final int ACTION_SELECT_CONTENT_FROM_APPS = 1;
|
||||
public static final int ACTION_SELECT_MULTIPLE_FILES = 2;
|
||||
public static final int ACTION_MOVE_FILES = 3;
|
||||
public static final int ACTION_COPY_FILES = 4;
|
||||
public static final int REQUEST_CODE__SELECT_CONTENT_FROM_APPS = REQUEST_CODE__LAST_SHARED + 1;
|
||||
public static final int REQUEST_CODE__SELECT_MULTIPLE_FILES = REQUEST_CODE__LAST_SHARED + 2;
|
||||
public static final int REQUEST_CODE__MOVE_FILES = REQUEST_CODE__LAST_SHARED + 3;
|
||||
public static final int REQUEST_CODE__COPY_FILES = REQUEST_CODE__LAST_SHARED + 4;
|
||||
|
||||
private static final String TAG = FileDisplayActivity.class.getSimpleName();
|
||||
|
||||
|
@ -152,7 +150,7 @@ public class FileDisplayActivity extends HookActivity
|
|||
Log_OC.v(TAG, "onCreate() start");
|
||||
|
||||
super.onCreate(savedInstanceState); // this calls onAccountChanged() when ownCloud Account
|
||||
// is valid
|
||||
// is valid
|
||||
|
||||
/// grant that FileObserverService is watching favorite files
|
||||
if (savedInstanceState == null) {
|
||||
|
@ -161,7 +159,7 @@ public class FileDisplayActivity extends HookActivity
|
|||
}
|
||||
|
||||
/// Load of saved instance state
|
||||
if(savedInstanceState != null) {
|
||||
if (savedInstanceState != null) {
|
||||
mWaitingToPreview = (OCFile) savedInstanceState.getParcelable(
|
||||
FileDisplayActivity.KEY_WAITING_TO_PREVIEW);
|
||||
mSyncInProgress = savedInstanceState.getBoolean(KEY_SYNC_IN_PROGRESS);
|
||||
|
@ -192,8 +190,8 @@ public class FileDisplayActivity extends HookActivity
|
|||
|
||||
// Action bar setup
|
||||
getSupportActionBar().setHomeButtonEnabled(true); // mandatory since Android ICS,
|
||||
// according to the official
|
||||
// documentation
|
||||
// according to the official
|
||||
// documentation
|
||||
|
||||
// enable ActionBar app icon to behave as action to toggle nav drawer
|
||||
//getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
|
@ -297,7 +295,7 @@ public class FileDisplayActivity extends HookActivity
|
|||
// cache until the upload is successful get parent from path
|
||||
parentPath = file.getRemotePath().substring(0,
|
||||
file.getRemotePath().lastIndexOf(file.getFileName()));
|
||||
if (getStorageManager().getFileByPath(parentPath) == null)
|
||||
if (getStorageManager().getFileByPath(parentPath) == null)
|
||||
file = null; // not able to know the directory where the file is uploading
|
||||
} else {
|
||||
file = getStorageManager().getFileByPath(file.getRemotePath());
|
||||
|
@ -311,7 +309,7 @@ public class FileDisplayActivity extends HookActivity
|
|||
setFile(file);
|
||||
|
||||
if (mAccountWasSet) {
|
||||
setUsernameInDrawer((RelativeLayout) findViewById(R.id.left_drawer), getAccount());
|
||||
setUsernameInDrawer(findViewById(R.id.left_drawer), getAccount());
|
||||
}
|
||||
|
||||
if (!stateWasRecovered) {
|
||||
|
@ -355,7 +353,6 @@ public class FileDisplayActivity extends HookActivity
|
|||
setSecondFragment(secondFragment);
|
||||
updateFragmentsVisibility(true);
|
||||
updateActionBarTitleAndHomeButton(file);
|
||||
|
||||
} else {
|
||||
cleanSecondFragment();
|
||||
if (file.isDown() && PreviewTextFragment.canBePreviewed(file))
|
||||
|
@ -389,8 +386,8 @@ public class FileDisplayActivity extends HookActivity
|
|||
} else if (file.isDown() && PreviewTextFragment.canBePreviewed(file)) {
|
||||
secondFragment = null;
|
||||
} else {
|
||||
secondFragment = FileDetailFragment.newInstance(file, getAccount());
|
||||
}
|
||||
secondFragment = FileDetailFragment.newInstance(file, getAccount());
|
||||
}
|
||||
}
|
||||
return secondFragment;
|
||||
}
|
||||
|
@ -488,7 +485,7 @@ public class FileDisplayActivity extends HookActivity
|
|||
OCFile fileInFragment = detailsFragment.getFile();
|
||||
if (fileInFragment != null &&
|
||||
!downloadedRemotePath.equals(fileInFragment.getRemotePath())) {
|
||||
// the user browsed to other file ; forget the automatic preview
|
||||
// the user browsed to other file ; forget the automatic preview
|
||||
mWaitingToPreview = null;
|
||||
|
||||
} else if (downloadEvent.equals(FileDownloader.getDownloadAddedMessage())) {
|
||||
|
@ -503,7 +500,7 @@ public class FileDisplayActivity extends HookActivity
|
|||
if (success) {
|
||||
mWaitingToPreview = getStorageManager().getFileById(
|
||||
mWaitingToPreview.getFileId()); // update the file from database,
|
||||
// for the local storage path
|
||||
// for the local storage path
|
||||
if (PreviewMediaFragment.canBePreviewed(mWaitingToPreview)) {
|
||||
startMediaPreview(mWaitingToPreview, 0, true);
|
||||
detailsFragmentChanged = true;
|
||||
|
@ -540,7 +537,7 @@ public class FileDisplayActivity extends HookActivity
|
|||
menu.findItem(R.id.action_create_dir).setVisible(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
|
@ -555,7 +552,7 @@ public class FileDisplayActivity extends HookActivity
|
|||
OCFile currentDir = getCurrentDir();
|
||||
if (mDrawerLayout.isDrawerOpen(GravityCompat.START)) {
|
||||
mDrawerLayout.closeDrawer(GravityCompat.START);
|
||||
} else if((currentDir != null && currentDir.getParentId() != 0) ||
|
||||
} else if ((currentDir != null && currentDir.getParentId() != 0) ||
|
||||
(second != null && second.getFile() != null)) {
|
||||
onBackPressed();
|
||||
|
||||
|
@ -574,26 +571,26 @@ public class FileDisplayActivity extends HookActivity
|
|||
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||
builder.setTitle(R.string.actionbar_sort_title)
|
||||
.setSingleChoiceItems(R.array.actionbar_sortby, sortOrder ,
|
||||
.setSingleChoiceItems(R.array.actionbar_sortby, sortOrder,
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
switch (which){
|
||||
case 0:
|
||||
sortByName(true);
|
||||
break;
|
||||
case 1:
|
||||
sortByDate(false);
|
||||
break;
|
||||
}
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
switch (which) {
|
||||
case 0:
|
||||
sortByName(true);
|
||||
break;
|
||||
case 1:
|
||||
sortByDate(false);
|
||||
break;
|
||||
}
|
||||
|
||||
dialog.dismiss();
|
||||
}
|
||||
});
|
||||
dialog.dismiss();
|
||||
}
|
||||
});
|
||||
builder.create().show();
|
||||
break;
|
||||
}
|
||||
case R.id.action_switch_view:{
|
||||
if (isGridView()){
|
||||
case R.id.action_switch_view: {
|
||||
if (isGridView()) {
|
||||
item.setTitle(getString(R.string.action_switch_grid_view));
|
||||
item.setIcon(ContextCompat.getDrawable(getApplicationContext(),
|
||||
R.drawable.ic_view_module));
|
||||
|
@ -606,8 +603,8 @@ public class FileDisplayActivity extends HookActivity
|
|||
}
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
retval = super.onOptionsItemSelected(item);
|
||||
default:
|
||||
retval = super.onOptionsItemSelected(item);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
@ -646,13 +643,12 @@ public class FileDisplayActivity extends HookActivity
|
|||
|
||||
/**
|
||||
* Called, when the user selected something for uploading
|
||||
*
|
||||
*/
|
||||
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
|
||||
if (requestCode == ACTION_SELECT_CONTENT_FROM_APPS && (resultCode == RESULT_OK ||
|
||||
if (requestCode == REQUEST_CODE__SELECT_CONTENT_FROM_APPS && (resultCode == RESULT_OK ||
|
||||
resultCode == UploadFilesActivity.RESULT_OK_AND_MOVE)) {
|
||||
|
||||
//getClipData is only supported on api level 16+, Jelly Bean
|
||||
|
@ -660,7 +656,7 @@ public class FileDisplayActivity extends HookActivity
|
|||
data.getClipData() != null &&
|
||||
data.getClipData().getItemCount() > 0) {
|
||||
|
||||
for( int i = 0; i < data.getClipData().getItemCount(); i++){
|
||||
for (int i = 0; i < data.getClipData().getItemCount(); i++) {
|
||||
Intent intent = new Intent();
|
||||
intent.setData(data.getClipData().getItemAt(i).getUri());
|
||||
requestSimpleUpload(intent, resultCode);
|
||||
|
@ -669,11 +665,11 @@ public class FileDisplayActivity extends HookActivity
|
|||
} else {
|
||||
requestSimpleUpload(data, resultCode);
|
||||
}
|
||||
} else if (requestCode == ACTION_SELECT_MULTIPLE_FILES && (resultCode == RESULT_OK ||
|
||||
} else if (requestCode == REQUEST_CODE__SELECT_MULTIPLE_FILES && (resultCode == RESULT_OK ||
|
||||
resultCode == UploadFilesActivity.RESULT_OK_AND_MOVE)) {
|
||||
requestMultipleUpload(data, resultCode);
|
||||
|
||||
} else if (requestCode == ACTION_MOVE_FILES && resultCode == RESULT_OK){
|
||||
} else if (requestCode == REQUEST_CODE__MOVE_FILES && resultCode == RESULT_OK) {
|
||||
final Intent fData = data;
|
||||
final int fResultCode = resultCode;
|
||||
getHandler().postDelayed(
|
||||
|
@ -686,7 +682,7 @@ public class FileDisplayActivity extends HookActivity
|
|||
DELAY_TO_REQUEST_OPERATIONS_LATER
|
||||
);
|
||||
|
||||
} else if (requestCode == ACTION_COPY_FILES && resultCode == RESULT_OK) {
|
||||
} else if (requestCode == REQUEST_CODE__COPY_FILES && resultCode == RESULT_OK) {
|
||||
|
||||
final Intent fData = data;
|
||||
final int fResultCode = resultCode;
|
||||
|
@ -711,18 +707,23 @@ public class FileDisplayActivity extends HookActivity
|
|||
if (filePaths != null) {
|
||||
String[] remotePaths = new String[filePaths.length];
|
||||
String remotePathBase = getCurrentDir().getRemotePath();
|
||||
for (int j = 0; j< remotePaths.length; j++) {
|
||||
for (int j = 0; j < remotePaths.length; j++) {
|
||||
remotePaths[j] = remotePathBase + (new File(filePaths[j])).getName();
|
||||
}
|
||||
|
||||
Intent i = new Intent(this, FileUploader.class);
|
||||
i.putExtra(FileUploader.KEY_ACCOUNT, getAccount());
|
||||
i.putExtra(FileUploader.KEY_LOCAL_FILE, filePaths);
|
||||
i.putExtra(FileUploader.KEY_REMOTE_FILE, remotePaths);
|
||||
i.putExtra(FileUploader.KEY_UPLOAD_TYPE, FileUploader.UPLOAD_MULTIPLE_FILES);
|
||||
if (resultCode == UploadFilesActivity.RESULT_OK_AND_MOVE)
|
||||
i.putExtra(FileUploader.KEY_LOCAL_BEHAVIOUR, FileUploader.LOCAL_BEHAVIOUR_MOVE);
|
||||
startService(i);
|
||||
int behaviour = (resultCode == UploadFilesActivity.RESULT_OK_AND_MOVE) ? FileUploader
|
||||
.LOCAL_BEHAVIOUR_MOVE : FileUploader.LOCAL_BEHAVIOUR_COPY;
|
||||
FileUploader.UploadRequester requester = new FileUploader.UploadRequester();
|
||||
requester.uploadNewFile(
|
||||
this,
|
||||
getAccount(),
|
||||
filePaths,
|
||||
remotePaths,
|
||||
null, // MIME type will be detected from file name
|
||||
behaviour,
|
||||
false, // do not create parent folder if not existent
|
||||
UploadFileOperation.CREATED_BY_USER
|
||||
);
|
||||
|
||||
} else {
|
||||
Log_OC.d(TAG, "User clicked on 'Update' with no selection");
|
||||
|
@ -768,9 +769,10 @@ public class FileDisplayActivity extends HookActivity
|
|||
}
|
||||
|
||||
Intent i = new Intent(this, FileUploader.class);
|
||||
i.putExtra(FileUploader.KEY_ACCOUNT, getAccount());
|
||||
i.putExtra(FileUploader.KEY_ACCOUNT,
|
||||
getAccount());
|
||||
OCFile currentDir = getCurrentDir();
|
||||
String remotePath = (currentDir != null) ? currentDir.getRemotePath() : OCFile.ROOT_PATH;
|
||||
String remotePath = (currentDir != null) ? currentDir.getRemotePath() : OCFile.ROOT_PATH;
|
||||
|
||||
if (filePath.startsWith(UriUtils.URI_CONTENT_SCHEME)) {
|
||||
Cursor cursor = getContentResolver().query(Uri.parse(filePath), null, null, null, null);
|
||||
|
@ -778,7 +780,7 @@ public class FileDisplayActivity extends HookActivity
|
|||
if (cursor != null && cursor.moveToFirst()) {
|
||||
String displayName = cursor.getString(cursor.getColumnIndex(
|
||||
OpenableColumns.DISPLAY_NAME));
|
||||
Log_OC.v(TAG, "Display Name: " + displayName );
|
||||
Log_OC.v(TAG, "Display Name: " + displayName);
|
||||
|
||||
displayName.replace(File.separatorChar, '_');
|
||||
displayName.replace(File.pathSeparatorChar, '_');
|
||||
|
@ -794,13 +796,20 @@ public class FileDisplayActivity extends HookActivity
|
|||
remotePath += new File(filePath).getName();
|
||||
}
|
||||
|
||||
i.putExtra(FileUploader.KEY_LOCAL_FILE, filePath);
|
||||
i.putExtra(FileUploader.KEY_REMOTE_FILE, remotePath);
|
||||
i.putExtra(FileUploader.KEY_MIME_TYPE, mimeType);
|
||||
i.putExtra(FileUploader.KEY_UPLOAD_TYPE, FileUploader.UPLOAD_SINGLE_FILE);
|
||||
if (resultCode == UploadFilesActivity.RESULT_OK_AND_MOVE)
|
||||
i.putExtra(FileUploader.KEY_LOCAL_BEHAVIOUR, FileUploader.LOCAL_BEHAVIOUR_MOVE);
|
||||
startService(i);
|
||||
int behaviour = (resultCode == UploadFilesActivity.RESULT_OK_AND_MOVE) ? FileUploader.LOCAL_BEHAVIOUR_MOVE :
|
||||
FileUploader.LOCAL_BEHAVIOUR_COPY;
|
||||
FileUploader.UploadRequester requester = new FileUploader.UploadRequester();
|
||||
requester.uploadNewFile(
|
||||
this,
|
||||
getAccount(),
|
||||
filePath,
|
||||
remotePath,
|
||||
behaviour,
|
||||
mimeType,
|
||||
false, // do not create parent folder if not existent
|
||||
UploadFileOperation.CREATED_BY_USER
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -882,7 +891,6 @@ public class FileDisplayActivity extends HookActivity
|
|||
Log_OC.v(TAG, "onSaveInstanceState() end");
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
Log_OC.v(TAG, "onResume() start");
|
||||
|
@ -964,6 +972,7 @@ public class FileDisplayActivity extends HookActivity
|
|||
String event = intent.getAction();
|
||||
Log_OC.d(TAG, "Received broadcast " + event);
|
||||
String accountName = intent.getStringExtra(FileSyncAdapter.EXTRA_ACCOUNT_NAME);
|
||||
|
||||
String synchFolderRemotePath =
|
||||
intent.getStringExtra(FileSyncAdapter.EXTRA_FOLDER_PATH);
|
||||
RemoteOperationResult synchResult =
|
||||
|
@ -982,16 +991,17 @@ public class FileDisplayActivity extends HookActivity
|
|||
getStorageManager().getFileByPath(getFile().getRemotePath());
|
||||
OCFile currentDir = (getCurrentDir() == null) ? null :
|
||||
getStorageManager().getFileByPath(getCurrentDir().getRemotePath());
|
||||
|
||||
|
||||
if (currentDir == null) {
|
||||
// current folder was removed from the server
|
||||
Toast.makeText( FileDisplayActivity.this,
|
||||
String.format(
|
||||
getString(R.string.
|
||||
sync_current_folder_was_removed),
|
||||
synchFolderRemotePath),
|
||||
Toast.LENGTH_LONG)
|
||||
.show();
|
||||
Toast.makeText(FileDisplayActivity.this,
|
||||
String.format(
|
||||
getString(R.string.
|
||||
sync_current_folder_was_removed),
|
||||
synchFolderRemotePath),
|
||||
|
||||
Toast.LENGTH_LONG)
|
||||
.show();
|
||||
|
||||
browseToRoot();
|
||||
|
||||
|
@ -1019,13 +1029,12 @@ public class FileDisplayActivity extends HookActivity
|
|||
mSyncInProgress = (!FileSyncAdapter.EVENT_FULL_SYNC_END.equals(event) &&
|
||||
!RefreshFolderOperation.EVENT_SINGLE_FOLDER_SHARES_SYNCED
|
||||
.equals(event));
|
||||
|
||||
|
||||
if (RefreshFolderOperation.EVENT_SINGLE_FOLDER_CONTENTS_SYNCED.
|
||||
equals(event) &&/// TODO refactor and make common
|
||||
equals(event) &&/// TODO refactor and make common
|
||||
|
||||
synchResult != null && !synchResult.isSuccess() &&
|
||||
(synchResult.getCode() == ResultCode.UNAUTHORIZED ||
|
||||
synchResult.isIdPRedirection() ||
|
||||
(ResultCode.UNAUTHORIZED.equals(synchResult.getCode()) ||
|
||||
(synchResult.isException() && synchResult.getException()
|
||||
instanceof AuthenticatorException))) {
|
||||
|
||||
|
@ -1049,7 +1058,7 @@ public class FileDisplayActivity extends HookActivity
|
|||
}
|
||||
}
|
||||
} catch (RuntimeException e) {
|
||||
// avoid app crashes after changing the serial id of RemoteOperationResult
|
||||
// avoid app crashes after changing the serial id of RemoteOperationResult
|
||||
// in owncloud library with broadcast notifications pending to process
|
||||
removeStickyBroadcast(intent);
|
||||
}
|
||||
|
@ -1102,10 +1111,12 @@ public class FileDisplayActivity extends HookActivity
|
|||
}
|
||||
}
|
||||
|
||||
boolean uploadWasFine = intent.getBooleanExtra(FileUploader.EXTRA_UPLOAD_RESULT,
|
||||
boolean uploadWasFine = intent.getBooleanExtra(
|
||||
FileUploader.EXTRA_UPLOAD_RESULT,
|
||||
false);
|
||||
boolean renamedInUpload = getFile().getRemotePath().
|
||||
equals(intent.getStringExtra(FileUploader.EXTRA_OLD_REMOTE_PATH));
|
||||
|
||||
boolean sameFile = getFile().getRemotePath().equals(uploadedRemotePath) ||
|
||||
renamedInUpload;
|
||||
FileFragment details = getSecondFragment();
|
||||
|
@ -1115,6 +1126,8 @@ public class FileDisplayActivity extends HookActivity
|
|||
if (sameAccount && sameFile && detailFragmentIsShown) {
|
||||
if (uploadWasFine) {
|
||||
setFile(getStorageManager().getFileByPath(uploadedRemotePath));
|
||||
} else {
|
||||
//TODO remove upload progress bar after upload failed.
|
||||
}
|
||||
if (renamedInUpload) {
|
||||
String newName = (new File(uploadedRemotePath)).getName();
|
||||
|
@ -1144,6 +1157,7 @@ public class FileDisplayActivity extends HookActivity
|
|||
}
|
||||
|
||||
mProgressBar.setIndeterminate(false);
|
||||
|
||||
} finally {
|
||||
if (intent != null) {
|
||||
removeStickyBroadcast(intent);
|
||||
|
@ -1161,13 +1175,12 @@ public class FileDisplayActivity extends HookActivity
|
|||
);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Class waiting for broadcast events from the {@link FileDownloader} service.
|
||||
*
|
||||
* <p/>
|
||||
* Updates the UI when a download is started or finished, provided that it is relevant for the
|
||||
* current folder.
|
||||
*/
|
||||
|
@ -1212,17 +1225,17 @@ public class FileDisplayActivity extends HookActivity
|
|||
private boolean isDescendant(String downloadedRemotePath) {
|
||||
OCFile currentDir = getCurrentDir();
|
||||
return (
|
||||
currentDir != null &&
|
||||
downloadedRemotePath != null &&
|
||||
downloadedRemotePath.startsWith(currentDir.getRemotePath())
|
||||
currentDir != null &&
|
||||
downloadedRemotePath != null &&
|
||||
downloadedRemotePath.startsWith(currentDir.getRemotePath())
|
||||
);
|
||||
}
|
||||
|
||||
private boolean isAscendant(String linkedToRemotePath) {
|
||||
OCFile currentDir = getCurrentDir();
|
||||
return (
|
||||
currentDir != null &&
|
||||
currentDir.getRemotePath().startsWith(linkedToRemotePath)
|
||||
currentDir != null &&
|
||||
currentDir.getRemotePath().startsWith(linkedToRemotePath)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1250,7 +1263,6 @@ public class FileDisplayActivity extends HookActivity
|
|||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* <p/>
|
||||
* Updates action bar and second fragment, if in dual pane mode.
|
||||
*/
|
||||
@Override
|
||||
|
@ -1306,7 +1318,7 @@ public class FileDisplayActivity extends HookActivity
|
|||
mDownloaderBinder = (FileDownloaderBinder) service;
|
||||
if (mWaitingToPreview != null)
|
||||
if (getStorageManager() != null) {
|
||||
// update the file
|
||||
// update the file
|
||||
mWaitingToPreview =
|
||||
getStorageManager().getFileById(mWaitingToPreview.getFileId());
|
||||
if (!mWaitingToPreview.isDown()) {
|
||||
|
@ -1425,9 +1437,9 @@ public class FileDisplayActivity extends HookActivity
|
|||
/**
|
||||
* Updates the view associated to the activity after the finish of an operation trying to
|
||||
* remove a file.
|
||||
*
|
||||
* @param operation Removal operation performed.
|
||||
* @param result Result of the removal.
|
||||
*
|
||||
* @param operation Removal operation performed.
|
||||
* @param result Result of the removal.
|
||||
*/
|
||||
private void onRemoveFileOperationFinish(RemoveFileOperation operation,
|
||||
RemoteOperationResult result) {
|
||||
|
@ -1446,7 +1458,7 @@ public class FileDisplayActivity extends HookActivity
|
|||
setFile(getStorageManager().getFileById(removedFile.getParentId()));
|
||||
cleanSecondFragment();
|
||||
}
|
||||
if (getStorageManager().getFileById(removedFile.getParentId()).equals(getCurrentDir())){
|
||||
if (getStorageManager().getFileById(removedFile.getParentId()).equals(getCurrentDir())) {
|
||||
refreshListOfFilesFragment();
|
||||
}
|
||||
invalidateOptionsMenu();
|
||||
|
@ -1509,9 +1521,9 @@ public class FileDisplayActivity extends HookActivity
|
|||
/**
|
||||
* Updates the view associated to the activity after the finish of an operation trying to rename
|
||||
* a file.
|
||||
*
|
||||
* @param operation Renaming operation performed.
|
||||
* @param result Result of the renaming.
|
||||
*
|
||||
* @param operation Renaming operation performed.
|
||||
* @param result Result of the renaming.
|
||||
*/
|
||||
private void onRenameFileOperationFinish(RenameFileOperation operation,
|
||||
RemoteOperationResult result) {
|
||||
|
@ -1520,7 +1532,7 @@ public class FileDisplayActivity extends HookActivity
|
|||
FileFragment details = getSecondFragment();
|
||||
if (details != null) {
|
||||
if (details instanceof FileDetailFragment &&
|
||||
renamedFile.equals(details.getFile()) ) {
|
||||
renamedFile.equals(details.getFile())) {
|
||||
((FileDetailFragment) details).updateFileDetails(renamedFile, getAccount());
|
||||
showDetails(renamedFile);
|
||||
|
||||
|
@ -1544,7 +1556,7 @@ public class FileDisplayActivity extends HookActivity
|
|||
}
|
||||
}
|
||||
|
||||
if (getStorageManager().getFileById(renamedFile.getParentId()).equals(getCurrentDir())){
|
||||
if (getStorageManager().getFileById(renamedFile.getParentId()).equals(getCurrentDir())) {
|
||||
refreshListOfFilesFragment();
|
||||
}
|
||||
|
||||
|
@ -1561,6 +1573,7 @@ public class FileDisplayActivity extends HookActivity
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
private void onSynchronizeFileOperationFinish(SynchronizeFileOperation operation,
|
||||
RemoteOperationResult result) {
|
||||
if (result.isSuccess()) {
|
||||
|
@ -1576,9 +1589,9 @@ public class FileDisplayActivity extends HookActivity
|
|||
/**
|
||||
* Updates the view associated to the activity after the finish of an operation trying create a
|
||||
* new folder
|
||||
*
|
||||
* @param operation Creation operation performed.
|
||||
* @param result Result of the creation.
|
||||
*
|
||||
* @param operation Creation operation performed.
|
||||
* @param result Result of the creation.
|
||||
*/
|
||||
private void onCreateFolderOperationFinish(CreateFolderOperation operation,
|
||||
RemoteOperationResult result) {
|
||||
|
@ -1606,7 +1619,7 @@ public class FileDisplayActivity extends HookActivity
|
|||
refreshListOfFilesFragment();
|
||||
FileFragment details = getSecondFragment();
|
||||
if (details != null && details instanceof FileDetailFragment &&
|
||||
file.equals(details.getFile()) ) {
|
||||
file.equals(details.getFile())) {
|
||||
if (downloading || uploading) {
|
||||
((FileDetailFragment) details).updateFileDetails(file, getAccount());
|
||||
} else {
|
||||
|
@ -1649,16 +1662,16 @@ public class FileDisplayActivity extends HookActivity
|
|||
|
||||
/**
|
||||
* Starts an operation to refresh the requested folder.
|
||||
*
|
||||
* <p/>
|
||||
* The operation is run in a new background thread created on the fly.
|
||||
*
|
||||
* <p/>
|
||||
* The refresh updates is a "light sync": properties of regular files in folder are updated (including
|
||||
* associated shares), but not their contents. Only the contents of files marked to be kept-in-sync are
|
||||
* synchronized too.
|
||||
*
|
||||
* @param folder Folder to refresh.
|
||||
* @param ignoreETag If 'true', the data from the server will be fetched and sync'ed even if the eTag
|
||||
* didn't change.
|
||||
* @param folder Folder to refresh.
|
||||
* @param ignoreETag If 'true', the data from the server will be fetched and sync'ed even if the eTag
|
||||
* didn't change.
|
||||
*/
|
||||
public void startSyncFolderOperation(final OCFile folder, final boolean ignoreETag) {
|
||||
|
||||
|
@ -1755,16 +1768,17 @@ public class FileDisplayActivity extends HookActivity
|
|||
showDetailsIntent.putExtra(EXTRA_FILE, file);
|
||||
showDetailsIntent.putExtra(EXTRA_ACCOUNT, getAccount());
|
||||
startActivity(showDetailsIntent);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Stars the preview of an already down media {@link OCFile}.
|
||||
*
|
||||
* @param file Media {@link OCFile} to preview.
|
||||
* @param startPlaybackPosition Media position where the playback will be started,
|
||||
* in milliseconds.
|
||||
* @param autoplay When 'true', the playback will start without user
|
||||
* interactions.
|
||||
* @param file Media {@link OCFile} to preview.
|
||||
* @param startPlaybackPosition Media position where the playback will be started,
|
||||
* in milliseconds.
|
||||
* @param autoplay When 'true', the playback will start without user
|
||||
* interactions.
|
||||
*/
|
||||
public void startMediaPreview(OCFile file, int startPlaybackPosition, boolean autoplay) {
|
||||
Fragment mediaFragment = new PreviewMediaFragment(file, getAccount(), startPlaybackPosition,
|
||||
|
@ -1856,9 +1870,12 @@ public class FileDisplayActivity extends HookActivity
|
|||
private void sortByName(boolean ascending) {
|
||||
getListOfFilesFragment().sortByName(ascending);
|
||||
}
|
||||
private boolean isGridView(){ return getListOfFilesFragment().isGridView(); }
|
||||
|
||||
public void allFilesOption() {
|
||||
browseToRoot();
|
||||
}
|
||||
private boolean isGridView() {
|
||||
return getListOfFilesFragment().isGridView();
|
||||
}
|
||||
|
||||
public void allFilesOption() {
|
||||
browseToRoot();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
* ownCloud Android client application
|
||||
*
|
||||
* Copyright (C) 2015 ownCloud Inc.
|
||||
* Copyright (C) 2016 ownCloud Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
|
@ -20,7 +20,6 @@
|
|||
package com.owncloud.android.ui.activity;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.accounts.AccountManager;
|
||||
import android.accounts.AuthenticatorException;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
|
@ -44,11 +43,6 @@ import android.widget.Toast;
|
|||
|
||||
import com.owncloud.android.R;
|
||||
import com.owncloud.android.datamodel.OCFile;
|
||||
import com.owncloud.android.lib.common.OwnCloudAccount;
|
||||
import com.owncloud.android.lib.common.OwnCloudClient;
|
||||
import com.owncloud.android.lib.common.OwnCloudClientManagerFactory;
|
||||
import com.owncloud.android.lib.common.OwnCloudCredentials;
|
||||
import com.owncloud.android.lib.common.accounts.AccountUtils.AccountNotFoundException;
|
||||
import com.owncloud.android.lib.common.operations.RemoteOperation;
|
||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
|
||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;
|
||||
|
@ -379,6 +373,7 @@ public class FolderPickerActivity extends FileActivity implements FileFragment.C
|
|||
data.putExtra(EXTRA_FILE, targetFile);
|
||||
}
|
||||
setResult(RESULT_OK, data);
|
||||
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
@ -486,9 +481,8 @@ public class FolderPickerActivity extends FileActivity implements FileFragment.C
|
|||
equals(event) &&
|
||||
/// TODO refactor and make common
|
||||
synchResult != null && !synchResult.isSuccess() &&
|
||||
(synchResult.getCode() == ResultCode.UNAUTHORIZED ||
|
||||
synchResult.isIdPRedirection() ||
|
||||
(synchResult.isException() && synchResult.getException()
|
||||
(ResultCode.UNAUTHORIZED.equals(synchResult.getCode()) ||
|
||||
(synchResult.isException() && synchResult.getException()
|
||||
instanceof AuthenticatorException))) {
|
||||
|
||||
requestCredentialsUpdate(context);
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* @author Bartek Przybylski
|
||||
* @author David A. Velasco
|
||||
* Copyright (C) 2011 Bartek Przybylski
|
||||
* Copyright (C) 2015 ownCloud Inc.
|
||||
* Copyright (C) 2016 ownCloud Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
|
@ -71,7 +71,6 @@ import com.owncloud.android.authentication.AccountUtils;
|
|||
import com.owncloud.android.authentication.AuthenticatorActivity;
|
||||
import com.owncloud.android.datamodel.FileDataStorageManager;
|
||||
import com.owncloud.android.datamodel.OCFile;
|
||||
import com.owncloud.android.db.DbHandler;
|
||||
import com.owncloud.android.files.FileOperationsHelper;
|
||||
import com.owncloud.android.files.services.FileDownloader;
|
||||
import com.owncloud.android.files.services.FileUploader;
|
||||
|
@ -92,12 +91,12 @@ public class Preferences extends PreferenceActivity
|
|||
|
||||
private static final String TAG = Preferences.class.getSimpleName();
|
||||
|
||||
|
||||
private static final int ACTION_SELECT_UPLOAD_PATH = 1;
|
||||
private static final int ACTION_SELECT_UPLOAD_VIDEO_PATH = 2;
|
||||
private static final int ACTION_REQUEST_PASSCODE = 5;
|
||||
private static final int ACTION_CONFIRM_PASSCODE = 6;
|
||||
|
||||
private DbHandler mDbHandler;
|
||||
private CheckBoxPreference pCode;
|
||||
private Preference pAboutApp;
|
||||
private AppCompatDelegate mDelegate;
|
||||
|
@ -128,7 +127,6 @@ public class Preferences extends PreferenceActivity
|
|||
getDelegate().installViewFactory();
|
||||
getDelegate().onCreate(savedInstanceState);
|
||||
super.onCreate(savedInstanceState);
|
||||
mDbHandler = new DbHandler(getBaseContext());
|
||||
addPreferencesFromResource(R.xml.preferences);
|
||||
|
||||
ActionBar actionBar = getSupportActionBar();
|
||||
|
@ -307,7 +305,8 @@ public class Preferences extends PreferenceActivity
|
|||
String username = currentAccount.name.substring(0,
|
||||
currentAccount.name.lastIndexOf('@'));
|
||||
|
||||
String recommendSubject = String.format(getString(R.string.recommend_subject),
|
||||
String recommendSubject =
|
||||
String.format(getString(R.string.recommend_subject),
|
||||
appName);
|
||||
String recommendText = String.format(getString(R.string.recommend_text),
|
||||
appName, downloadUrl);
|
||||
|
@ -334,7 +333,8 @@ public class Preferences extends PreferenceActivity
|
|||
@Override
|
||||
public boolean onPreferenceClick(Preference preference) {
|
||||
String feedbackMail =(String) getText(R.string.mail_feedback);
|
||||
String feedback =(String) getText(R.string.prefs_feedback) + " - android v" + appVersion;
|
||||
String feedback =(String) getText(R.string.prefs_feedback) +
|
||||
" - android v" + appVersion;
|
||||
Intent intent = new Intent(Intent.ACTION_SENDTO);
|
||||
intent.setType("text/plain");
|
||||
intent.putExtra(Intent.EXTRA_SUBJECT, feedback);
|
||||
|
@ -453,7 +453,8 @@ public class Preferences extends PreferenceActivity
|
|||
/* About App */
|
||||
pAboutApp = (Preference) findPreference("about_app");
|
||||
if (pAboutApp != null) {
|
||||
pAboutApp.setTitle(String.format(getString(R.string.about_android), getString(R.string.app_name)));
|
||||
pAboutApp.setTitle(String.format(getString(R.string.about_android),
|
||||
getString(R.string.app_name)));
|
||||
pAboutApp.setSummary(String.format(getString(R.string.about_version), appVersion));
|
||||
}
|
||||
|
||||
|
@ -692,8 +693,6 @@ public class Preferences extends PreferenceActivity
|
|||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
mDbHandler.close();
|
||||
|
||||
if (mDownloadServiceConnection != null) {
|
||||
unbindService(mDownloadServiceConnection);
|
||||
mDownloadServiceConnection = null;
|
||||
|
@ -912,7 +911,8 @@ public class Preferences extends PreferenceActivity
|
|||
if (component.equals(new ComponentName(Preferences.this, FileDownloader.class))) {
|
||||
mDownloaderBinder = (FileDownloader.FileDownloaderBinder) service;
|
||||
|
||||
} else if (component.equals(new ComponentName(Preferences.this, FileUploader.class))) {
|
||||
} else if (component.equals(new ComponentName(Preferences.this,
|
||||
FileUploader.class))) {
|
||||
Log_OC.d(TAG, "Upload service connected");
|
||||
mUploaderBinder = (FileUploader.FileUploaderBinder) service;
|
||||
} else {
|
||||
|
@ -926,7 +926,8 @@ public class Preferences extends PreferenceActivity
|
|||
if (component.equals(new ComponentName(Preferences.this, FileDownloader.class))) {
|
||||
Log_OC.d(TAG, "Download service suddenly disconnected");
|
||||
mDownloaderBinder = null;
|
||||
} else if (component.equals(new ComponentName(Preferences.this, FileUploader.class))) {
|
||||
} else if (component.equals(new ComponentName(Preferences.this,
|
||||
FileUploader.class))) {
|
||||
Log_OC.d(TAG, "Upload service suddenly disconnected");
|
||||
mUploaderBinder = null;
|
||||
}
|
||||
|
|
|
@ -363,8 +363,8 @@ public class UploadFilesActivity extends FileActivity implements
|
|||
/**
|
||||
* Updates the activity UI after the check of space is done.
|
||||
*
|
||||
* If there is not space enough. shows a new dialog to query the user if wants to move the files instead
|
||||
* of copy them.
|
||||
* If there is not space enough. shows a new dialog to query the user if wants to move the
|
||||
* files instead of copy them.
|
||||
*
|
||||
* @param result 'True' when there is space enough to copy all the selected files.
|
||||
*/
|
||||
|
@ -398,7 +398,8 @@ public class UploadFilesActivity extends FileActivity implements
|
|||
// to the ownCloud folder instead of copying
|
||||
String[] args = {getString(R.string.app_name)};
|
||||
ConfirmationDialogFragment dialog = ConfirmationDialogFragment.newInstance(
|
||||
R.string.upload_query_move_foreign_files, args, R.string.common_yes, -1, R.string.common_no
|
||||
R.string.upload_query_move_foreign_files, args, R.string.common_yes, -1,
|
||||
R.string.common_no
|
||||
);
|
||||
dialog.setOnConfirmationListener(UploadFilesActivity.this);
|
||||
dialog.show(getSupportFragmentManager(), QUERY_TO_MOVE_DIALOG_TAG);
|
||||
|
|
361
src/com/owncloud/android/ui/activity/UploadListActivity.java
Executable file
|
@ -0,0 +1,361 @@
|
|||
/**
|
||||
* ownCloud Android client application
|
||||
*
|
||||
* @author LukeOwncloud
|
||||
* @author David A. Velasco
|
||||
* @author masensio
|
||||
* Copyright (C) 2016 ownCloud Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package com.owncloud.android.ui.activity;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.accounts.AccountManager;
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.ServiceConnection;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
import android.support.v4.app.FragmentTransaction;
|
||||
import android.support.v4.view.GravityCompat;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.owncloud.android.R;
|
||||
import com.owncloud.android.authentication.AccountUtils;
|
||||
import com.owncloud.android.datamodel.OCFile;
|
||||
import com.owncloud.android.datamodel.UploadsStorageManager;
|
||||
import com.owncloud.android.db.OCUpload;
|
||||
import com.owncloud.android.db.UploadResult;
|
||||
import com.owncloud.android.files.services.FileUploader;
|
||||
import com.owncloud.android.files.services.FileUploader.FileUploaderBinder;
|
||||
import com.owncloud.android.lib.common.operations.RemoteOperation;
|
||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
|
||||
import com.owncloud.android.lib.common.utils.Log_OC;
|
||||
import com.owncloud.android.operations.CheckCurrentCredentialsOperation;
|
||||
import com.owncloud.android.ui.fragment.UploadListFragment;
|
||||
import com.owncloud.android.utils.MimetypeIconUtil;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* Activity listing pending, active, and completed uploads. User can delete
|
||||
* completed uploads from view. Content of this list of coming from
|
||||
* {@link UploadsStorageManager}.
|
||||
*
|
||||
*/
|
||||
public class UploadListActivity extends FileActivity implements UploadListFragment.ContainerActivity {
|
||||
|
||||
private static final String TAG = UploadListActivity.class.getSimpleName();
|
||||
|
||||
private static final String TAG_UPLOAD_LIST_FRAGMENT = "UPLOAD_LIST_FRAGMENT";
|
||||
|
||||
private UploadMessagesReceiver mUploadMessagesReceiver;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setContentView(R.layout.upload_list_layout);
|
||||
|
||||
// this activity has no file really bound, it's for mulitple accounts at the same time; should no inherit
|
||||
// from FileActivity; moreover, some behaviours inherited from FileActivity should be delegated to Fragments;
|
||||
// but that's other story
|
||||
setFile(null);
|
||||
|
||||
// Navigation Drawer
|
||||
initDrawer();
|
||||
|
||||
// Add fragment with a transaction for setting a tag
|
||||
if(savedInstanceState == null) {
|
||||
createUploadListFragment();
|
||||
} // else, the Fragment Manager makes the job on configuration changes
|
||||
|
||||
// enable ActionBar app icon to behave as action to toggle nav drawer
|
||||
getSupportActionBar().setHomeButtonEnabled(true);
|
||||
mDrawerToggle.setDrawerIndicatorEnabled(true);
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
getSupportActionBar().setTitle(R.string.uploads_view_title);
|
||||
|
||||
}
|
||||
|
||||
private void createUploadListFragment(){
|
||||
UploadListFragment uploadList = new UploadListFragment();
|
||||
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
|
||||
transaction.add(R.id.upload_list_fragment, uploadList, TAG_UPLOAD_LIST_FRAGMENT);
|
||||
transaction.commit();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
Log_OC.v(TAG, "onResume() start");
|
||||
super.onResume();
|
||||
|
||||
// Listen for upload messages
|
||||
mUploadMessagesReceiver = new UploadMessagesReceiver();
|
||||
IntentFilter uploadIntentFilter = new IntentFilter();
|
||||
uploadIntentFilter.addAction(FileUploader.getUploadsAddedMessage());
|
||||
uploadIntentFilter.addAction(FileUploader.getUploadStartMessage());
|
||||
uploadIntentFilter.addAction(FileUploader.getUploadFinishMessage());
|
||||
registerReceiver(mUploadMessagesReceiver, uploadIntentFilter);
|
||||
|
||||
Log_OC.v(TAG, "onResume() end");
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
Log_OC.v(TAG, "onPause() start");
|
||||
if (mUploadMessagesReceiver != null) {
|
||||
unregisterReceiver(mUploadMessagesReceiver);
|
||||
mUploadMessagesReceiver = null;
|
||||
}
|
||||
super.onPause();
|
||||
Log_OC.v(TAG, "onPause() end");
|
||||
}
|
||||
|
||||
// ////////////////////////////////////////
|
||||
// UploadListFragment.ContainerActivity
|
||||
// ////////////////////////////////////////
|
||||
@Override
|
||||
public boolean onUploadItemClick(OCUpload file) {
|
||||
/// TODO is this path still active?
|
||||
File f = new File(file.getLocalPath());
|
||||
if(!f.exists()) {
|
||||
Toast.makeText(this, "Cannot open. Local file does not exist.",
|
||||
Toast.LENGTH_SHORT).show();
|
||||
} else {
|
||||
openFileWithDefault(file.getLocalPath());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Open file with app associates with its MIME type. If MIME type unknown, show list with all apps.
|
||||
*/
|
||||
private void openFileWithDefault(String localPath) {
|
||||
Intent myIntent = new Intent(android.content.Intent.ACTION_VIEW);
|
||||
File file = new File(localPath);
|
||||
String mimetype = MimetypeIconUtil.getBestMimeTypeByFilename(localPath);
|
||||
if ("application/octet-stream".equals(mimetype)) {
|
||||
mimetype = "*/*";
|
||||
}
|
||||
myIntent.setDataAndType(Uri.fromFile(file), mimetype);
|
||||
try {
|
||||
startActivity(myIntent);
|
||||
} catch (ActivityNotFoundException e) {
|
||||
Toast.makeText(this, "Found no app to open this file.", Toast.LENGTH_LONG).show();
|
||||
Log_OC.i(TAG, "Could not find app for sending log history.");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as openFileWithDefault() but user cannot save default app.
|
||||
* @param ocFile
|
||||
*/
|
||||
private void openFileWithDefaultNoDefault(OCFile ocFile) {
|
||||
getFileOperationsHelper().openFile(ocFile);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
boolean retval = true;
|
||||
UploadsStorageManager storageManager = null;
|
||||
UploadListFragment uploadListFragment =
|
||||
(UploadListFragment) getSupportFragmentManager().findFragmentByTag(TAG_UPLOAD_LIST_FRAGMENT);
|
||||
switch (item.getItemId()) {
|
||||
case android.R.id.home:
|
||||
if (mDrawerLayout.isDrawerOpen(GravityCompat.START)) {
|
||||
mDrawerLayout.closeDrawer(GravityCompat.START);
|
||||
} else {
|
||||
mDrawerLayout.openDrawer(GravityCompat.START);
|
||||
}
|
||||
break;
|
||||
case R.id.action_retry_uploads:
|
||||
FileUploader.UploadRequester requester = new FileUploader.UploadRequester();
|
||||
requester.retryFailedUploads(this, null, null);
|
||||
break;
|
||||
|
||||
case R.id.action_clear_failed_uploads:
|
||||
storageManager = new UploadsStorageManager(getContentResolver());
|
||||
storageManager.clearFailedUploads();
|
||||
uploadListFragment.updateUploads();
|
||||
break;
|
||||
|
||||
case R.id.action_clear_successfull_uploads:
|
||||
storageManager = new UploadsStorageManager(getContentResolver());
|
||||
storageManager.clearSuccessfulUploads();
|
||||
uploadListFragment.updateUploads();
|
||||
break;
|
||||
|
||||
case R.id.action_clear_finished_uploads:
|
||||
storageManager = new UploadsStorageManager(getContentResolver());
|
||||
storageManager.clearAllFinishedUploads();
|
||||
uploadListFragment.updateUploads();
|
||||
break;
|
||||
|
||||
default:
|
||||
retval = super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
MenuInflater inflater = getMenuInflater();
|
||||
inflater.inflate(R.menu.upload_list_menu, menu);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
if (requestCode == FileActivity.REQUEST_CODE__UPDATE_CREDENTIALS && resultCode == RESULT_OK) {
|
||||
// Retry uploads of the updated account
|
||||
Account account = AccountUtils.getOwnCloudAccountByName(
|
||||
this,
|
||||
data.getStringExtra(AccountManager.KEY_ACCOUNT_NAME)
|
||||
);
|
||||
FileUploader.UploadRequester requester = new FileUploader.UploadRequester();
|
||||
requester.retryFailedUploads(
|
||||
this,
|
||||
account,
|
||||
UploadResult.CREDENTIAL_ERROR
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param operation Operation performed.
|
||||
* @param result Result of the removal.
|
||||
*/
|
||||
@Override
|
||||
public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationResult result) {
|
||||
if (operation instanceof CheckCurrentCredentialsOperation) {
|
||||
// Do not call super in this case; more refactoring needed around onRemoteOeprationFinish :'(
|
||||
getFileOperationsHelper().setOpIdWaitingFor(Long.MAX_VALUE);
|
||||
dismissLoadingDialog();
|
||||
Account account = (Account) result.getData().get(0);
|
||||
if (!result.isSuccess()) {
|
||||
requestCredentialsUpdate(this, account);
|
||||
|
||||
} else {
|
||||
// already updated -> just retry!
|
||||
FileUploader.UploadRequester requester = new FileUploader.UploadRequester();
|
||||
requester.retryFailedUploads(this, account, UploadResult.CREDENTIAL_ERROR);
|
||||
}
|
||||
|
||||
} else {
|
||||
super.onRemoteOperationFinish(operation, result);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected ServiceConnection newTransferenceServiceConnection() {
|
||||
return new UploadListServiceConnection();
|
||||
}
|
||||
|
||||
/** Defines callbacks for service binding, passed to bindService() */
|
||||
private class UploadListServiceConnection implements ServiceConnection {
|
||||
|
||||
@Override
|
||||
public void onServiceConnected(ComponentName component, IBinder service) {
|
||||
if (service instanceof FileUploaderBinder) {
|
||||
if(mUploaderBinder == null)
|
||||
{
|
||||
mUploaderBinder = (FileUploaderBinder) service;
|
||||
Log_OC.d(TAG, "UploadListActivity connected to Upload service. component: " +
|
||||
component + " service: "
|
||||
+ service);
|
||||
// Say to UploadListFragment that the Binder is READY in the Activity
|
||||
UploadListFragment uploadListFragment =
|
||||
(UploadListFragment) getSupportFragmentManager().findFragmentByTag(TAG_UPLOAD_LIST_FRAGMENT);
|
||||
if (uploadListFragment != null) {
|
||||
uploadListFragment.binderReady();
|
||||
}
|
||||
} else {
|
||||
Log_OC.d(TAG, "mUploaderBinder already set. mUploaderBinder: " +
|
||||
mUploaderBinder + " service:" + service);
|
||||
}
|
||||
} else {
|
||||
Log_OC.d(TAG, "UploadListActivity not connected to Upload service. component: " +
|
||||
component + " service: " + service);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceDisconnected(ComponentName component) {
|
||||
if (component.equals(new ComponentName(UploadListActivity.this, FileUploader.class))) {
|
||||
Log_OC.d(TAG, "UploadListActivity suddenly disconnected from Upload service");
|
||||
mUploaderBinder = null;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Once the file upload has changed its status -> update uploads list view
|
||||
*/
|
||||
private class UploadMessagesReceiver extends BroadcastReceiver {
|
||||
/**
|
||||
* {@link BroadcastReceiver} to enable syncing feedback in UI
|
||||
*/
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
try {
|
||||
UploadListFragment uploadListFragment =
|
||||
(UploadListFragment) getSupportFragmentManager().findFragmentByTag(TAG_UPLOAD_LIST_FRAGMENT);
|
||||
|
||||
uploadListFragment.updateUploads();
|
||||
} finally {
|
||||
if (intent != null) {
|
||||
removeStickyBroadcast(intent);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getDefaultTitle() {
|
||||
return getString(R.string.uploads_view_title);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Called when the ownCloud {@link Account} associated to the Activity was just updated.
|
||||
*/
|
||||
@Override
|
||||
protected void onAccountSet(boolean stateWasRecovered) {
|
||||
super.onAccountSet(stateWasRecovered);
|
||||
updateActionBarTitleAndHomeButton(null);
|
||||
if (mAccountWasSet) {
|
||||
setUsernameInDrawer(findViewById(R.id.left_drawer), getAccount());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,51 +1,30 @@
|
|||
/**
|
||||
* ownCloud Android client application
|
||||
* ownCloud Android client application
|
||||
*
|
||||
* @author Bartek Przybylski
|
||||
* @author masensio
|
||||
* Copyright (C) 2012 Bartek Przybylski
|
||||
* Copyright (C) 2015 ownCloud Inc.
|
||||
* @author Bartek Przybylski
|
||||
* @author masensio
|
||||
* Copyright (C) 2012 Bartek Przybylski
|
||||
* Copyright (C) 2016 ownCloud Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.owncloud.android.ui.activity;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Stack;
|
||||
import java.util.Vector;
|
||||
|
||||
import com.owncloud.android.MainApp;
|
||||
import com.owncloud.android.R;
|
||||
import com.owncloud.android.authentication.AccountAuthenticator;
|
||||
import com.owncloud.android.datamodel.OCFile;
|
||||
import com.owncloud.android.files.services.FileUploader;
|
||||
import com.owncloud.android.lib.common.operations.RemoteOperation;
|
||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
|
||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;
|
||||
import com.owncloud.android.lib.common.utils.Log_OC;
|
||||
import com.owncloud.android.operations.RefreshFolderOperation;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.accounts.AccountManager;
|
||||
import android.accounts.AuthenticatorException;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.AlertDialog.Builder;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Dialog;
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.BroadcastReceiver;
|
||||
|
@ -62,6 +41,7 @@ import android.net.Uri;
|
|||
import android.os.Bundle;
|
||||
import android.os.Parcelable;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.provider.MediaStore;
|
||||
import android.provider.MediaStore.Audio;
|
||||
import android.provider.MediaStore.Images;
|
||||
import android.provider.MediaStore.Video;
|
||||
|
@ -69,6 +49,8 @@ import android.support.v4.app.Fragment;
|
|||
import android.support.v4.app.FragmentManager;
|
||||
import android.support.v4.app.FragmentTransaction;
|
||||
import android.support.v7.app.ActionBar;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import android.support.v7.app.AlertDialog.Builder;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
|
@ -81,7 +63,18 @@ import android.widget.ListView;
|
|||
import android.widget.ProgressBar;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.owncloud.android.MainApp;
|
||||
import com.owncloud.android.R;
|
||||
import com.owncloud.android.authentication.AccountAuthenticator;
|
||||
import com.owncloud.android.datamodel.OCFile;
|
||||
import com.owncloud.android.files.services.FileUploader;
|
||||
import com.owncloud.android.lib.common.operations.RemoteOperation;
|
||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
|
||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;
|
||||
import com.owncloud.android.lib.common.utils.Log_OC;
|
||||
import com.owncloud.android.operations.CreateFolderOperation;
|
||||
import com.owncloud.android.operations.RefreshFolderOperation;
|
||||
import com.owncloud.android.operations.UploadFileOperation;
|
||||
import com.owncloud.android.syncadapter.FileSyncAdapter;
|
||||
import com.owncloud.android.ui.adapter.UploaderAdapter;
|
||||
import com.owncloud.android.ui.dialog.CreateFolderDialogFragment;
|
||||
|
@ -90,6 +83,14 @@ import com.owncloud.android.utils.CopyTmpFileAsyncTask;
|
|||
import com.owncloud.android.utils.DisplayUtils;
|
||||
import com.owncloud.android.utils.ErrorMessageAdapter;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Stack;
|
||||
import java.util.Vector;
|
||||
|
||||
|
||||
/**
|
||||
* This can be used to upload things to an ownCloud instance.
|
||||
|
@ -114,13 +115,13 @@ public class Uploader extends FileActivity
|
|||
|
||||
private ArrayList<String> mRemoteCacheData;
|
||||
private int mNumCacheFile;
|
||||
|
||||
|
||||
private final static int DIALOG_NO_ACCOUNT = 0;
|
||||
private final static int DIALOG_WAITING = 1;
|
||||
private final static int DIALOG_NO_STREAM = 2;
|
||||
private final static int DIALOG_MULTIPLE_ACCOUNT = 3;
|
||||
|
||||
private final static int REQUEST_CODE_SETUP_ACCOUNT = 0;
|
||||
private final static int REQUEST_CODE__SETUP_ACCOUNT = REQUEST_CODE__LAST_SHARED + 1;
|
||||
|
||||
private final static String KEY_PARENTS = "PARENTS";
|
||||
private final static String KEY_FILE = "FILE";
|
||||
|
@ -200,7 +201,7 @@ public class Uploader extends FileActivity
|
|||
|
||||
@Override
|
||||
protected void onSaveInstanceState(Bundle outState) {
|
||||
Log_OC.d(TAG, "onSaveInstanceState() start");
|
||||
Log_OC.d(TAG, "onSaveInstanceState() start");
|
||||
super.onSaveInstanceState(outState);
|
||||
outState.putSerializable(KEY_PARENTS, mParents);
|
||||
//outState.putParcelable(KEY_ACCOUNT, mAccount);
|
||||
|
@ -245,7 +246,8 @@ public class Uploader extends FileActivity
|
|||
builder.setIcon(R.drawable.ic_warning);
|
||||
builder.setTitle(R.string.uploader_wrn_no_account_title);
|
||||
builder.setMessage(String.format(
|
||||
getString(R.string.uploader_wrn_no_account_text), getString(R.string.app_name)));
|
||||
getString(R.string.uploader_wrn_no_account_text),
|
||||
getString(R.string.app_name)));
|
||||
builder.setCancelable(false);
|
||||
builder.setPositiveButton(R.string.uploader_wrn_no_account_setup_btn_text, new OnClickListener() {
|
||||
@Override
|
||||
|
@ -253,13 +255,13 @@ public class Uploader extends FileActivity
|
|||
if (android.os.Build.VERSION.SDK_INT >
|
||||
android.os.Build.VERSION_CODES.ECLAIR_MR1) {
|
||||
// using string value since in API7 this
|
||||
// constant is not defined
|
||||
// in API7 < this constant is defined in
|
||||
// constatn is not defined
|
||||
// in API7 < this constatant is defined in
|
||||
// Settings.ADD_ACCOUNT_SETTINGS
|
||||
// and Settings.EXTRA_AUTHORITIES
|
||||
Intent intent = new Intent(android.provider.Settings.ACTION_ADD_ACCOUNT);
|
||||
intent.putExtra("authorities", new String[] { MainApp.getAuthTokenType() });
|
||||
startActivityForResult(intent, REQUEST_CODE_SETUP_ACCOUNT);
|
||||
intent.putExtra("authorities", new String[]{MainApp.getAuthTokenType()});
|
||||
startActivityForResult(intent, REQUEST_CODE__SETUP_ACCOUNT);
|
||||
} else {
|
||||
// since in API7 there is no direct call for
|
||||
// account setup, so we need to
|
||||
|
@ -267,7 +269,7 @@ public class Uploader extends FileActivity
|
|||
// desired results and setup
|
||||
// everything for ourself
|
||||
Intent intent = new Intent(getBaseContext(), AccountAuthenticator.class);
|
||||
startActivityForResult(intent, REQUEST_CODE_SETUP_ACCOUNT);
|
||||
startActivityForResult(intent, REQUEST_CODE__SETUP_ACCOUNT);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -328,7 +330,7 @@ public class Uploader extends FileActivity
|
|||
EditText mDirname;
|
||||
|
||||
public a(String path, EditText dirname) {
|
||||
mPath = path;
|
||||
mPath = path;
|
||||
mDirname = dirname;
|
||||
}
|
||||
|
||||
|
@ -379,24 +381,24 @@ public class Uploader extends FileActivity
|
|||
public void onClick(View v) {
|
||||
// click on button
|
||||
switch (v.getId()) {
|
||||
case R.id.uploader_choose_folder:
|
||||
mUploadPath = ""; // first element in mParents is root dir, represented by "";
|
||||
// init mUploadPath with "/" results in a "//" prefix
|
||||
for (String p : mParents)
|
||||
mUploadPath += p + OCFile.PATH_SEPARATOR;
|
||||
Log_OC.d(TAG, "Uploading file to dir " + mUploadPath);
|
||||
case R.id.uploader_choose_folder:
|
||||
mUploadPath = ""; // first element in mParents is root dir, represented by "";
|
||||
// init mUploadPath with "/" results in a "//" prefix
|
||||
for (String p : mParents)
|
||||
mUploadPath += p + OCFile.PATH_SEPARATOR;
|
||||
Log_OC.d(TAG, "Uploading file to dir " + mUploadPath);
|
||||
|
||||
uploadFiles();
|
||||
uploadFiles();
|
||||
|
||||
break;
|
||||
|
||||
case R.id.uploader_cancel:
|
||||
finish();
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
throw new IllegalArgumentException("Wrong element clicked");
|
||||
break;
|
||||
|
||||
case R.id.uploader_cancel:
|
||||
finish();
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
throw new IllegalArgumentException("Wrong element clicked");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -404,7 +406,7 @@ public class Uploader extends FileActivity
|
|||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
Log_OC.i(TAG, "result received. req: " + requestCode + " res: " + resultCode);
|
||||
if (requestCode == REQUEST_CODE_SETUP_ACCOUNT) {
|
||||
if (requestCode == REQUEST_CODE__SETUP_ACCOUNT) {
|
||||
dismissDialog(DIALOG_NO_ACCOUNT);
|
||||
if (resultCode == RESULT_CANCELED) {
|
||||
finish();
|
||||
|
@ -424,14 +426,13 @@ public class Uploader extends FileActivity
|
|||
|
||||
private void populateDirectoryList() {
|
||||
setContentView(R.layout.uploader_layout);
|
||||
|
||||
|
||||
ListView mListView = (ListView) findViewById(android.R.id.list);
|
||||
|
||||
String current_dir = mParents.peek();
|
||||
if(current_dir.equals("")){
|
||||
if (current_dir.equals("")) {
|
||||
getSupportActionBar().setTitle(getString(R.string.default_display_name_for_root_folder));
|
||||
}
|
||||
else{
|
||||
} else {
|
||||
getSupportActionBar().setTitle(current_dir);
|
||||
}
|
||||
boolean notRoot = (mParents.size() > 1);
|
||||
|
@ -453,7 +454,7 @@ public class Uploader extends FileActivity
|
|||
h.put("dirname", f);
|
||||
data.add(h);
|
||||
}
|
||||
|
||||
|
||||
UploaderAdapter sa = new UploaderAdapter(this,
|
||||
data,
|
||||
R.layout.uploader_list_item_layout,
|
||||
|
@ -464,10 +465,10 @@ public class Uploader extends FileActivity
|
|||
mListView.setAdapter(sa);
|
||||
Button btnChooseFolder = (Button) findViewById(R.id.uploader_choose_folder);
|
||||
btnChooseFolder.setOnClickListener(this);
|
||||
|
||||
|
||||
Button btnNewFolder = (Button) findViewById(R.id.uploader_cancel);
|
||||
btnNewFolder.setOnClickListener(this);
|
||||
|
||||
|
||||
mListView.setOnItemClickListener(this);
|
||||
}
|
||||
}
|
||||
|
@ -512,85 +513,81 @@ public class Uploader extends FileActivity
|
|||
return (mStreamsToUpload != null && mStreamsToUpload.get(0) != null);
|
||||
}
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
public void uploadFiles() {
|
||||
try {
|
||||
|
||||
// ArrayList for files with path in external storage
|
||||
ArrayList<String> local = new ArrayList<String>();
|
||||
ArrayList<String> remote = new ArrayList<String>();
|
||||
|
||||
// this checks the mimeType
|
||||
// this checks the mimeType
|
||||
for (Parcelable mStream : mStreamsToUpload) {
|
||||
|
||||
|
||||
Uri uri = (Uri) mStream;
|
||||
String data = null;
|
||||
String filePath = "";
|
||||
|
||||
if (uri != null) {
|
||||
if (uri.getScheme().equals("content")) {
|
||||
String mimeType = getContentResolver().getType(uri);
|
||||
String mimeType = getContentResolver().getType(uri);
|
||||
|
||||
if (mimeType.contains("image")) {
|
||||
String[] CONTENT_PROJECTION = { Images.Media.DATA, Images.Media.DISPLAY_NAME,
|
||||
Images.Media.MIME_TYPE, Images.Media.SIZE};
|
||||
Cursor c = getContentResolver().query(uri, CONTENT_PROJECTION, null, null, null);
|
||||
c.moveToFirst();
|
||||
int index = c.getColumnIndex(Images.Media.DATA);
|
||||
data = c.getString(index);
|
||||
local.add(data);
|
||||
remote.add(mUploadPath + c.getString(c.getColumnIndex(Images.Media.DISPLAY_NAME)));
|
||||
if (mimeType.contains("image")) {
|
||||
String[] CONTENT_PROJECTION = {Images.Media.DATA,
|
||||
Images.Media.DISPLAY_NAME, Images.Media.MIME_TYPE,
|
||||
Images.Media.SIZE};
|
||||
Cursor c = getContentResolver().query(uri, CONTENT_PROJECTION, null,
|
||||
null, null);
|
||||
c.moveToFirst();
|
||||
int index = c.getColumnIndex(Images.Media.DATA);
|
||||
data = c.getString(index);
|
||||
filePath = mUploadPath +
|
||||
c.getString(c.getColumnIndex(Images.Media.DISPLAY_NAME));
|
||||
|
||||
}
|
||||
else if (mimeType.contains("video")) {
|
||||
String[] CONTENT_PROJECTION = { Video.Media.DATA, Video.Media.DISPLAY_NAME,
|
||||
Video.Media.MIME_TYPE, Video.Media.SIZE,
|
||||
Video.Media.DATE_MODIFIED };
|
||||
Cursor c = getContentResolver().query(uri, CONTENT_PROJECTION, null, null, null);
|
||||
c.moveToFirst();
|
||||
int index = c.getColumnIndex(Video.Media.DATA);
|
||||
data = c.getString(index);
|
||||
local.add(data);
|
||||
remote.add(mUploadPath + c.getString(c.getColumnIndex(Video.Media.DISPLAY_NAME)));
|
||||
} else if (mimeType.contains("video")) {
|
||||
String[] CONTENT_PROJECTION = {Video.Media.DATA,
|
||||
Video.Media.DISPLAY_NAME, Video.Media.MIME_TYPE,
|
||||
Video.Media.SIZE, Video.Media.DATE_MODIFIED};
|
||||
Cursor c = getContentResolver().query(uri, CONTENT_PROJECTION, null,
|
||||
null, null);
|
||||
c.moveToFirst();
|
||||
int index = c.getColumnIndex(Video.Media.DATA);
|
||||
data = c.getString(index);
|
||||
filePath = mUploadPath +
|
||||
c.getString(c.getColumnIndex(Video.Media.DISPLAY_NAME));
|
||||
|
||||
}
|
||||
else if (mimeType.contains("audio")) {
|
||||
String[] CONTENT_PROJECTION = { Audio.Media.DATA, Audio.Media.DISPLAY_NAME,
|
||||
Audio.Media.MIME_TYPE, Audio.Media.SIZE };
|
||||
Cursor c = getContentResolver().query(uri, CONTENT_PROJECTION, null, null, null);
|
||||
c.moveToFirst();
|
||||
int index = c.getColumnIndex(Audio.Media.DATA);
|
||||
data = c.getString(index);
|
||||
local.add(data);
|
||||
remote.add(mUploadPath + c.getString(c.getColumnIndex(Audio.Media.DISPLAY_NAME)));
|
||||
} else if (mimeType.contains("audio")) {
|
||||
String[] CONTENT_PROJECTION = {Audio.Media.DATA,
|
||||
Audio.Media.DISPLAY_NAME, Audio.Media.MIME_TYPE,
|
||||
Audio.Media.SIZE};
|
||||
Cursor c = getContentResolver().query(uri, CONTENT_PROJECTION, null,
|
||||
null, null);
|
||||
c.moveToFirst();
|
||||
int index = c.getColumnIndex(Audio.Media.DATA);
|
||||
data = c.getString(index);
|
||||
filePath = mUploadPath +
|
||||
c.getString(c.getColumnIndex(Audio.Media.DISPLAY_NAME));
|
||||
|
||||
} else {
|
||||
Cursor cursor = getContentResolver().query(uri,
|
||||
new String[]{MediaStore.MediaColumns.DISPLAY_NAME},
|
||||
null, null, null);
|
||||
cursor.moveToFirst();
|
||||
int nameIndex = cursor.getColumnIndex(cursor.getColumnNames()[0]);
|
||||
if (nameIndex >= 0) {
|
||||
filePath = mUploadPath + cursor.getString(nameIndex);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
filePath = Uri.decode(uri.toString()).replace(uri.getScheme() + "://", "");
|
||||
// cut everything whats before mnt. It occured to me that sometimes apps send
|
||||
// their name into the URI
|
||||
if (filePath.contains("mnt")) {
|
||||
String splitedFilePath[] = filePath.split("/mnt");
|
||||
filePath = splitedFilePath[1];
|
||||
}
|
||||
final File file = new File(filePath);
|
||||
local.add(file.getAbsolutePath());
|
||||
remote.add(mUploadPath + file.getName());
|
||||
}
|
||||
} else if (uri.getScheme().equals("file")) {
|
||||
filePath = Uri.decode(uri.toString()).replace(uri.getScheme() +
|
||||
"://", "");
|
||||
if (filePath.contains("mnt")) {
|
||||
String splitedFilePath[] = filePath.split("/mnt");
|
||||
filePath = splitedFilePath[1];
|
||||
String splitedFilePath[] = filePath.split("/mnt");
|
||||
filePath = splitedFilePath[1];
|
||||
}
|
||||
final File file = new File(filePath);
|
||||
data = file.getAbsolutePath();
|
||||
filePath = mUploadPath + file.getName();
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
throw new SecurityException();
|
||||
}
|
||||
if (data == null) {
|
||||
//if (data == null) {
|
||||
mRemoteCacheData.add(filePath);
|
||||
CopyTmpFileAsyncTask copyTask = new CopyTmpFileAsyncTask(this);
|
||||
Object[] params = {uri, filePath, mRemoteCacheData.size() - 1,
|
||||
|
@ -598,20 +595,14 @@ public class Uploader extends FileActivity
|
|||
mNumCacheFile++;
|
||||
showWaitingCopyDialog();
|
||||
copyTask.execute(params);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
//} else {
|
||||
// TODO request to FileUploader with data as source file, resulting in lazy temporary copy
|
||||
//}
|
||||
} else {
|
||||
throw new SecurityException();
|
||||
}
|
||||
|
||||
Intent intent = new Intent(getApplicationContext(), FileUploader.class);
|
||||
intent.putExtra(FileUploader.KEY_UPLOAD_TYPE, FileUploader.UPLOAD_MULTIPLE_FILES);
|
||||
intent.putExtra(FileUploader.KEY_LOCAL_FILE, local.toArray(new String[local.size()]));
|
||||
intent.putExtra(FileUploader.KEY_REMOTE_FILE,
|
||||
remote.toArray(new String[remote.size()]));
|
||||
intent.putExtra(FileUploader.KEY_ACCOUNT, getAccount());
|
||||
startService(intent);
|
||||
|
||||
//Save the path to shared preferences
|
||||
SharedPreferences.Editor appPrefs = PreferenceManager
|
||||
.getDefaultSharedPreferences(getApplicationContext()).edit();
|
||||
|
@ -620,31 +611,31 @@ public class Uploader extends FileActivity
|
|||
|
||||
finish();
|
||||
}
|
||||
|
||||
|
||||
} catch (SecurityException e) {
|
||||
String message = String.format(getString(R.string.uploader_error_forbidden_content),
|
||||
getString(R.string.app_name));
|
||||
Toast.makeText(this, message, Toast.LENGTH_LONG).show();
|
||||
Toast.makeText(this, message, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationResult result) {
|
||||
super.onRemoteOperationFinish(operation, result);
|
||||
|
||||
|
||||
|
||||
|
||||
if (operation instanceof CreateFolderOperation) {
|
||||
onCreateFolderOperationFinish((CreateFolderOperation)operation, result);
|
||||
onCreateFolderOperationFinish((CreateFolderOperation) operation, result);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Updates the view associated to the activity after the finish of an operation
|
||||
* trying create a new folder
|
||||
*
|
||||
* @param operation Creation operation performed.
|
||||
* @param result Result of the creation.
|
||||
*
|
||||
* @param operation Creation operation performed.
|
||||
* @param result Result of the creation.
|
||||
*/
|
||||
private void onCreateFolderOperationFinish(CreateFolderOperation operation,
|
||||
RemoteOperationResult result) {
|
||||
|
@ -652,44 +643,44 @@ public class Uploader extends FileActivity
|
|||
populateDirectoryList();
|
||||
} else {
|
||||
try {
|
||||
Toast msg = Toast.makeText(this,
|
||||
ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()),
|
||||
Toast.LENGTH_LONG);
|
||||
Toast msg = Toast.makeText(this,
|
||||
ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()),
|
||||
Toast.LENGTH_LONG);
|
||||
msg.show();
|
||||
|
||||
} catch (NotFoundException e) {
|
||||
Log_OC.e(TAG, "Error while trying to show fail message " , e);
|
||||
Log_OC.e(TAG, "Error while trying to show fail message ", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Loads the target folder initialize shown to the user.
|
||||
*
|
||||
* The target account has to be chosen before this method is called.
|
||||
* Loads the target folder initialize shown to the user.
|
||||
* <p/>
|
||||
* The target account has to be chosen before this method is called.
|
||||
*/
|
||||
private void initTargetFolder() {
|
||||
if (getStorageManager() == null) {
|
||||
throw new IllegalStateException("Do not call this method before " +
|
||||
"initializing mStorageManager");
|
||||
}
|
||||
|
||||
|
||||
SharedPreferences appPreferences = PreferenceManager
|
||||
.getDefaultSharedPreferences(getApplicationContext());
|
||||
|
||||
String last_path = appPreferences.getString("last_upload_path", "");
|
||||
// "/" equals root-directory
|
||||
if(last_path.equals("/")) {
|
||||
if (last_path.equals("/")) {
|
||||
mParents.add("");
|
||||
} else{
|
||||
} else {
|
||||
String[] dir_names = last_path.split("/");
|
||||
mParents.clear();
|
||||
for (String dir : dir_names)
|
||||
mParents.add(dir);
|
||||
}
|
||||
//Make sure that path still exists, if it doesn't pop the stack and try the previous path
|
||||
while(!getStorageManager().fileExists(generatePath(mParents)) && mParents.size() > 1){
|
||||
while (!getStorageManager().fileExists(generatePath(mParents)) && mParents.size() > 1) {
|
||||
mParents.pop();
|
||||
}
|
||||
}
|
||||
|
@ -702,7 +693,7 @@ public class Uploader extends FileActivity
|
|||
menu.findItem(R.id.action_sync_account).setVisible(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
boolean retval = true;
|
||||
|
@ -714,7 +705,7 @@ public class Uploader extends FileActivity
|
|||
CreateFolderDialogFragment.CREATE_FOLDER_FRAGMENT);
|
||||
break;
|
||||
case android.R.id.home:
|
||||
if((mParents.size() > 1)) {
|
||||
if ((mParents.size() > 1)) {
|
||||
onBackPressed();
|
||||
}
|
||||
break;
|
||||
|
@ -824,21 +815,26 @@ public class Uploader extends FileActivity
|
|||
}
|
||||
/**
|
||||
* Process the result of CopyTmpFileAsyncTask
|
||||
*
|
||||
* @param result
|
||||
* @param index
|
||||
*/
|
||||
@Override
|
||||
public void onTmpFileCopied(String result, int index) {
|
||||
if (mNumCacheFile -- == 0) {
|
||||
if (mNumCacheFile-- == 0) {
|
||||
dismissWaitingCopyDialog();
|
||||
}
|
||||
if (result != null) {
|
||||
Intent intent = new Intent(getApplicationContext(), FileUploader.class);
|
||||
intent.putExtra(FileUploader.KEY_UPLOAD_TYPE, FileUploader.UPLOAD_SINGLE_FILE);
|
||||
intent.putExtra(FileUploader.KEY_LOCAL_FILE, result);
|
||||
intent.putExtra(FileUploader.KEY_REMOTE_FILE, mRemoteCacheData.get(index));
|
||||
intent.putExtra(FileUploader.KEY_ACCOUNT, getAccount());
|
||||
startService(intent);
|
||||
FileUploader.UploadRequester requester = new FileUploader.UploadRequester();
|
||||
requester.uploadNewFile(
|
||||
this, getAccount(),
|
||||
result,
|
||||
mRemoteCacheData.get(index),
|
||||
FileUploader.LOCAL_BEHAVIOUR_FORGET,
|
||||
null, // MIME type will be detected from file name
|
||||
false, // do not create parent folder if not existent
|
||||
UploadFileOperation.CREATED_BY_USER
|
||||
);
|
||||
|
||||
} else {
|
||||
String message = String.format(getString(R.string.uploader_error_forbidden_content),
|
||||
|
@ -865,7 +861,7 @@ public class Uploader extends FileActivity
|
|||
/**
|
||||
* Dismiss waiting for copy dialog
|
||||
*/
|
||||
public void dismissWaitingCopyDialog(){
|
||||
public void dismissWaitingCopyDialog() {
|
||||
Fragment frag = getSupportFragmentManager().findFragmentByTag(DIALOG_WAIT_COPY_FILE);
|
||||
if (frag != null) {
|
||||
LoadingDialog loading = (LoadingDialog) frag;
|
||||
|
|
720
src/com/owncloud/android/ui/adapter/ExpandableUploadListAdapter.java
Executable file
|
@ -0,0 +1,720 @@
|
|||
/**
|
||||
* ownCloud Android client application
|
||||
*
|
||||
* @author LukeOwncloud
|
||||
* @author masensio
|
||||
* Copyright (C) 2016 ownCloud Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.owncloud.android.ui.adapter;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.DataSetObserver;
|
||||
import android.graphics.Bitmap;
|
||||
import android.text.format.DateUtils;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.BaseExpandableListAdapter;
|
||||
import android.widget.ExpandableListView;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.owncloud.android.R;
|
||||
import com.owncloud.android.datamodel.OCFile;
|
||||
import com.owncloud.android.datamodel.ThumbnailsCacheManager;
|
||||
import com.owncloud.android.datamodel.UploadsStorageManager;
|
||||
import com.owncloud.android.datamodel.UploadsStorageManager.UploadStatus;
|
||||
import com.owncloud.android.db.OCUpload;
|
||||
import com.owncloud.android.db.UploadResult;
|
||||
import com.owncloud.android.files.services.FileUploader;
|
||||
import com.owncloud.android.lib.common.network.OnDatatransferProgressListener;
|
||||
import com.owncloud.android.lib.common.utils.Log_OC;
|
||||
import com.owncloud.android.ui.activity.FileActivity;
|
||||
import com.owncloud.android.utils.DisplayUtils;
|
||||
import com.owncloud.android.utils.MimetypeIconUtil;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.Observable;
|
||||
import java.util.Observer;
|
||||
|
||||
/**
|
||||
* This Adapter populates a ListView with following types of uploads: pending,
|
||||
* active, completed. Filtering possible.
|
||||
*
|
||||
*/
|
||||
public class ExpandableUploadListAdapter extends BaseExpandableListAdapter implements Observer {
|
||||
|
||||
private static final String TAG = ExpandableUploadListAdapter.class.getSimpleName();
|
||||
private FileActivity mParentActivity;
|
||||
|
||||
private UploadsStorageManager mUploadsStorageManager;
|
||||
|
||||
public ProgressListener mProgressListener;
|
||||
|
||||
interface Refresh {
|
||||
public void refresh();
|
||||
}
|
||||
|
||||
abstract class UploadGroup implements Refresh {
|
||||
OCUpload[] items;
|
||||
String name;
|
||||
|
||||
public UploadGroup(String groupName) {
|
||||
this.name = groupName;
|
||||
items = new OCUpload[0];
|
||||
}
|
||||
|
||||
public String getGroupName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public Comparator<OCUpload> comparator = new Comparator<OCUpload>() {
|
||||
|
||||
@Override
|
||||
public int compare(OCUpload upload1, OCUpload upload2) {
|
||||
if (upload1.getUploadStatus().equals(UploadStatus.UPLOAD_IN_PROGRESS)) {
|
||||
FileUploader.FileUploaderBinder binder = mParentActivity.getFileUploaderBinder();
|
||||
if (binder != null) {
|
||||
if (binder.isUploadingNow(upload1)) {
|
||||
return -1;
|
||||
} else if (binder.isUploadingNow(upload2)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (upload1.getUploadEndTimestamp() == 0) {
|
||||
return compareUploadId(upload1, upload2);
|
||||
} else {
|
||||
return compareUpdateTime(upload1, upload2);
|
||||
}
|
||||
}
|
||||
|
||||
private int compareUploadId(OCUpload upload1, OCUpload upload2) {
|
||||
return Long.valueOf(upload1.getUploadId()).compareTo(upload2.getUploadId());
|
||||
}
|
||||
|
||||
private int compareUpdateTime(OCUpload upload1, OCUpload upload2) {
|
||||
return Long.valueOf(upload2.getUploadEndTimestamp()).compareTo(upload1.getUploadEndTimestamp());
|
||||
}
|
||||
};
|
||||
|
||||
abstract public int getGroupIcon();
|
||||
}
|
||||
|
||||
private UploadGroup[] mUploadGroups = null;
|
||||
|
||||
public ExpandableUploadListAdapter(FileActivity parentActivity) {
|
||||
Log_OC.d(TAG, "ExpandableUploadListAdapter");
|
||||
mParentActivity = parentActivity;
|
||||
mUploadsStorageManager = new UploadsStorageManager(mParentActivity.getContentResolver());
|
||||
mUploadGroups = new UploadGroup[3];
|
||||
mUploadGroups[0] = new UploadGroup(mParentActivity.getString(R.string.uploads_view_group_current_uploads)) {
|
||||
@Override
|
||||
public void refresh() {
|
||||
items = mUploadsStorageManager.getCurrentAndPendingUploads();
|
||||
Arrays.sort(items, comparator);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getGroupIcon() {
|
||||
return R.drawable.upload_in_progress;
|
||||
}
|
||||
};
|
||||
mUploadGroups[1] = new UploadGroup(mParentActivity.getString(R.string.uploads_view_group_failed_uploads)) {
|
||||
@Override
|
||||
public void refresh() {
|
||||
items = mUploadsStorageManager.getFailedUploads();
|
||||
Arrays.sort(items, comparator);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getGroupIcon() {
|
||||
return R.drawable.upload_failed;
|
||||
}
|
||||
|
||||
};
|
||||
mUploadGroups[2] = new UploadGroup(mParentActivity.getString(R.string.uploads_view_group_finished_uploads)) {
|
||||
@Override
|
||||
public void refresh() {
|
||||
items = mUploadsStorageManager.getFinishedUploads();
|
||||
Arrays.sort(items, comparator);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getGroupIcon() {
|
||||
return R.drawable.upload_finished;
|
||||
}
|
||||
|
||||
};
|
||||
loadUploadItemsFromDb();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void registerDataSetObserver(DataSetObserver observer) {
|
||||
super.registerDataSetObserver(observer);
|
||||
mUploadsStorageManager.addObserver(this);
|
||||
Log_OC.d(TAG, "registerDataSetObserver");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterDataSetObserver(DataSetObserver observer) {
|
||||
super.unregisterDataSetObserver(observer);
|
||||
mUploadsStorageManager.deleteObserver(this);
|
||||
Log_OC.d(TAG, "unregisterDataSetObserver");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areAllItemsEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
private View getView(OCUpload[] uploadsItems, int position, View convertView, ViewGroup parent) {
|
||||
View view = convertView;
|
||||
if (view == null) {
|
||||
LayoutInflater inflator =
|
||||
(LayoutInflater) mParentActivity.getSystemService(
|
||||
Context.LAYOUT_INFLATER_SERVICE
|
||||
);
|
||||
view = inflator.inflate(R.layout.upload_list_item, parent, false);
|
||||
}
|
||||
|
||||
if (uploadsItems != null && uploadsItems.length > position) {
|
||||
final OCUpload upload = uploadsItems[position];
|
||||
|
||||
// local file name
|
||||
TextView fileTextView = (TextView) view.findViewById(R.id.upload_name);
|
||||
File remoteFile = new File(upload.getRemotePath());
|
||||
String fileName = remoteFile.getName();
|
||||
if (fileName.length() == 0) {
|
||||
fileName = File.separator;
|
||||
}
|
||||
fileTextView.setText(fileName);
|
||||
|
||||
// remote path to parent folder
|
||||
TextView pathTextView = (TextView) view.findViewById(R.id.upload_remote_path);
|
||||
String remoteParentPath = upload.getRemotePath();
|
||||
remoteParentPath = new File(remoteParentPath).getParent();
|
||||
pathTextView.setText(mParentActivity.getString(R.string.app_name) + remoteParentPath);
|
||||
|
||||
// file size
|
||||
TextView fileSizeTextView = (TextView) view.findViewById(R.id.upload_file_size);
|
||||
fileSizeTextView.setText(DisplayUtils.bytesToHumanReadable(upload.getFileSize()) + ", ");
|
||||
|
||||
//* upload date
|
||||
TextView uploadDateTextView = (TextView) view.findViewById(R.id.upload_date);
|
||||
long updateTime = upload.getUploadEndTimestamp();
|
||||
CharSequence dateString = DisplayUtils.getRelativeDateTimeString(
|
||||
mParentActivity,
|
||||
updateTime,
|
||||
DateUtils.SECOND_IN_MILLIS,
|
||||
DateUtils.WEEK_IN_MILLIS,
|
||||
0
|
||||
);
|
||||
uploadDateTextView.setText(dateString);
|
||||
|
||||
TextView accountNameTextView = (TextView) view.findViewById(R.id.upload_account);
|
||||
accountNameTextView.setText(upload.getAccountName());
|
||||
|
||||
TextView statusTextView = (TextView) view.findViewById(R.id.upload_status);
|
||||
|
||||
ProgressBar progressBar = (ProgressBar) view.findViewById(R.id.upload_progress_bar);
|
||||
|
||||
/// Reset fields visibility
|
||||
uploadDateTextView.setVisibility(View.VISIBLE);
|
||||
pathTextView.setVisibility(View.VISIBLE);
|
||||
fileSizeTextView.setVisibility(View.VISIBLE);
|
||||
accountNameTextView.setVisibility(View.VISIBLE);
|
||||
statusTextView.setVisibility(View.VISIBLE);
|
||||
progressBar.setVisibility(View.GONE);
|
||||
|
||||
/// Update information depending of upload details
|
||||
String status = getStatusText(upload);
|
||||
switch (upload.getUploadStatus()) {
|
||||
case UPLOAD_IN_PROGRESS:
|
||||
progressBar.setProgress(0);
|
||||
progressBar.setVisibility(View.VISIBLE);
|
||||
|
||||
FileUploader.FileUploaderBinder binder = mParentActivity.getFileUploaderBinder();
|
||||
if (binder != null) {
|
||||
if (binder.isUploadingNow(upload)) {
|
||||
/// really uploading, so...
|
||||
/// ... unbind the old progress bar, if any; ...
|
||||
if (mProgressListener != null) {
|
||||
binder.removeDatatransferProgressListener(
|
||||
mProgressListener,
|
||||
mProgressListener.getUpload() // the one that was added
|
||||
);
|
||||
}
|
||||
/// ... then, bind the current progress bar to listen for updates
|
||||
mProgressListener = new ProgressListener(upload, progressBar);
|
||||
binder.addDatatransferProgressListener(
|
||||
mProgressListener,
|
||||
upload
|
||||
);
|
||||
|
||||
} else {
|
||||
/// not really uploading; stop listening progress if view is reused!
|
||||
if (convertView != null &&
|
||||
mProgressListener != null &&
|
||||
mProgressListener.isWrapping(progressBar)) {
|
||||
binder.removeDatatransferProgressListener(
|
||||
mProgressListener,
|
||||
mProgressListener.getUpload() // the one that was added
|
||||
);
|
||||
mProgressListener = null;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Log_OC.w(
|
||||
TAG,
|
||||
"FileUploaderBinder not ready yet for upload " + upload.getRemotePath()
|
||||
);
|
||||
}
|
||||
uploadDateTextView.setVisibility(View.GONE);
|
||||
pathTextView.setVisibility(View.GONE);
|
||||
fileSizeTextView.setVisibility(View.GONE);
|
||||
progressBar.invalidate();
|
||||
break;
|
||||
|
||||
case UPLOAD_FAILED:
|
||||
uploadDateTextView.setVisibility(View.GONE);
|
||||
break;
|
||||
|
||||
case UPLOAD_SUCCEEDED:
|
||||
statusTextView.setVisibility(View.GONE);
|
||||
break;
|
||||
}
|
||||
statusTextView.setText(status);
|
||||
|
||||
/// bind listeners to perform actions
|
||||
ImageButton rightButton = (ImageButton) view.findViewById(R.id.upload_right_button);
|
||||
if (upload.getUploadStatus() == UploadStatus.UPLOAD_IN_PROGRESS) {
|
||||
//Cancel
|
||||
rightButton.setImageResource(R.drawable.ic_cancel);
|
||||
rightButton.setVisibility(View.VISIBLE);
|
||||
rightButton.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
FileUploader.FileUploaderBinder uploaderBinder = mParentActivity.getFileUploaderBinder();
|
||||
if (uploaderBinder != null) {
|
||||
uploaderBinder.cancel(upload);
|
||||
refreshView();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
} else if (upload.getUploadStatus() == UploadStatus.UPLOAD_FAILED) {
|
||||
//Delete
|
||||
rightButton.setImageResource(R.drawable.ic_action_delete);
|
||||
rightButton.setVisibility(View.VISIBLE);
|
||||
rightButton.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
mUploadsStorageManager.removeUpload(upload);
|
||||
refreshView();
|
||||
}
|
||||
});
|
||||
|
||||
} else { // UploadStatus.UPLOAD_SUCCESS
|
||||
rightButton.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
|
||||
// retry
|
||||
if (upload.getUploadStatus() == UploadStatus.UPLOAD_FAILED) {
|
||||
if (UploadResult.CREDENTIAL_ERROR.equals(upload.getLastResult())) {
|
||||
view.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
mParentActivity.getFileOperationsHelper().checkCurrentCredentials(
|
||||
upload.getAccount(mParentActivity)
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
} else {
|
||||
// not a credentials error
|
||||
view.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
File file = new File(upload.getLocalPath());
|
||||
if (file.exists()) {
|
||||
FileUploader.UploadRequester requester = new FileUploader.UploadRequester();
|
||||
requester.retry(mParentActivity, upload);
|
||||
refreshView();
|
||||
} else {
|
||||
final String message = String.format(
|
||||
mParentActivity.getString(R.string.local_file_not_found_toast)
|
||||
);
|
||||
Toast.makeText(mParentActivity, message, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
view.setOnClickListener(null);
|
||||
}
|
||||
|
||||
/// Set icon or thumbnail
|
||||
ImageView fileIcon = (ImageView) view.findViewById(R.id.thumbnail);
|
||||
fileIcon.setImageResource(R.drawable.file);
|
||||
|
||||
/** Cancellation needs do be checked and done before changing the drawable in fileIcon, or
|
||||
* {@link ThumbnailsCacheManager#cancelPotentialWork} will NEVER cancel any task.
|
||||
**/
|
||||
OCFile fakeFileToCheatThumbnailsCacheManagerInterface = new OCFile(upload.getRemotePath());
|
||||
fakeFileToCheatThumbnailsCacheManagerInterface.setStoragePath(upload.getLocalPath());
|
||||
fakeFileToCheatThumbnailsCacheManagerInterface.setMimetype(upload.getMimeType());
|
||||
|
||||
boolean allowedToCreateNewThumbnail = (ThumbnailsCacheManager.cancelPotentialWork(
|
||||
fakeFileToCheatThumbnailsCacheManagerInterface,
|
||||
fileIcon)
|
||||
);
|
||||
|
||||
// TODO this code is duplicated; refactor to a common place
|
||||
if ((fakeFileToCheatThumbnailsCacheManagerInterface.isImage()
|
||||
&& fakeFileToCheatThumbnailsCacheManagerInterface.getRemoteId() != null &&
|
||||
upload.getUploadStatus() == UploadStatus.UPLOAD_SUCCEEDED)) {
|
||||
// Thumbnail in Cache?
|
||||
Bitmap thumbnail = ThumbnailsCacheManager.getBitmapFromDiskCache(
|
||||
String.valueOf(fakeFileToCheatThumbnailsCacheManagerInterface.getRemoteId())
|
||||
);
|
||||
if (thumbnail != null && !fakeFileToCheatThumbnailsCacheManagerInterface.needsUpdateThumbnail()) {
|
||||
fileIcon.setImageBitmap(thumbnail);
|
||||
} else {
|
||||
// generate new Thumbnail
|
||||
if (allowedToCreateNewThumbnail) {
|
||||
final ThumbnailsCacheManager.ThumbnailGenerationTask task =
|
||||
new ThumbnailsCacheManager.ThumbnailGenerationTask(
|
||||
fileIcon, mParentActivity.getStorageManager(), mParentActivity.getAccount()
|
||||
);
|
||||
if (thumbnail == null) {
|
||||
thumbnail = ThumbnailsCacheManager.mDefaultImg;
|
||||
}
|
||||
final ThumbnailsCacheManager.AsyncDrawable asyncDrawable =
|
||||
new ThumbnailsCacheManager.AsyncDrawable(
|
||||
mParentActivity.getResources(),
|
||||
thumbnail,
|
||||
task
|
||||
);
|
||||
fileIcon.setImageDrawable(asyncDrawable);
|
||||
task.execute(fakeFileToCheatThumbnailsCacheManagerInterface);
|
||||
}
|
||||
}
|
||||
|
||||
if ("image/png".equals(upload.getMimeType())) {
|
||||
fileIcon.setBackgroundColor(mParentActivity.getResources()
|
||||
.getColor(R.color.background_color));
|
||||
}
|
||||
|
||||
|
||||
} else if (fakeFileToCheatThumbnailsCacheManagerInterface.isImage()) {
|
||||
File file = new File(upload.getLocalPath());
|
||||
// Thumbnail in Cache?
|
||||
Bitmap thumbnail = ThumbnailsCacheManager.getBitmapFromDiskCache(
|
||||
String.valueOf(file.hashCode()));
|
||||
if (thumbnail != null) {
|
||||
fileIcon.setImageBitmap(thumbnail);
|
||||
} else {
|
||||
// generate new Thumbnail
|
||||
if (allowedToCreateNewThumbnail) {
|
||||
final ThumbnailsCacheManager.ThumbnailGenerationTask task =
|
||||
new ThumbnailsCacheManager.ThumbnailGenerationTask(fileIcon);
|
||||
if (thumbnail == null) {
|
||||
thumbnail = ThumbnailsCacheManager.mDefaultImg;
|
||||
}
|
||||
final ThumbnailsCacheManager.AsyncDrawable asyncDrawable =
|
||||
new ThumbnailsCacheManager.AsyncDrawable(
|
||||
mParentActivity.getResources(),
|
||||
thumbnail,
|
||||
task
|
||||
);
|
||||
fileIcon.setImageDrawable(asyncDrawable);
|
||||
task.execute(file);
|
||||
Log_OC.v(TAG, "Executing task to generate a new thumbnail");
|
||||
}
|
||||
}
|
||||
|
||||
if ("image/png".equalsIgnoreCase(upload.getMimeType())) {
|
||||
fileIcon.setBackgroundColor(mParentActivity.getResources()
|
||||
.getColor(R.color.background_color));
|
||||
}
|
||||
} else {
|
||||
fileIcon.setImageResource(MimetypeIconUtil.getFileTypeIconId(
|
||||
upload.getMimeType(),
|
||||
fileName
|
||||
));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the status text to show to the user according to the status and last result of the
|
||||
* the given upload.
|
||||
*
|
||||
* @param upload Upload to describe.
|
||||
* @return Text describing the status of the given upload.
|
||||
*/
|
||||
private String getStatusText(OCUpload upload) {
|
||||
String status;
|
||||
switch (upload.getUploadStatus()) {
|
||||
|
||||
case UPLOAD_IN_PROGRESS:
|
||||
status = mParentActivity.getString(R.string.uploads_view_later_waiting_to_upload);
|
||||
FileUploader.FileUploaderBinder binder = mParentActivity.getFileUploaderBinder();
|
||||
if (binder != null && binder.isUploadingNow(upload)) {
|
||||
/// really uploading, bind the progress bar to listen for progress updates
|
||||
status = mParentActivity.getString(R.string.uploader_upload_in_progress_ticker);
|
||||
}
|
||||
break;
|
||||
|
||||
case UPLOAD_SUCCEEDED:
|
||||
status = mParentActivity.getString(R.string.uploads_view_upload_status_succeeded);
|
||||
break;
|
||||
|
||||
case UPLOAD_FAILED:
|
||||
switch (upload.getLastResult()) {
|
||||
case CREDENTIAL_ERROR:
|
||||
status = mParentActivity.getString(
|
||||
R.string.uploads_view_upload_status_failed_credentials_error
|
||||
);
|
||||
break;
|
||||
case FOLDER_ERROR:
|
||||
status = mParentActivity.getString(
|
||||
R.string.uploads_view_upload_status_failed_folder_error
|
||||
);
|
||||
break;
|
||||
case FILE_NOT_FOUND:
|
||||
status = mParentActivity.getString(
|
||||
R.string.uploads_view_upload_status_failed_localfile_error
|
||||
);
|
||||
break;
|
||||
case FILE_ERROR:
|
||||
status = mParentActivity.getString(
|
||||
R.string.uploads_view_upload_status_failed_file_error
|
||||
);
|
||||
break;
|
||||
case PRIVILEDGES_ERROR:
|
||||
status = mParentActivity.getString(
|
||||
R.string.uploads_view_upload_status_failed_permission_error
|
||||
);
|
||||
break;
|
||||
case NETWORK_CONNECTION:
|
||||
status = mParentActivity.getString(
|
||||
R.string.uploads_view_upload_status_failed_connection_error
|
||||
);
|
||||
break;
|
||||
case DELAYED_FOR_WIFI:
|
||||
status = mParentActivity.getString(
|
||||
R.string.uploads_view_upload_status_waiting_for_wifi
|
||||
);
|
||||
break;
|
||||
case CONFLICT_ERROR:
|
||||
status = mParentActivity.getString(
|
||||
R.string.uploads_view_upload_status_conflict
|
||||
);
|
||||
break;
|
||||
case SERVICE_INTERRUPTED:
|
||||
status = mParentActivity.getString(
|
||||
R.string.uploads_view_upload_status_service_interrupted
|
||||
);
|
||||
break;
|
||||
case UNKNOWN:
|
||||
status = mParentActivity.getString(
|
||||
R.string.uploads_view_upload_status_unknown_fail
|
||||
);
|
||||
break;
|
||||
case CANCELLED:
|
||||
// should not get here ; cancelled uploads should be wiped out
|
||||
status = mParentActivity.getString(
|
||||
R.string.uploads_view_upload_status_cancelled
|
||||
);
|
||||
break;
|
||||
case UPLOADED:
|
||||
// should not get here ; status should be UPLOAD_SUCCESS
|
||||
status = mParentActivity.getString(R.string.uploads_view_upload_status_succeeded);
|
||||
break;
|
||||
default:
|
||||
status = "Naughty devs added a new fail result but no description for the user";
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
status = "Uncontrolled status: " + upload.getUploadStatus().toString();
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean hasStableIds() {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Load upload items from {@link UploadsStorageManager}.
|
||||
*/
|
||||
private void loadUploadItemsFromDb() {
|
||||
Log_OC.d(TAG, "loadUploadItemsFromDb");
|
||||
|
||||
for (UploadGroup group : mUploadGroups) {
|
||||
group.refresh();
|
||||
}
|
||||
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(Observable arg0, Object arg1) {
|
||||
Log_OC.d(TAG, "update");
|
||||
loadUploadItemsFromDb();
|
||||
}
|
||||
|
||||
|
||||
public void refreshView() {
|
||||
Log_OC.d(TAG, "refreshView");
|
||||
loadUploadItemsFromDb();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getChild(int groupPosition, int childPosition) {
|
||||
return mUploadGroups[(int) getGroupId(groupPosition)].items[childPosition];
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getChildId(int groupPosition, int childPosition) {
|
||||
return childPosition;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView,
|
||||
ViewGroup parent) {
|
||||
return getView(mUploadGroups[(int) getGroupId(groupPosition)].items, childPosition, convertView, parent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getChildrenCount(int groupPosition) {
|
||||
return mUploadGroups[(int) getGroupId(groupPosition)].items.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getGroup(int groupPosition) {
|
||||
return mUploadGroups[(int) getGroupId(groupPosition)];
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getGroupCount() {
|
||||
int size = 0;
|
||||
for (UploadGroup uploadGroup : mUploadGroups) {
|
||||
if (uploadGroup.items.length > 0) {
|
||||
size++;
|
||||
}
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the groupId (that is, index in mUploadGroups) for group at position groupPosition (0-based).
|
||||
* Could probably be done more intuitive but this tested methods works as intended.
|
||||
*/
|
||||
@Override
|
||||
public long getGroupId(int groupPosition) {
|
||||
int id = -1;
|
||||
for (int i = 0; i <= groupPosition; ) {
|
||||
id++;
|
||||
if (mUploadGroups[id].items.length > 0) {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
|
||||
//force group to stay unfolded
|
||||
ExpandableListView listView = (ExpandableListView) parent;
|
||||
listView.expandGroup(groupPosition);
|
||||
|
||||
listView.setGroupIndicator(null);
|
||||
UploadGroup group = (UploadGroup) getGroup(groupPosition);
|
||||
if (convertView == null) {
|
||||
LayoutInflater inflaInflater = (LayoutInflater) mParentActivity
|
||||
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
convertView = inflaInflater.inflate(R.layout.upload_list_group, null);
|
||||
}
|
||||
TextView tv = (TextView) convertView.findViewById(R.id.uploadListGroupName);
|
||||
tv.setText(group.getGroupName());
|
||||
return convertView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChildSelectable(int groupPosition, int childPosition) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public class ProgressListener implements OnDatatransferProgressListener {
|
||||
int mLastPercent = 0;
|
||||
OCUpload mUpload = null;
|
||||
WeakReference<ProgressBar> mProgressBar = null;
|
||||
|
||||
public ProgressListener(OCUpload upload, ProgressBar progressBar) {
|
||||
mUpload = upload;
|
||||
mProgressBar = new WeakReference<ProgressBar>(progressBar);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTransferProgress(long progressRate, long totalTransferredSoFar, long totalToTransfer, String
|
||||
filename) {
|
||||
int percent = (int) (100.0 * ((double) totalTransferredSoFar) / ((double) totalToTransfer));
|
||||
if (percent != mLastPercent) {
|
||||
ProgressBar pb = mProgressBar.get();
|
||||
if (pb != null) {
|
||||
pb.setProgress(percent);
|
||||
pb.postInvalidate();
|
||||
}
|
||||
}
|
||||
mLastPercent = percent;
|
||||
}
|
||||
|
||||
public boolean isWrapping(ProgressBar progressBar) {
|
||||
ProgressBar wrappedProgressBar = mProgressBar.get();
|
||||
return (
|
||||
wrappedProgressBar != null &&
|
||||
wrappedProgressBar == progressBar // on purpose; don't replace with equals
|
||||
);
|
||||
}
|
||||
|
||||
public OCUpload getUpload() {
|
||||
return mUpload;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void addBinder() {
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
}
|
|
@ -6,7 +6,7 @@
|
|||
* @author David A. Velasco
|
||||
* @author masensio
|
||||
* Copyright (C) 2011 Bartek Przybylski
|
||||
* Copyright (C) 2015 ownCloud Inc.
|
||||
* Copyright (C) 2016 ownCloud Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
|
@ -24,9 +24,6 @@
|
|||
package com.owncloud.android.ui.adapter;
|
||||
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Vector;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
|
@ -57,6 +54,8 @@ import com.owncloud.android.utils.DisplayUtils;
|
|||
import com.owncloud.android.utils.FileStorageUtils;
|
||||
import com.owncloud.android.utils.MimetypeIconUtil;
|
||||
|
||||
import java.util.Vector;
|
||||
|
||||
|
||||
/**
|
||||
* This Adapter populates a ListView with all files and folders in an ownCloud
|
||||
|
@ -88,12 +87,14 @@ public class FileListListAdapter extends BaseAdapter implements ListAdapter {
|
|||
mJustFolders = justFolders;
|
||||
mContext = context;
|
||||
mAccount = AccountUtils.getCurrentOwnCloudAccount(mContext);
|
||||
|
||||
mTransferServiceGetter = transferServiceGetter;
|
||||
|
||||
mAppPreferences = PreferenceManager
|
||||
.getDefaultSharedPreferences(mContext);
|
||||
|
||||
// Read sorting order, default to sort by name ascending
|
||||
|
||||
FileStorageUtils.mSortOrder = mAppPreferences.getInt("sortOrder", 0);
|
||||
FileStorageUtils.mSortAscending = mAppPreferences.getBoolean("sortAscending", true);
|
||||
|
||||
|
@ -356,6 +357,7 @@ public class FileListListAdapter extends BaseAdapter implements ListAdapter {
|
|||
file.getFileName()));
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
// Folder
|
||||
fileIcon.setImageResource(
|
||||
|
|
|
@ -1,138 +0,0 @@
|
|||
/**
|
||||
* ownCloud Android client application
|
||||
*
|
||||
* Copyright (C) 2015 ownCloud Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package com.owncloud.android.ui.adapter;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.util.SparseArray;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.BaseExpandableListAdapter;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.owncloud.android.R;
|
||||
|
||||
public class MyExpandableListAdapter extends BaseExpandableListAdapter {
|
||||
|
||||
private final SparseArray<GroupAdapter> groups;
|
||||
public LayoutInflater inflater;
|
||||
public Activity activity;
|
||||
|
||||
public MyExpandableListAdapter(Activity act, SparseArray<GroupAdapter> groups) {
|
||||
activity = act;
|
||||
this.groups = groups;
|
||||
inflater = act.getLayoutInflater();
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Object getChild(int groupPosition, int childPosition) {
|
||||
return groups.get(groupPosition).children.get(childPosition);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getChildId(int groupPosition, int childPosition) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getChildView(int groupPosition, final int childPosition,
|
||||
boolean isLastChild, View convertView, ViewGroup parent) {
|
||||
final String children = (String) getChild(groupPosition, childPosition);
|
||||
TextView text = null;
|
||||
if (convertView == null) {
|
||||
convertView = inflater.inflate(R.layout.listrow_details, null);
|
||||
}
|
||||
|
||||
|
||||
text = (TextView) convertView.findViewById(R.id.textView1);
|
||||
text.setText(children);
|
||||
convertView.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
Toast.makeText(activity, children, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
});
|
||||
return convertView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getGroupView(int groupPosition, boolean isExpanded,
|
||||
View convertView, ViewGroup parent) {
|
||||
if (convertView == null) {
|
||||
convertView = inflater.inflate(R.layout.listrow_group, null);
|
||||
}
|
||||
|
||||
final GroupAdapter groupAdapter = (GroupAdapter) getGroup(groupPosition);
|
||||
if (groupAdapter.children.size() == 0){
|
||||
convertView.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
Toast.makeText(activity, groupAdapter.string, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
});
|
||||
}
|
||||
((TextView) convertView).setText(groupAdapter.string);
|
||||
|
||||
return convertView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getChildrenCount(int groupPosition) {
|
||||
return groups.get(groupPosition).children.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getGroup(int groupPosition) {
|
||||
return groups.get(groupPosition);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getGroupCount() {
|
||||
return groups.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGroupCollapsed(int groupPosition) {
|
||||
super.onGroupCollapsed(groupPosition);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGroupExpanded(int groupPosition) {
|
||||
super.onGroupExpanded(groupPosition);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getGroupId(int groupPosition) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasStableIds() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChildSelectable(int groupPosition, int childPosition) {
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -77,12 +77,12 @@ public class UploadSourceDialogFragment extends DialogFragment {
|
|||
UploadFilesActivity.EXTRA_ACCOUNT,
|
||||
((FileActivity)getActivity()).getAccount()
|
||||
);
|
||||
//startActivityForResult(action, ACTION_SELECT_MULTIPLE_FILES);
|
||||
//startActivityForResult(action, REQUEST_CODE__SELECT_MULTIPLE_FILES);
|
||||
// this flow seems broken;
|
||||
// Actionbarsherlock, maybe?
|
||||
getActivity().startActivityForResult(
|
||||
action,
|
||||
FileDisplayActivity.ACTION_SELECT_MULTIPLE_FILES
|
||||
FileDisplayActivity.REQUEST_CODE__SELECT_MULTIPLE_FILES
|
||||
);
|
||||
|
||||
} else if (item == 1) {
|
||||
|
@ -94,7 +94,7 @@ public class UploadSourceDialogFragment extends DialogFragment {
|
|||
}
|
||||
getActivity().startActivityForResult(
|
||||
Intent.createChooser(action, getString(R.string.upload_chooser_title)),
|
||||
FileDisplayActivity.ACTION_SELECT_CONTENT_FROM_APPS
|
||||
FileDisplayActivity.REQUEST_CODE__SELECT_CONTENT_FROM_APPS
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
45
src/com/owncloud/android/ui/errorhandling/ErrorShowActivity.java
Executable file
|
@ -0,0 +1,45 @@
|
|||
/**
|
||||
* ownCloud Android client application
|
||||
*
|
||||
* @author LukeOwncloud
|
||||
* Copyright (C) 2016 ownCloud Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package com.owncloud.android.ui.errorhandling;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.owncloud.android.R;
|
||||
|
||||
public class ErrorShowActivity extends Activity {
|
||||
|
||||
private static final String TAG = ErrorShowActivity.class.getSimpleName();
|
||||
|
||||
TextView mError;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
Log.e(TAG, "ErrorShowActivity was called. See above for StackTrace.");
|
||||
Thread.setDefaultUncaughtExceptionHandler(new ExceptionHandler(this));
|
||||
setContentView(R.layout.errorhandling_showerror);
|
||||
mError = (TextView) findViewById(R.id.errorTextView);
|
||||
mError.setText(getIntent().getStringExtra("error"));
|
||||
|
||||
}
|
||||
}
|
85
src/com/owncloud/android/ui/errorhandling/ExceptionHandler.java
Executable file
|
@ -0,0 +1,85 @@
|
|||
/**
|
||||
* ownCloud Android client application
|
||||
*
|
||||
* @author LukeOwncloud
|
||||
* Copyright (C) 2016 ownCloud Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package com.owncloud.android.ui.errorhandling;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.os.Build;
|
||||
import android.util.Log;
|
||||
|
||||
public class ExceptionHandler implements java.lang.Thread.UncaughtExceptionHandler {
|
||||
private final Activity mContext;
|
||||
private final String LINE_SEPARATOR = "\n";
|
||||
|
||||
private static final String TAG = ExceptionHandler.class.getSimpleName();
|
||||
|
||||
public ExceptionHandler(Activity context) {
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
public void uncaughtException(Thread thread, Throwable exception) {
|
||||
Log.e(TAG, "ExceptionHandler caught UncaughtException", exception);
|
||||
StringWriter stackTrace = new StringWriter();
|
||||
exception.printStackTrace(new PrintWriter(stackTrace));
|
||||
StringBuilder errorReport = new StringBuilder();
|
||||
errorReport.append("************ CAUSE OF ERROR ************\n\n");
|
||||
errorReport.append(stackTrace.toString());
|
||||
|
||||
errorReport.append("\n************ DEVICE INFORMATION ***********\n");
|
||||
errorReport.append("Brand: ");
|
||||
errorReport.append(Build.BRAND);
|
||||
errorReport.append(LINE_SEPARATOR);
|
||||
errorReport.append("Device: ");
|
||||
errorReport.append(Build.DEVICE);
|
||||
errorReport.append(LINE_SEPARATOR);
|
||||
errorReport.append("Model: ");
|
||||
errorReport.append(Build.MODEL);
|
||||
errorReport.append(LINE_SEPARATOR);
|
||||
errorReport.append("Id: ");
|
||||
errorReport.append(Build.ID);
|
||||
errorReport.append(LINE_SEPARATOR);
|
||||
errorReport.append("Product: ");
|
||||
errorReport.append(Build.PRODUCT);
|
||||
errorReport.append(LINE_SEPARATOR);
|
||||
errorReport.append("\n************ FIRMWARE ************\n");
|
||||
errorReport.append("SDK: ");
|
||||
errorReport.append(Build.VERSION.SDK_INT);
|
||||
errorReport.append(LINE_SEPARATOR);
|
||||
errorReport.append("Release: ");
|
||||
errorReport.append(Build.VERSION.RELEASE);
|
||||
errorReport.append(LINE_SEPARATOR);
|
||||
errorReport.append("Incremental: ");
|
||||
errorReport.append(Build.VERSION.INCREMENTAL);
|
||||
errorReport.append(LINE_SEPARATOR);
|
||||
|
||||
Log.e(TAG, "An exception was thrown and handled by ExceptionHandler:", exception);
|
||||
|
||||
Intent intent = new Intent(mContext, ErrorShowActivity.class);
|
||||
intent.putExtra("error", errorReport.toString());
|
||||
mContext.startActivity(intent);
|
||||
|
||||
android.os.Process.killProcess(android.os.Process.myPid());
|
||||
System.exit(1000);
|
||||
}
|
||||
|
||||
}
|
90
src/com/owncloud/android/ui/fragment/ExpandableListFragment.java
Executable file
|
@ -0,0 +1,90 @@
|
|||
/**
|
||||
* ownCloud Android client application
|
||||
*
|
||||
* Copyright (C) 2012 Bartek Przybylski
|
||||
* Copyright (C) 2012-2016 ownCloud Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.owncloud.android.ui.fragment;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.widget.SwipeRefreshLayout;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ExpandableListAdapter;
|
||||
import android.widget.ExpandableListView;
|
||||
import android.widget.ExpandableListView.OnChildClickListener;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.owncloud.android.R;
|
||||
import com.owncloud.android.lib.common.utils.Log_OC;
|
||||
|
||||
/**
|
||||
* Extending ExtendedListFragment. This allows dividing list in groups.
|
||||
*/
|
||||
public class ExpandableListFragment extends ExtendedListFragment implements OnChildClickListener
|
||||
{
|
||||
protected static final String TAG = ExpandableListFragment.class.getSimpleName();
|
||||
|
||||
protected ExpandableListView mList;
|
||||
|
||||
public void setListAdapter(ExpandableListAdapter listAdapter) {
|
||||
mList.setAdapter(listAdapter);
|
||||
mList.invalidate();
|
||||
}
|
||||
|
||||
public ExpandableListView getListView() {
|
||||
return mList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
Log_OC.e(TAG, "onCreateView");
|
||||
|
||||
View v = inflater.inflate(R.layout.list_fragment_expandable, null);
|
||||
mEmptyListMessage = (TextView) v.findViewById(R.id.empty_list_view);
|
||||
mList = (ExpandableListView)(v.findViewById(R.id.list_root));
|
||||
mList.setOnChildClickListener(this);
|
||||
|
||||
mList.setDivider(getResources().getDrawable(R.drawable.uploader_list_separator));
|
||||
mList.setDividerHeight(1);
|
||||
|
||||
// if (savedInstanceState != null) {
|
||||
// int referencePosition = savedInstanceState.getInt(KEY_SAVED_LIST_POSITION);
|
||||
// setReferencePosition(referencePosition);
|
||||
// }
|
||||
|
||||
// Pull down refresh
|
||||
mRefreshListLayout = (SwipeRefreshLayout) v.findViewById(R.id.swipe_refresh_files);
|
||||
mRefreshEmptyLayout = (SwipeRefreshLayout) v.findViewById(R.id.swipe_refresh_files_emptyView);
|
||||
|
||||
onCreateSwipeToRefresh(mRefreshListLayout);
|
||||
onCreateSwipeToRefresh(mRefreshEmptyLayout);
|
||||
|
||||
mList.setEmptyView(mRefreshEmptyLayout);
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) {
|
||||
// to be @overriden
|
||||
Log_OC.e(TAG, "onChildClick(). This method should be overriden!");
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
|
@ -2,7 +2,7 @@
|
|||
* ownCloud Android client application
|
||||
*
|
||||
* Copyright (C) 2012 Bartek Przybylski
|
||||
* Copyright (C) 2012-2015 ownCloud Inc.
|
||||
* Copyright (C) 2012-2016 ownCloud Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
|
@ -20,8 +20,6 @@
|
|||
|
||||
package com.owncloud.android.ui.fragment;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.Fragment;
|
||||
|
@ -45,33 +43,33 @@ import com.owncloud.android.ui.ExtendedListView;
|
|||
import com.owncloud.android.ui.activity.OnEnforceableRefreshListener;
|
||||
import com.owncloud.android.ui.adapter.FileListListAdapter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import third_parties.in.srain.cube.GridViewWithHeaderAndFooter;
|
||||
|
||||
/**
|
||||
* TODO extending SherlockListFragment instead of SherlockFragment
|
||||
*/
|
||||
public class ExtendedListFragment extends Fragment
|
||||
implements OnItemClickListener, OnEnforceableRefreshListener {
|
||||
|
||||
private static final String TAG = ExtendedListFragment.class.getSimpleName();
|
||||
protected static final String TAG = ExtendedListFragment.class.getSimpleName();
|
||||
|
||||
protected static final String KEY_SAVED_LIST_POSITION = "SAVED_LIST_POSITION";
|
||||
|
||||
private static final String KEY_SAVED_LIST_POSITION = "SAVED_LIST_POSITION";
|
||||
private static final String KEY_INDEXES = "INDEXES";
|
||||
private static final String KEY_FIRST_POSITIONS= "FIRST_POSITIONS";
|
||||
private static final String KEY_TOPS = "TOPS";
|
||||
private static final String KEY_HEIGHT_CELL = "HEIGHT_CELL";
|
||||
private static final String KEY_EMPTY_LIST_MESSAGE = "EMPTY_LIST_MESSAGE";
|
||||
|
||||
private SwipeRefreshLayout mRefreshListLayout;
|
||||
protected SwipeRefreshLayout mRefreshListLayout;
|
||||
private SwipeRefreshLayout mRefreshGridLayout;
|
||||
private SwipeRefreshLayout mRefreshEmptyLayout;
|
||||
private TextView mEmptyListMessage;
|
||||
protected SwipeRefreshLayout mRefreshEmptyLayout;
|
||||
protected TextView mEmptyListMessage;
|
||||
|
||||
private FloatingActionsMenu mFabMain;
|
||||
private FloatingActionButton mFabUpload;
|
||||
private FloatingActionButton mFabMkdir;
|
||||
private FloatingActionButton mFabUploadFromApp;
|
||||
|
||||
|
||||
// Save the state of the scroll in browsing
|
||||
private ArrayList<Integer> mIndexes;
|
||||
private ArrayList<Integer> mFirstPositions;
|
||||
|
@ -386,7 +384,7 @@ public class ExtendedListFragment extends Fragment
|
|||
return (mEmptyListMessage != null) ? mEmptyListMessage.getText().toString() : "";
|
||||
}
|
||||
|
||||
private void onCreateSwipeToRefresh(SwipeRefreshLayout refreshLayout) {
|
||||
protected void onCreateSwipeToRefresh(SwipeRefreshLayout refreshLayout) {
|
||||
// Colors in animations
|
||||
refreshLayout.setColorSchemeResources(R.color.color_accent, R.color.primary,
|
||||
R.color.primary_dark);
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* @author Bartek Przybylski
|
||||
* @author David A. Velasco
|
||||
* Copyright (C) 2011 Bartek Przybylski
|
||||
* Copyright (C) 2015 ownCloud Inc.
|
||||
* Copyright (C) 2016 ownCloud Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
|
@ -549,6 +549,8 @@ public class FileDetailFragment extends FileFragment implements OnClickListener
|
|||
mContainerActivity.getFileUploaderBinder().
|
||||
addDatatransferProgressListener(mProgressListener, mAccount, getFile());
|
||||
}
|
||||
} else {
|
||||
Log_OC.d(TAG, "mProgressListener == null");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* @author masensio
|
||||
* @author David A. Velasco
|
||||
* Copyright (C) 2011 Bartek Przybylski
|
||||
* Copyright (C) 2015 ownCloud Inc.
|
||||
* Copyright (C) 2016 ownCloud Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
|
@ -229,7 +229,7 @@ public class OCFileListFragment extends ExtendedListFragment
|
|||
@Override
|
||||
public void onClick(View v) {
|
||||
UploadFilesActivity.startUploadActivityForResult(getActivity(), ((FileActivity)getActivity())
|
||||
.getAccount(), FileDisplayActivity.ACTION_SELECT_MULTIPLE_FILES);
|
||||
.getAccount(), FileDisplayActivity.REQUEST_CODE__SELECT_MULTIPLE_FILES);
|
||||
getFabMain().collapse();
|
||||
recordMiniFabClick();
|
||||
}
|
||||
|
@ -285,7 +285,7 @@ public class OCFileListFragment extends ExtendedListFragment
|
|||
}
|
||||
getActivity().startActivityForResult(
|
||||
Intent.createChooser(action, getString(R.string.upload_chooser_title)),
|
||||
FileDisplayActivity.ACTION_SELECT_CONTENT_FROM_APPS
|
||||
FileDisplayActivity.REQUEST_CODE__SELECT_CONTENT_FROM_APPS
|
||||
);
|
||||
getFabMain().collapse();
|
||||
recordMiniFabClick();
|
||||
|
@ -586,7 +586,7 @@ public class OCFileListFragment extends ExtendedListFragment
|
|||
|
||||
// Pass mTargetFile that contains info of selected file/folder
|
||||
action.putExtra(FolderPickerActivity.EXTRA_FILE, mTargetFile);
|
||||
getActivity().startActivityForResult(action, FileDisplayActivity.ACTION_MOVE_FILES);
|
||||
getActivity().startActivityForResult(action, FileDisplayActivity.REQUEST_CODE__MOVE_FILES);
|
||||
return true;
|
||||
}
|
||||
case R.id.action_favorite_file: {
|
||||
|
@ -602,7 +602,7 @@ public class OCFileListFragment extends ExtendedListFragment
|
|||
|
||||
// Pass mTargetFile that contains info of selected file/folder
|
||||
action.putExtra(FolderPickerActivity.EXTRA_FILE, mTargetFile);
|
||||
getActivity().startActivityForResult(action, FileDisplayActivity.ACTION_COPY_FILES);
|
||||
getActivity().startActivityForResult(action, FileDisplayActivity.REQUEST_CODE__COPY_FILES);
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
|
|
152
src/com/owncloud/android/ui/fragment/UploadListFragment.java
Executable file
|
@ -0,0 +1,152 @@
|
|||
/**
|
||||
* ownCloud Android client application
|
||||
*
|
||||
* @author LukeOwncloud
|
||||
* Copyright (C) 2016 ownCloud Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package com.owncloud.android.ui.fragment;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ExpandableListView;
|
||||
import android.widget.ListView;
|
||||
|
||||
import com.owncloud.android.R;
|
||||
import com.owncloud.android.db.OCUpload;
|
||||
import com.owncloud.android.lib.common.utils.Log_OC;
|
||||
import com.owncloud.android.ui.activity.FileActivity;
|
||||
import com.owncloud.android.ui.adapter.ExpandableUploadListAdapter;
|
||||
|
||||
/**
|
||||
* A Fragment that lists all files and folders in a given LOCAL path.
|
||||
*
|
||||
*/
|
||||
public class UploadListFragment extends ExpandableListFragment {
|
||||
static private String TAG = UploadListFragment.class.getSimpleName();
|
||||
|
||||
/**
|
||||
* Reference to the Activity which this fragment is attached to. For
|
||||
* callbacks
|
||||
*/
|
||||
private UploadListFragment.ContainerActivity mContainerActivity;
|
||||
|
||||
private ExpandableUploadListAdapter mAdapter;
|
||||
|
||||
/** Is binder ready in the Activity? */
|
||||
private boolean mBinderReady = false;
|
||||
|
||||
public void setBinderReady(boolean ready) {
|
||||
mBinderReady = ready;
|
||||
}
|
||||
public boolean isBinderReady(){
|
||||
return mBinderReady;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
View v = super.onCreateView(inflater, container, savedInstanceState);
|
||||
getListView().setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
|
||||
setMessageForEmptyList(getString(R.string.upload_list_empty));
|
||||
setOnRefreshListener(this);
|
||||
return v;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRefresh() {
|
||||
// remove the progress circle as soon as pull is triggered, like in the list of files
|
||||
mRefreshEmptyLayout.setRefreshing(false);
|
||||
mRefreshListLayout.setRefreshing(false);
|
||||
|
||||
mAdapter.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttach(Activity activity) {
|
||||
super.onAttach(activity);
|
||||
try {
|
||||
mContainerActivity = (ContainerActivity) activity;
|
||||
} catch (ClassCastException e) {
|
||||
throw new ClassCastException(activity.toString() + " must implement "
|
||||
+ UploadListFragment.ContainerActivity.class.getSimpleName());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityCreated(Bundle savedInstanceState) {
|
||||
Log_OC.d(TAG, "onActivityCreated() start");
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
Log_OC.d(TAG, "onStart() start");
|
||||
super.onStart();
|
||||
mAdapter = new ExpandableUploadListAdapter((FileActivity)getActivity());
|
||||
setListAdapter(mAdapter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) {
|
||||
boolean handled = false;
|
||||
OCUpload OCUpload = (OCUpload) mAdapter.getChild(groupPosition, childPosition);
|
||||
if (OCUpload != null) {
|
||||
// notify the click to container Activity
|
||||
handled = mContainerActivity.onUploadItemClick(OCUpload);
|
||||
} else {
|
||||
Log_OC.w(TAG, "Null object in ListAdapter!!");
|
||||
}
|
||||
return handled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface to implement by any Activity that includes some instance of
|
||||
* UploadListFragment
|
||||
*
|
||||
* @author LukeOwncloud
|
||||
*/
|
||||
public interface ContainerActivity {
|
||||
|
||||
/**
|
||||
* Callback method invoked when an upload item is clicked by the user on
|
||||
* the upload list
|
||||
*
|
||||
* @param file
|
||||
* @return return true if click was handled.
|
||||
*/
|
||||
public boolean onUploadItemClick(OCUpload file);
|
||||
|
||||
}
|
||||
|
||||
public void binderReady(){
|
||||
setBinderReady(true);
|
||||
|
||||
if (mAdapter != null) {
|
||||
mAdapter.addBinder();
|
||||
}
|
||||
}
|
||||
|
||||
public void updateUploads(){
|
||||
if (mAdapter != null) {
|
||||
mAdapter.refreshView();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -2,7 +2,7 @@
|
|||
* ownCloud Android client application
|
||||
*
|
||||
* @author David A. Velasco
|
||||
* Copyright (C) 2015 ownCloud Inc.
|
||||
* Copyright (C) 2016 ownCloud Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* ownCloud Android client application
|
||||
*
|
||||
* @author David A. Velasco
|
||||
* Copyright (C) 2015 ownCloud Inc.
|
||||
* Copyright (C) 2016 ownCloud Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
|
@ -21,10 +21,6 @@ package com.owncloud.android.ui.preview;
|
|||
|
||||
import android.accounts.Account;
|
||||
import android.app.Activity;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.media.MediaMetadataRetriever;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
|
@ -32,12 +28,16 @@ import android.content.Intent;
|
|||
import android.content.ServiceConnection;
|
||||
import android.content.res.Configuration;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.media.MediaMetadataRetriever;
|
||||
import android.media.MediaPlayer;
|
||||
import android.media.MediaPlayer.OnCompletionListener;
|
||||
import android.media.MediaPlayer.OnErrorListener;
|
||||
import android.media.MediaPlayer.OnPreparedListener;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
|
@ -557,7 +557,7 @@ public class PreviewMediaFragment extends FileFragment implements
|
|||
i.putExtra(PreviewVideoActivity.EXTRA_AUTOPLAY, mVideoPreview.isPlaying());
|
||||
mVideoPreview.pause();
|
||||
i.putExtra(PreviewVideoActivity.EXTRA_START_POSITION, mVideoPreview.getCurrentPosition());
|
||||
startActivityForResult(i, 0);
|
||||
startActivityForResult(i, FileActivity.REQUEST_CODE__LAST_SHARED + 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
47
src/com/owncloud/android/utils/ConnectivityUtils.java
Normal file
|
@ -0,0 +1,47 @@
|
|||
/**
|
||||
* ownCloud Android client application
|
||||
*
|
||||
* @author David A. Velasco
|
||||
* Copyright (C) 2016 ownCloud Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.owncloud.android.utils;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.NetworkInfo;
|
||||
|
||||
import com.owncloud.android.lib.common.utils.Log_OC;
|
||||
|
||||
public class ConnectivityUtils {
|
||||
|
||||
private final static String TAG = ConnectivityUtils.class.getName();
|
||||
|
||||
public static boolean isAppConnectedViaWiFi(Context context) {
|
||||
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
boolean result =
|
||||
cm != null && cm.getActiveNetworkInfo() != null
|
||||
&& cm.getActiveNetworkInfo().getType() == ConnectivityManager.TYPE_WIFI
|
||||
&& cm.getActiveNetworkInfo().getState() == NetworkInfo.State.CONNECTED;
|
||||
Log_OC.d(TAG, "is AppConnectedViaWifi returns " + result);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static boolean isAppConnected(Context context) {
|
||||
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
return cm.getActiveNetworkInfo() != null && cm.getActiveNetworkInfo().isConnected();
|
||||
}
|
||||
|
||||
}
|
|
@ -2,7 +2,7 @@
|
|||
* ownCloud Android client application
|
||||
*
|
||||
* @author David A. Velasco
|
||||
* Copyright (C) 2015 ownCloud Inc.
|
||||
* Copyright (C) 2016 ownCloud Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
|
@ -53,23 +53,53 @@ public class FileStorageUtils {
|
|||
public static Integer mSortOrder = SORT_NAME;
|
||||
public static Boolean mSortAscending = true;
|
||||
|
||||
/**
|
||||
* Takes a full path to owncloud file and removes beginning which is path to ownload data folder.
|
||||
* If fullPath does not start with that folder, fullPath is returned as is.
|
||||
*/
|
||||
public static final String removeDataFolderPath(String fullPath) {
|
||||
File sdCard = Environment.getExternalStorageDirectory();
|
||||
String dataFolderPath = sdCard.getAbsolutePath() + "/" + MainApp.getDataFolder() + "/";
|
||||
if(fullPath.indexOf(dataFolderPath) == 0) {
|
||||
return fullPath.substring(dataFolderPath.length());
|
||||
}
|
||||
return fullPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get local owncloud storage path for accountName.
|
||||
*/
|
||||
public static final String getSavePath(String accountName) {
|
||||
File sdCard = Environment.getExternalStorageDirectory();
|
||||
return sdCard.getAbsolutePath() + "/" + MainApp.getDataFolder() + "/" + Uri.encode(accountName, "@");
|
||||
// URL encoding is an 'easy fix' to overcome that NTFS and FAT32 don't allow ":" in file names, that can be in the accountName since 0.1.190B
|
||||
// URL encoding is an 'easy fix' to overcome that NTFS and FAT32 don't allow ":" in file names,
|
||||
// that can be in the accountName since 0.1.190B
|
||||
}
|
||||
|
||||
/**
|
||||
* Get local path where OCFile file is to be stored after upload. That is,
|
||||
* corresponding local path (in local owncloud storage) to remote uploaded
|
||||
* file.
|
||||
*/
|
||||
public static final String getDefaultSavePathFor(String accountName, OCFile file) {
|
||||
return getSavePath(accountName) + file.getRemotePath();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get absolute path to tmp folder inside datafolder in sd-card for given accountName.
|
||||
*/
|
||||
public static final String getTemporalPath(String accountName) {
|
||||
File sdCard = Environment.getExternalStorageDirectory();
|
||||
return sdCard.getAbsolutePath() + "/" + MainApp.getDataFolder() + "/tmp/" + Uri.encode(accountName, "@");
|
||||
// URL encoding is an 'easy fix' to overcome that NTFS and FAT32 don't allow ":" in file names, that can be in the accountName since 0.1.190B
|
||||
// URL encoding is an 'easy fix' to overcome that NTFS and FAT32 don't allow ":" in file names,
|
||||
// that can be in the accountName since 0.1.190B
|
||||
}
|
||||
|
||||
/**
|
||||
* Optimistic number of bytes available on sd-card. accountName is ignored.
|
||||
* @param accountName not used. can thus be null.
|
||||
* @return Optimistic number of available bytes (can be less)
|
||||
*/
|
||||
@SuppressLint("NewApi")
|
||||
public static final long getUsableSpace(String accountName) {
|
||||
File savePath = Environment.getExternalStorageDirectory();
|
||||
|
|
|
@ -1,3 +1,22 @@
|
|||
/**
|
||||
* ownCloud Android client application
|
||||
*
|
||||
* Copyright (C) 2016 ownCloud Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.owncloud.android.utils;
|
||||
|
||||
import android.webkit.MimeTypeMap;
|
||||
|
@ -83,6 +102,21 @@ public class MimetypeIconUtil {
|
|||
return R.drawable.ic_menu_archive;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a single MIME type of all the possible, by inspection of the file extension, and taking
|
||||
* into account the MIME types known by ownCloud first.
|
||||
*
|
||||
* @param filename Name of file
|
||||
* @return A single MIME type, "application/octet-stream" for unknown file extensions.
|
||||
*/
|
||||
public static String getBestMimeTypeByFilename(String filename) {
|
||||
List<String> candidates = determineMimeTypesByFilename(filename);
|
||||
if (candidates == null || candidates.size() < 1) {
|
||||
return "application/octet-stream";
|
||||
}
|
||||
return candidates.get(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* determines the icon based on the mime type.
|
||||
*
|
||||
|
|
53
src/com/owncloud/android/utils/UploadUtils.java
Executable file
|
@ -0,0 +1,53 @@
|
|||
/**
|
||||
* ownCloud Android client application
|
||||
*
|
||||
* @author LukeOwncloud
|
||||
* Copyright (C) 2016 ownCloud Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.owncloud.android.utils;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.NetworkInfo.State;
|
||||
import android.os.BatteryManager;
|
||||
|
||||
|
||||
public class UploadUtils {
|
||||
|
||||
public static boolean isCharging(Context context) {
|
||||
IntentFilter ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
|
||||
Intent batteryStatus = context.registerReceiver(null, ifilter);
|
||||
|
||||
int status = batteryStatus.getIntExtra(BatteryManager.EXTRA_STATUS, -1);
|
||||
return status == BatteryManager.BATTERY_STATUS_CHARGING || status == BatteryManager.BATTERY_STATUS_FULL;
|
||||
}
|
||||
|
||||
public static boolean isOnline(Context context) {
|
||||
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
return cm.getActiveNetworkInfo() != null && cm.getActiveNetworkInfo().isConnected();
|
||||
}
|
||||
|
||||
public static boolean isConnectedViaWiFi(Context context) {
|
||||
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
return cm != null && cm.getActiveNetworkInfo() != null
|
||||
&& cm.getActiveNetworkInfo().getType() == ConnectivityManager.TYPE_WIFI
|
||||
&& cm.getActiveNetworkInfo().getState() == State.CONNECTED;
|
||||
}
|
||||
|
||||
}
|