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