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.services.FileOperationService.OPERATION_COPY;
20 import static com.android.documentsui.services.FileOperationService.OPERATION_COMPRESS;
21 import static com.android.documentsui.services.FileOperationService.OPERATION_EXTRACT;
22 import static com.android.documentsui.services.FileOperationService.OPERATION_DELETE;
23 import static com.android.documentsui.services.FileOperationService.OPERATION_MOVE;
24 import static com.android.documentsui.services.FileOperationService.OPERATION_UNKNOWN;
25 
26 import android.content.Context;
27 import android.net.Uri;
28 import android.os.Parcel;
29 import android.os.Parcelable;
30 import android.support.annotation.VisibleForTesting;
31 
32 import com.android.documentsui.base.DocumentStack;
33 import com.android.documentsui.base.Features;
34 import com.android.documentsui.clipping.UrisSupplier;
35 import com.android.documentsui.services.FileOperationService.OpType;
36 
37 import javax.annotation.Nullable;
38 
39 /**
40  * FileOperation describes a file operation, such as move/copy/delete etc.
41  */
42 public abstract class FileOperation implements Parcelable {
43     private final @OpType int mOpType;
44 
45     private final UrisSupplier mSrcs;
46     private DocumentStack mDestination;
47 
48     @VisibleForTesting
FileOperation(@pType int opType, UrisSupplier srcs, DocumentStack destination)49     FileOperation(@OpType int opType, UrisSupplier srcs, DocumentStack destination) {
50         assert(opType != OPERATION_UNKNOWN);
51         assert(srcs.getItemCount() > 0);
52 
53         mOpType = opType;
54         mSrcs = srcs;
55         mDestination = destination;
56     }
57 
58     @Override
describeContents()59     public int describeContents() {
60         return 0;
61     }
62 
getOpType()63     public @OpType int getOpType() {
64         return mOpType;
65     }
66 
getSrc()67     public UrisSupplier getSrc() {
68         return mSrcs;
69     }
70 
getDestination()71     public DocumentStack getDestination() {
72         return mDestination;
73     }
74 
setDestination(DocumentStack destination)75     public void setDestination(DocumentStack destination) {
76         mDestination = destination;
77     }
78 
dispose()79     public void dispose() {
80         mSrcs.dispose();
81     }
82 
createJob(Context service, Job.Listener listener, String id, Features features)83     abstract Job createJob(Context service, Job.Listener listener, String id, Features features);
84 
appendInfoTo(StringBuilder builder)85     private void appendInfoTo(StringBuilder builder) {
86         builder.append("opType=").append(mOpType);
87         builder.append(", srcs=").append(mSrcs.toString());
88         builder.append(", destination=").append(mDestination.toString());
89     }
90 
91     @Override
writeToParcel(Parcel out, int flag)92     public void writeToParcel(Parcel out, int flag) {
93         out.writeInt(mOpType);
94         out.writeParcelable(mSrcs, flag);
95         out.writeParcelable(mDestination, flag);
96     }
97 
FileOperation(Parcel in)98     private FileOperation(Parcel in) {
99         mOpType = in.readInt();
100         mSrcs = in.readParcelable(FileOperation.class.getClassLoader());
101         mDestination = in.readParcelable(FileOperation.class.getClassLoader());
102     }
103 
104     public static class CopyOperation extends FileOperation {
CopyOperation(UrisSupplier srcs, DocumentStack destination)105         private CopyOperation(UrisSupplier srcs, DocumentStack destination) {
106             super(OPERATION_COPY, srcs, destination);
107         }
108 
109         @Override
toString()110         public String toString() {
111             StringBuilder builder = new StringBuilder();
112 
113             builder.append("CopyOperation{");
114             super.appendInfoTo(builder);
115             builder.append("}");
116 
117             return builder.toString();
118         }
119 
createJob(Context service, Job.Listener listener, String id, Features features)120         CopyJob createJob(Context service, Job.Listener listener, String id, Features features) {
121             return new CopyJob(service, listener, id, getDestination(), getSrc(), features);
122         }
123 
CopyOperation(Parcel in)124         private CopyOperation(Parcel in) {
125             super(in);
126         }
127 
128         public static final Parcelable.Creator<CopyOperation> CREATOR =
129                 new Parcelable.Creator<CopyOperation>() {
130 
131                     @Override
132                     public CopyOperation createFromParcel(Parcel source) {
133                         return new CopyOperation(source);
134                     }
135 
136                     @Override
137                     public CopyOperation[] newArray(int size) {
138                         return new CopyOperation[size];
139                     }
140                 };
141     }
142 
143     public static class CompressOperation extends FileOperation {
CompressOperation(UrisSupplier srcs, DocumentStack destination)144         private CompressOperation(UrisSupplier srcs, DocumentStack destination) {
145             super(OPERATION_COMPRESS, srcs, destination);
146         }
147 
148         @Override
toString()149         public String toString() {
150             StringBuilder builder = new StringBuilder();
151 
152             builder.append("CompressOperation{");
153             super.appendInfoTo(builder);
154             builder.append("}");
155 
156             return builder.toString();
157         }
158 
createJob(Context service, Job.Listener listener, String id, Features features)159         CopyJob createJob(Context service, Job.Listener listener, String id, Features features) {
160             return new CompressJob(service, listener, id, getDestination(), getSrc(), features);
161         }
162 
CompressOperation(Parcel in)163         private CompressOperation(Parcel in) {
164             super(in);
165         }
166 
167         public static final Parcelable.Creator<CompressOperation> CREATOR =
168                 new Parcelable.Creator<CompressOperation>() {
169 
170                     @Override
171                     public CompressOperation createFromParcel(Parcel source) {
172                         return new CompressOperation(source);
173                     }
174 
175                     @Override
176                     public CompressOperation[] newArray(int size) {
177                         return new CompressOperation[size];
178                     }
179                 };
180     }
181 
182     public static class ExtractOperation extends FileOperation {
ExtractOperation(UrisSupplier srcs, DocumentStack destination)183         private ExtractOperation(UrisSupplier srcs, DocumentStack destination) {
184             super(OPERATION_EXTRACT, srcs, destination);
185         }
186 
187         @Override
toString()188         public String toString() {
189             StringBuilder builder = new StringBuilder();
190 
191             builder.append("ExtractOperation{");
192             super.appendInfoTo(builder);
193             builder.append("}");
194 
195             return builder.toString();
196         }
197 
198         // TODO: Replace CopyJob with ExtractJob.
createJob(Context service, Job.Listener listener, String id, Features features)199         CopyJob createJob(Context service, Job.Listener listener, String id, Features features) {
200             return new CopyJob(service, listener, id, getDestination(), getSrc(), features);
201         }
202 
ExtractOperation(Parcel in)203         private ExtractOperation(Parcel in) {
204             super(in);
205         }
206 
207         public static final Parcelable.Creator<ExtractOperation> CREATOR =
208                 new Parcelable.Creator<ExtractOperation>() {
209 
210                     @Override
211                     public ExtractOperation createFromParcel(Parcel source) {
212                         return new ExtractOperation(source);
213                     }
214 
215                     @Override
216                     public ExtractOperation[] newArray(int size) {
217                         return new ExtractOperation[size];
218                     }
219                 };
220     }
221 
222     public static class MoveDeleteOperation extends FileOperation {
223         private final @Nullable Uri mSrcParent;
224 
MoveDeleteOperation(@pType int opType, UrisSupplier srcs, DocumentStack destination, @Nullable Uri srcParent)225         private MoveDeleteOperation(@OpType int opType, UrisSupplier srcs,
226                 DocumentStack destination, @Nullable Uri srcParent) {
227             super(opType, srcs, destination);
228 
229             mSrcParent = srcParent;
230         }
231 
232         @Override
createJob(Context service, Job.Listener listener, String id, Features features)233         Job createJob(Context service, Job.Listener listener, String id, Features features) {
234             switch(getOpType()) {
235                 case OPERATION_MOVE:
236                     return new MoveJob(service, listener, id, getDestination(), getSrc(),
237                             mSrcParent, features);
238                 case OPERATION_DELETE:
239                     return new DeleteJob(service, listener, id, getDestination(), getSrc(),
240                             mSrcParent, features);
241                 default:
242                     throw new UnsupportedOperationException("Unsupported op type: " + getOpType());
243             }
244         }
245 
246         @Override
toString()247         public String toString() {
248             StringBuilder builder = new StringBuilder();
249 
250             builder.append("MoveDeleteOperation{");
251             super.appendInfoTo(builder);
252             builder.append(", srcParent=").append(mSrcParent.toString());
253             builder.append("}");
254 
255             return builder.toString();
256         }
257 
258         @Override
writeToParcel(Parcel out, int flag)259         public void writeToParcel(Parcel out, int flag) {
260             super.writeToParcel(out, flag);
261             out.writeParcelable(mSrcParent, flag);
262         }
263 
MoveDeleteOperation(Parcel in)264         private MoveDeleteOperation(Parcel in) {
265             super(in);
266             mSrcParent = in.readParcelable(null);
267         }
268 
269         public static final Parcelable.Creator<MoveDeleteOperation> CREATOR =
270                 new Parcelable.Creator<MoveDeleteOperation>() {
271 
272 
273             @Override
274             public MoveDeleteOperation createFromParcel(Parcel source) {
275                 return new MoveDeleteOperation(source);
276             }
277 
278             @Override
279             public MoveDeleteOperation[] newArray(int size) {
280                 return new MoveDeleteOperation[size];
281             }
282         };
283     }
284 
285     public static class Builder {
286         private @OpType int mOpType;
287         private Uri mSrcParent;
288         private UrisSupplier mSrcs;
289         private DocumentStack mDestination;
290 
withOpType(@pType int opType)291         public Builder withOpType(@OpType int opType) {
292             mOpType = opType;
293             return this;
294         }
295 
withSrcParent(@ullable Uri srcParent)296         public Builder withSrcParent(@Nullable Uri srcParent) {
297             mSrcParent = srcParent;
298             return this;
299         }
300 
withSrcs(UrisSupplier srcs)301         public Builder withSrcs(UrisSupplier srcs) {
302             mSrcs = srcs;
303             return this;
304         }
305 
withDestination(DocumentStack destination)306         public Builder withDestination(DocumentStack destination) {
307             mDestination = destination;
308             return this;
309         }
310 
build()311         public FileOperation build() {
312             switch (mOpType) {
313                 case OPERATION_COPY:
314                     return new CopyOperation(mSrcs, mDestination);
315                 case OPERATION_COMPRESS:
316                     return new CompressOperation(mSrcs, mDestination);
317                 case OPERATION_EXTRACT:
318                     return new ExtractOperation(mSrcs, mDestination);
319                 case OPERATION_MOVE:
320                 case OPERATION_DELETE:
321                     return new MoveDeleteOperation(mOpType, mSrcs, mDestination, mSrcParent);
322                 default:
323                     throw new UnsupportedOperationException("Unsupported op type: " + mOpType);
324             }
325         }
326     }
327 }
328