• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.documentsui.services;
18 
19 import static com.android.documentsui.Shared.DEBUG;
20 import static com.android.documentsui.services.FileOperationService.OPERATION_MOVE;
21 
22 import android.app.Notification;
23 import android.app.Notification.Builder;
24 import android.content.Context;
25 import android.os.RemoteException;
26 import android.provider.DocumentsContract;
27 import android.provider.DocumentsContract.Document;
28 import android.util.Log;
29 
30 import com.android.documentsui.R;
31 import com.android.documentsui.model.DocumentInfo;
32 import com.android.documentsui.model.DocumentStack;
33 
34 import java.util.List;
35 
36 // TODO: Stop extending CopyJob.
37 final class MoveJob extends CopyJob {
38 
39     private static final String TAG = "MoveJob";
40 
41     final DocumentInfo mSrcParent;
42 
43     /**
44      * Moves files to a destination identified by {@code destination}.
45      * Performs most work by delegating to CopyJob, then deleting
46      * a file after it has been copied.
47      *
48      * @see @link {@link Job} constructor for most param descriptions.
49      *
50      * @param srcs List of files to be moved.
51      * @param srcParent Parent of all source files.
52      */
MoveJob(Context service, Context appContext, Listener listener, String id, DocumentStack destination, List<DocumentInfo> srcs, DocumentInfo srcParent)53     MoveJob(Context service, Context appContext, Listener listener,
54             String id, DocumentStack destination, List<DocumentInfo> srcs, DocumentInfo srcParent) {
55         super(service, appContext, listener, OPERATION_MOVE, id, destination, srcs);
56         this.mSrcParent = srcParent;
57     }
58 
59     @Override
createProgressBuilder()60     Builder createProgressBuilder() {
61         return super.createProgressBuilder(
62                 service.getString(R.string.move_notification_title),
63                 R.drawable.ic_menu_copy,
64                 service.getString(android.R.string.cancel),
65                 R.drawable.ic_cab_cancel);
66     }
67 
68     @Override
getSetupNotification()69     public Notification getSetupNotification() {
70         return getSetupNotification(service.getString(R.string.move_preparing));
71     }
72 
73     @Override
getProgressNotification()74     public Notification getProgressNotification() {
75         return getProgressNotification(R.string.copy_remaining);
76     }
77 
78     @Override
getFailureNotification()79     Notification getFailureNotification() {
80         return getFailureNotification(
81                 R.plurals.move_error_notification_title, R.drawable.ic_menu_copy);
82     }
83 
processDocument(DocumentInfo src, DocumentInfo srcParent, DocumentInfo dest)84     void processDocument(DocumentInfo src, DocumentInfo srcParent, DocumentInfo dest)
85             throws ResourceException {
86 
87         // TODO: When optimized move kicks in, we're not making any progress updates. FIX IT!
88 
89         // When moving within the same provider, try to use optimized moving.
90         // If not supported, then fallback to byte-by-byte copy/move.
91         if (src.authority.equals(dest.authority)) {
92             if ((src.flags & Document.FLAG_SUPPORTS_MOVE) != 0) {
93                 try {
94                     if (DocumentsContract.moveDocument(getClient(src), src.derivedUri,
95                             srcParent != null ? srcParent.derivedUri : mSrcParent.derivedUri,
96                             dest.derivedUri) != null) {
97                         return;
98                     }
99                 } catch (RemoteException | RuntimeException e) {
100                     Log.e(TAG, "Provider side move failed for: " + src.derivedUri
101                             + " due to an exception: ", e);
102                 }
103                 // If optimized move fails, then fallback to byte-by-byte copy.
104                 if (DEBUG) Log.d(TAG, "Fallback to byte-by-byte move for: " + src.derivedUri);
105             }
106         }
107 
108         // Moving virtual files by bytes is not supported. This is because, it would involve
109         // conversion, and the source file should not be deleted in such case (as it's a different
110         // file).
111         if (src.isVirtualDocument()) {
112             throw new ResourceException("Cannot move virtual file %s byte by byte.",
113                     src.derivedUri);
114         }
115 
116         // If we couldn't do an optimized copy...we fall back to vanilla byte copy.
117         byteCopyDocument(src, dest);
118 
119         // Remove the source document.
120         if(!isCanceled()) {
121             deleteDocument(src, srcParent);
122         }
123     }
124 
125     @Override
toString()126     public String toString() {
127         return new StringBuilder()
128                 .append("MoveJob")
129                 .append("{")
130                 .append("id=" + id)
131                 .append(", srcs=" + mSrcs)
132                 .append(", srcParent=" + mSrcParent)
133                 .append(", destination=" + stack)
134                 .append("}")
135                 .toString();
136     }
137 }
138