14833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan/*
24833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan * Copyright (C) 2016 The Android Open Source Project
34833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan *
44833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan * Licensed under the Apache License, Version 2.0 (the "License");
54833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan * you may not use this file except in compliance with the License.
64833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan * You may obtain a copy of the License at
74833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan *
84833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan *      http://www.apache.org/licenses/LICENSE-2.0
94833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan *
104833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan * Unless required by applicable law or agreed to in writing, software
114833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan * distributed under the License is distributed on an "AS IS" BASIS,
124833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
134833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan * See the License for the specific language governing permissions and
144833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan * limitations under the License.
154833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan */
164833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan
174833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tanpackage com.android.documentsui.services;
184833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan
194833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tanimport static com.android.documentsui.services.FileOperationService.OPERATION_COPY;
20bc7eb5fc39b5555eedc7d7b3591687343ecda18dTomasz Mikolajewskiimport static com.android.documentsui.services.FileOperationService.OPERATION_COMPRESS;
21bc7eb5fc39b5555eedc7d7b3591687343ecda18dTomasz Mikolajewskiimport static com.android.documentsui.services.FileOperationService.OPERATION_EXTRACT;
224833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tanimport static com.android.documentsui.services.FileOperationService.OPERATION_DELETE;
234833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tanimport static com.android.documentsui.services.FileOperationService.OPERATION_MOVE;
244833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tanimport static com.android.documentsui.services.FileOperationService.OPERATION_UNKNOWN;
254833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan
264833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tanimport android.content.Context;
274833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tanimport android.net.Uri;
280d83d32b66332034b17b327352693b125e9b3a05Tomasz Mikolajewskiimport android.os.Handler;
290d83d32b66332034b17b327352693b125e9b3a05Tomasz Mikolajewskiimport android.os.Looper;
300d83d32b66332034b17b327352693b125e9b3a05Tomasz Mikolajewskiimport android.os.Message;
310d83d32b66332034b17b327352693b125e9b3a05Tomasz Mikolajewskiimport android.os.Messenger;
324833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tanimport android.os.Parcel;
334833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tanimport android.os.Parcelable;
344833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tanimport android.support.annotation.VisibleForTesting;
354833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan
36d080506e3aa8547605cd4783eb660775d7d2b8eeSteve McKayimport com.android.documentsui.base.DocumentStack;
373a968cd43ba31c7a2a65ba747a36079d605027dfGarfield Tanimport com.android.documentsui.base.Features;
389666ce691a4d45344460f17cec3577dbe075235aGarfield, Tanimport com.android.documentsui.clipping.UrisSupplier;
394833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tanimport com.android.documentsui.services.FileOperationService.OpType;
404833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan
410d83d32b66332034b17b327352693b125e9b3a05Tomasz Mikolajewskiimport java.util.ArrayList;
420d83d32b66332034b17b327352693b125e9b3a05Tomasz Mikolajewskiimport java.util.List;
430d83d32b66332034b17b327352693b125e9b3a05Tomasz Mikolajewski
4403a3a39d1cb62aa41bdd40e49ee26c7aabc5ada1Garfield Tanimport javax.annotation.Nullable;
4503a3a39d1cb62aa41bdd40e49ee26c7aabc5ada1Garfield Tan
464833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan/**
474833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan * FileOperation describes a file operation, such as move/copy/delete etc.
484833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan */
494833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tanpublic abstract class FileOperation implements Parcelable {
504833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan    private final @OpType int mOpType;
514833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan
524833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan    private final UrisSupplier mSrcs;
530d83d32b66332034b17b327352693b125e9b3a05Tomasz Mikolajewski    private final List<Handler.Callback> mMessageListeners = new ArrayList<>();
544833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan    private DocumentStack mDestination;
550d83d32b66332034b17b327352693b125e9b3a05Tomasz Mikolajewski    private Messenger mMessenger = new Messenger(
560d83d32b66332034b17b327352693b125e9b3a05Tomasz Mikolajewski            new Handler(Looper.getMainLooper(), this::onMessage));
574833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan
584833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan    @VisibleForTesting
594833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan    FileOperation(@OpType int opType, UrisSupplier srcs, DocumentStack destination) {
604833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan        assert(opType != OPERATION_UNKNOWN);
614833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan        assert(srcs.getItemCount() > 0);
624833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan
634833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan        mOpType = opType;
644833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan        mSrcs = srcs;
654833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan        mDestination = destination;
664833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan    }
674833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan
684833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan    @Override
694833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan    public int describeContents() {
704833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan        return 0;
714833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan    }
724833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan
734833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan    public @OpType int getOpType() {
744833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan        return mOpType;
754833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan    }
764833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan
774833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan    public UrisSupplier getSrc() {
784833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan        return mSrcs;
794833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan    }
804833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan
814833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan    public DocumentStack getDestination() {
824833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan        return mDestination;
834833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan    }
844833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan
850d83d32b66332034b17b327352693b125e9b3a05Tomasz Mikolajewski    public Messenger getMessenger() {
860d83d32b66332034b17b327352693b125e9b3a05Tomasz Mikolajewski        return mMessenger;
870d83d32b66332034b17b327352693b125e9b3a05Tomasz Mikolajewski    }
880d83d32b66332034b17b327352693b125e9b3a05Tomasz Mikolajewski
894833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan    public void setDestination(DocumentStack destination) {
904833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan        mDestination = destination;
914833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan    }
924833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan
93b7e5f6b55f5075e4752bd94586211fae9af2bae0Garfield, Tan    public void dispose() {
94b7e5f6b55f5075e4752bd94586211fae9af2bae0Garfield, Tan        mSrcs.dispose();
954833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan    }
964833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan
973a968cd43ba31c7a2a65ba747a36079d605027dfGarfield Tan    abstract Job createJob(Context service, Job.Listener listener, String id, Features features);
984833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan
994833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan    private void appendInfoTo(StringBuilder builder) {
1004833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan        builder.append("opType=").append(mOpType);
1014833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan        builder.append(", srcs=").append(mSrcs.toString());
1024833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan        builder.append(", destination=").append(mDestination.toString());
1034833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan    }
1044833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan
1054833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan    @Override
1064833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan    public void writeToParcel(Parcel out, int flag) {
1074833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan        out.writeInt(mOpType);
1084833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan        out.writeParcelable(mSrcs, flag);
1094833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan        out.writeParcelable(mDestination, flag);
1100d83d32b66332034b17b327352693b125e9b3a05Tomasz Mikolajewski        out.writeParcelable(mMessenger, flag);
1114833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan    }
1124833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan
1134833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan    private FileOperation(Parcel in) {
1144833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan        mOpType = in.readInt();
1154833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan        mSrcs = in.readParcelable(FileOperation.class.getClassLoader());
1164833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan        mDestination = in.readParcelable(FileOperation.class.getClassLoader());
1170d83d32b66332034b17b327352693b125e9b3a05Tomasz Mikolajewski        mMessenger = in.readParcelable(FileOperation.class.getClassLoader());
1184833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan    }
1194833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan
1204833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan    public static class CopyOperation extends FileOperation {
1214833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan        private CopyOperation(UrisSupplier srcs, DocumentStack destination) {
1224833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan            super(OPERATION_COPY, srcs, destination);
1234833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan        }
1244833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan
1254833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan        @Override
1264833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan        public String toString() {
1274833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan            StringBuilder builder = new StringBuilder();
1284833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan
1294833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan            builder.append("CopyOperation{");
1304833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan            super.appendInfoTo(builder);
1314833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan            builder.append("}");
1324833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan
1334833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan            return builder.toString();
1344833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan        }
1354833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan
1363a968cd43ba31c7a2a65ba747a36079d605027dfGarfield Tan        CopyJob createJob(Context service, Job.Listener listener, String id, Features features) {
1373a968cd43ba31c7a2a65ba747a36079d605027dfGarfield Tan            return new CopyJob(
1383a968cd43ba31c7a2a65ba747a36079d605027dfGarfield Tan                    service, listener, id, getDestination(), getSrc(), getMessenger(), features);
1394833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan        }
1404833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan
1414833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan        private CopyOperation(Parcel in) {
1424833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan            super(in);
1434833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan        }
1444833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan
1454833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan        public static final Parcelable.Creator<CopyOperation> CREATOR =
1464833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan                new Parcelable.Creator<CopyOperation>() {
1474833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan
1484833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan                    @Override
1494833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan                    public CopyOperation createFromParcel(Parcel source) {
1504833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan                        return new CopyOperation(source);
1514833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan                    }
1524833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan
1534833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan                    @Override
1544833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan                    public CopyOperation[] newArray(int size) {
1554833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan                        return new CopyOperation[size];
1564833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan                    }
1574833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan                };
1584833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan    }
1594833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan
160bc7eb5fc39b5555eedc7d7b3591687343ecda18dTomasz Mikolajewski    public static class CompressOperation extends FileOperation {
161bc7eb5fc39b5555eedc7d7b3591687343ecda18dTomasz Mikolajewski        private CompressOperation(UrisSupplier srcs, DocumentStack destination) {
162bc7eb5fc39b5555eedc7d7b3591687343ecda18dTomasz Mikolajewski            super(OPERATION_COMPRESS, srcs, destination);
163bc7eb5fc39b5555eedc7d7b3591687343ecda18dTomasz Mikolajewski        }
164bc7eb5fc39b5555eedc7d7b3591687343ecda18dTomasz Mikolajewski
165bc7eb5fc39b5555eedc7d7b3591687343ecda18dTomasz Mikolajewski        @Override
166bc7eb5fc39b5555eedc7d7b3591687343ecda18dTomasz Mikolajewski        public String toString() {
167bc7eb5fc39b5555eedc7d7b3591687343ecda18dTomasz Mikolajewski            StringBuilder builder = new StringBuilder();
168bc7eb5fc39b5555eedc7d7b3591687343ecda18dTomasz Mikolajewski
169bc7eb5fc39b5555eedc7d7b3591687343ecda18dTomasz Mikolajewski            builder.append("CompressOperation{");
170bc7eb5fc39b5555eedc7d7b3591687343ecda18dTomasz Mikolajewski            super.appendInfoTo(builder);
171bc7eb5fc39b5555eedc7d7b3591687343ecda18dTomasz Mikolajewski            builder.append("}");
172bc7eb5fc39b5555eedc7d7b3591687343ecda18dTomasz Mikolajewski
173bc7eb5fc39b5555eedc7d7b3591687343ecda18dTomasz Mikolajewski            return builder.toString();
174bc7eb5fc39b5555eedc7d7b3591687343ecda18dTomasz Mikolajewski        }
175bc7eb5fc39b5555eedc7d7b3591687343ecda18dTomasz Mikolajewski
1763a968cd43ba31c7a2a65ba747a36079d605027dfGarfield Tan        CopyJob createJob(Context service, Job.Listener listener, String id, Features features) {
1770d83d32b66332034b17b327352693b125e9b3a05Tomasz Mikolajewski            return new CompressJob(service, listener, id, getDestination(), getSrc(),
1783a968cd43ba31c7a2a65ba747a36079d605027dfGarfield Tan                    getMessenger(), features);
179bc7eb5fc39b5555eedc7d7b3591687343ecda18dTomasz Mikolajewski        }
180bc7eb5fc39b5555eedc7d7b3591687343ecda18dTomasz Mikolajewski
181bc7eb5fc39b5555eedc7d7b3591687343ecda18dTomasz Mikolajewski        private CompressOperation(Parcel in) {
182bc7eb5fc39b5555eedc7d7b3591687343ecda18dTomasz Mikolajewski            super(in);
183bc7eb5fc39b5555eedc7d7b3591687343ecda18dTomasz Mikolajewski        }
184bc7eb5fc39b5555eedc7d7b3591687343ecda18dTomasz Mikolajewski
185bc7eb5fc39b5555eedc7d7b3591687343ecda18dTomasz Mikolajewski        public static final Parcelable.Creator<CompressOperation> CREATOR =
186bc7eb5fc39b5555eedc7d7b3591687343ecda18dTomasz Mikolajewski                new Parcelable.Creator<CompressOperation>() {
187bc7eb5fc39b5555eedc7d7b3591687343ecda18dTomasz Mikolajewski
188bc7eb5fc39b5555eedc7d7b3591687343ecda18dTomasz Mikolajewski                    @Override
189bc7eb5fc39b5555eedc7d7b3591687343ecda18dTomasz Mikolajewski                    public CompressOperation createFromParcel(Parcel source) {
190bc7eb5fc39b5555eedc7d7b3591687343ecda18dTomasz Mikolajewski                        return new CompressOperation(source);
191bc7eb5fc39b5555eedc7d7b3591687343ecda18dTomasz Mikolajewski                    }
192bc7eb5fc39b5555eedc7d7b3591687343ecda18dTomasz Mikolajewski
193bc7eb5fc39b5555eedc7d7b3591687343ecda18dTomasz Mikolajewski                    @Override
194bc7eb5fc39b5555eedc7d7b3591687343ecda18dTomasz Mikolajewski                    public CompressOperation[] newArray(int size) {
195bc7eb5fc39b5555eedc7d7b3591687343ecda18dTomasz Mikolajewski                        return new CompressOperation[size];
196bc7eb5fc39b5555eedc7d7b3591687343ecda18dTomasz Mikolajewski                    }
197bc7eb5fc39b5555eedc7d7b3591687343ecda18dTomasz Mikolajewski                };
198bc7eb5fc39b5555eedc7d7b3591687343ecda18dTomasz Mikolajewski    }
199bc7eb5fc39b5555eedc7d7b3591687343ecda18dTomasz Mikolajewski
200bc7eb5fc39b5555eedc7d7b3591687343ecda18dTomasz Mikolajewski    public static class ExtractOperation extends FileOperation {
201bc7eb5fc39b5555eedc7d7b3591687343ecda18dTomasz Mikolajewski        private ExtractOperation(UrisSupplier srcs, DocumentStack destination) {
202bc7eb5fc39b5555eedc7d7b3591687343ecda18dTomasz Mikolajewski            super(OPERATION_EXTRACT, srcs, destination);
203bc7eb5fc39b5555eedc7d7b3591687343ecda18dTomasz Mikolajewski        }
204bc7eb5fc39b5555eedc7d7b3591687343ecda18dTomasz Mikolajewski
205bc7eb5fc39b5555eedc7d7b3591687343ecda18dTomasz Mikolajewski        @Override
206bc7eb5fc39b5555eedc7d7b3591687343ecda18dTomasz Mikolajewski        public String toString() {
207bc7eb5fc39b5555eedc7d7b3591687343ecda18dTomasz Mikolajewski            StringBuilder builder = new StringBuilder();
208bc7eb5fc39b5555eedc7d7b3591687343ecda18dTomasz Mikolajewski
209bc7eb5fc39b5555eedc7d7b3591687343ecda18dTomasz Mikolajewski            builder.append("ExtractOperation{");
210bc7eb5fc39b5555eedc7d7b3591687343ecda18dTomasz Mikolajewski            super.appendInfoTo(builder);
211bc7eb5fc39b5555eedc7d7b3591687343ecda18dTomasz Mikolajewski            builder.append("}");
212bc7eb5fc39b5555eedc7d7b3591687343ecda18dTomasz Mikolajewski
213bc7eb5fc39b5555eedc7d7b3591687343ecda18dTomasz Mikolajewski            return builder.toString();
214bc7eb5fc39b5555eedc7d7b3591687343ecda18dTomasz Mikolajewski        }
215bc7eb5fc39b5555eedc7d7b3591687343ecda18dTomasz Mikolajewski
216bc7eb5fc39b5555eedc7d7b3591687343ecda18dTomasz Mikolajewski        // TODO: Replace CopyJob with ExtractJob.
2173a968cd43ba31c7a2a65ba747a36079d605027dfGarfield Tan        CopyJob createJob(Context service, Job.Listener listener, String id, Features features) {
2183a968cd43ba31c7a2a65ba747a36079d605027dfGarfield Tan            return new CopyJob(
2193a968cd43ba31c7a2a65ba747a36079d605027dfGarfield Tan                    service, listener, id, getDestination(), getSrc(), getMessenger(), features);
220bc7eb5fc39b5555eedc7d7b3591687343ecda18dTomasz Mikolajewski        }
221bc7eb5fc39b5555eedc7d7b3591687343ecda18dTomasz Mikolajewski
222bc7eb5fc39b5555eedc7d7b3591687343ecda18dTomasz Mikolajewski        private ExtractOperation(Parcel in) {
223bc7eb5fc39b5555eedc7d7b3591687343ecda18dTomasz Mikolajewski            super(in);
224bc7eb5fc39b5555eedc7d7b3591687343ecda18dTomasz Mikolajewski        }
225bc7eb5fc39b5555eedc7d7b3591687343ecda18dTomasz Mikolajewski
226bc7eb5fc39b5555eedc7d7b3591687343ecda18dTomasz Mikolajewski        public static final Parcelable.Creator<ExtractOperation> CREATOR =
227bc7eb5fc39b5555eedc7d7b3591687343ecda18dTomasz Mikolajewski                new Parcelable.Creator<ExtractOperation>() {
228bc7eb5fc39b5555eedc7d7b3591687343ecda18dTomasz Mikolajewski
229bc7eb5fc39b5555eedc7d7b3591687343ecda18dTomasz Mikolajewski                    @Override
230bc7eb5fc39b5555eedc7d7b3591687343ecda18dTomasz Mikolajewski                    public ExtractOperation createFromParcel(Parcel source) {
231bc7eb5fc39b5555eedc7d7b3591687343ecda18dTomasz Mikolajewski                        return new ExtractOperation(source);
232bc7eb5fc39b5555eedc7d7b3591687343ecda18dTomasz Mikolajewski                    }
233bc7eb5fc39b5555eedc7d7b3591687343ecda18dTomasz Mikolajewski
234bc7eb5fc39b5555eedc7d7b3591687343ecda18dTomasz Mikolajewski                    @Override
235bc7eb5fc39b5555eedc7d7b3591687343ecda18dTomasz Mikolajewski                    public ExtractOperation[] newArray(int size) {
236bc7eb5fc39b5555eedc7d7b3591687343ecda18dTomasz Mikolajewski                        return new ExtractOperation[size];
237bc7eb5fc39b5555eedc7d7b3591687343ecda18dTomasz Mikolajewski                    }
238bc7eb5fc39b5555eedc7d7b3591687343ecda18dTomasz Mikolajewski                };
239bc7eb5fc39b5555eedc7d7b3591687343ecda18dTomasz Mikolajewski    }
240bc7eb5fc39b5555eedc7d7b3591687343ecda18dTomasz Mikolajewski
2414833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan    public static class MoveDeleteOperation extends FileOperation {
24203a3a39d1cb62aa41bdd40e49ee26c7aabc5ada1Garfield Tan        private final @Nullable Uri mSrcParent;
2434833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan
24403a3a39d1cb62aa41bdd40e49ee26c7aabc5ada1Garfield Tan        private MoveDeleteOperation(@OpType int opType, UrisSupplier srcs,
24503a3a39d1cb62aa41bdd40e49ee26c7aabc5ada1Garfield Tan                DocumentStack destination, @Nullable Uri srcParent) {
2464833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan            super(opType, srcs, destination);
2474833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan
2484833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan            mSrcParent = srcParent;
2494833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan        }
2504833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan
2514833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan        @Override
2523a968cd43ba31c7a2a65ba747a36079d605027dfGarfield Tan        Job createJob(Context service, Job.Listener listener, String id, Features features) {
2534833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan            switch(getOpType()) {
2544833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan                case OPERATION_MOVE:
2554833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan                    return new MoveJob(
2560d83d32b66332034b17b327352693b125e9b3a05Tomasz Mikolajewski                            service, listener, id, getDestination(), getSrc(), mSrcParent,
2573a968cd43ba31c7a2a65ba747a36079d605027dfGarfield Tan                            getMessenger(), features);
2584833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan                case OPERATION_DELETE:
2593a968cd43ba31c7a2a65ba747a36079d605027dfGarfield Tan                    return new DeleteJob(service, listener, id, getDestination(), getSrc(),
2603a968cd43ba31c7a2a65ba747a36079d605027dfGarfield Tan                            mSrcParent, features);
2614833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan                default:
2624833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan                    throw new UnsupportedOperationException("Unsupported op type: " + getOpType());
2634833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan            }
2644833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan        }
2654833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan
2664833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan        @Override
2674833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan        public String toString() {
2684833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan            StringBuilder builder = new StringBuilder();
2694833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan
2704833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan            builder.append("MoveDeleteOperation{");
2714833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan            super.appendInfoTo(builder);
2724833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan            builder.append(", srcParent=").append(mSrcParent.toString());
2734833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan            builder.append("}");
2744833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan
2754833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan            return builder.toString();
2764833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan        }
2774833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan
2784833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan        @Override
2794833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan        public void writeToParcel(Parcel out, int flag) {
2804833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan            super.writeToParcel(out, flag);
2814833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan            out.writeParcelable(mSrcParent, flag);
2824833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan        }
2834833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan
2844833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan        private MoveDeleteOperation(Parcel in) {
2854833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan            super(in);
2864833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan            mSrcParent = in.readParcelable(null);
2874833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan        }
2884833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan
2894833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan        public static final Parcelable.Creator<MoveDeleteOperation> CREATOR =
2904833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan                new Parcelable.Creator<MoveDeleteOperation>() {
2914833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan
2924833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan
2934833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan            @Override
2944833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan            public MoveDeleteOperation createFromParcel(Parcel source) {
2954833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan                return new MoveDeleteOperation(source);
2964833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan            }
2974833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan
2984833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan            @Override
2994833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan            public MoveDeleteOperation[] newArray(int size) {
3004833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan                return new MoveDeleteOperation[size];
3014833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan            }
3024833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan        };
3034833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan    }
3044833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan
3054833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan    public static class Builder {
3064833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan        private @OpType int mOpType;
3074833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan        private Uri mSrcParent;
3084833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan        private UrisSupplier mSrcs;
3094833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan        private DocumentStack mDestination;
3104833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan
3114833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan        public Builder withOpType(@OpType int opType) {
3124833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan            mOpType = opType;
3134833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan            return this;
3144833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan        }
3154833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan
31603a3a39d1cb62aa41bdd40e49ee26c7aabc5ada1Garfield Tan        public Builder withSrcParent(@Nullable Uri srcParent) {
3174833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan            mSrcParent = srcParent;
3184833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan            return this;
3194833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan        }
3204833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan
3214833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan        public Builder withSrcs(UrisSupplier srcs) {
3224833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan            mSrcs = srcs;
3234833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan            return this;
3244833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan        }
3254833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan
3264833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan        public Builder withDestination(DocumentStack destination) {
3274833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan            mDestination = destination;
3284833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan            return this;
3294833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan        }
3304833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan
3314833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan        public FileOperation build() {
3324833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan            switch (mOpType) {
3334833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan                case OPERATION_COPY:
3344833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan                    return new CopyOperation(mSrcs, mDestination);
335bc7eb5fc39b5555eedc7d7b3591687343ecda18dTomasz Mikolajewski                case OPERATION_COMPRESS:
336bc7eb5fc39b5555eedc7d7b3591687343ecda18dTomasz Mikolajewski                    return new CompressOperation(mSrcs, mDestination);
337bc7eb5fc39b5555eedc7d7b3591687343ecda18dTomasz Mikolajewski                case OPERATION_EXTRACT:
338bc7eb5fc39b5555eedc7d7b3591687343ecda18dTomasz Mikolajewski                    return new ExtractOperation(mSrcs, mDestination);
3394833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan                case OPERATION_MOVE:
3404833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan                case OPERATION_DELETE:
34103a3a39d1cb62aa41bdd40e49ee26c7aabc5ada1Garfield Tan                    return new MoveDeleteOperation(mOpType, mSrcs, mDestination, mSrcParent);
3424833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan                default:
3434833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan                    throw new UnsupportedOperationException("Unsupported op type: " + mOpType);
3444833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan            }
3454833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan        }
3464833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan    }
3470d83d32b66332034b17b327352693b125e9b3a05Tomasz Mikolajewski
3480d83d32b66332034b17b327352693b125e9b3a05Tomasz Mikolajewski    boolean onMessage(Message message) {
3490d83d32b66332034b17b327352693b125e9b3a05Tomasz Mikolajewski        for (Handler.Callback listener : mMessageListeners) {
3500d83d32b66332034b17b327352693b125e9b3a05Tomasz Mikolajewski            if (listener.handleMessage(message)) {
3510d83d32b66332034b17b327352693b125e9b3a05Tomasz Mikolajewski              return true;
3520d83d32b66332034b17b327352693b125e9b3a05Tomasz Mikolajewski            }
3530d83d32b66332034b17b327352693b125e9b3a05Tomasz Mikolajewski        }
3540d83d32b66332034b17b327352693b125e9b3a05Tomasz Mikolajewski        return false;
3550d83d32b66332034b17b327352693b125e9b3a05Tomasz Mikolajewski    }
3560d83d32b66332034b17b327352693b125e9b3a05Tomasz Mikolajewski
3570d83d32b66332034b17b327352693b125e9b3a05Tomasz Mikolajewski    /**
3580d83d32b66332034b17b327352693b125e9b3a05Tomasz Mikolajewski     * Registers a listener for messages from the service job.
3590d83d32b66332034b17b327352693b125e9b3a05Tomasz Mikolajewski     *
3600d83d32b66332034b17b327352693b125e9b3a05Tomasz Mikolajewski     * Callbacks must return true if the message is handled, and false if not.
3610d83d32b66332034b17b327352693b125e9b3a05Tomasz Mikolajewski     * Once handled, consecutive callbacks will not be called.
3620d83d32b66332034b17b327352693b125e9b3a05Tomasz Mikolajewski     */
3630d83d32b66332034b17b327352693b125e9b3a05Tomasz Mikolajewski    public void addMessageListener(Handler.Callback handler) {
3640d83d32b66332034b17b327352693b125e9b3a05Tomasz Mikolajewski        mMessageListeners.add(handler);
3650d83d32b66332034b17b327352693b125e9b3a05Tomasz Mikolajewski    }
3660d83d32b66332034b17b327352693b125e9b3a05Tomasz Mikolajewski
3670d83d32b66332034b17b327352693b125e9b3a05Tomasz Mikolajewski    public void removeMessageListener(Handler.Callback handler) {
3680d83d32b66332034b17b327352693b125e9b3a05Tomasz Mikolajewski        mMessageListeners.remove(handler);
3690d83d32b66332034b17b327352693b125e9b3a05Tomasz Mikolajewski    }
3704833477d7d42fa79ee42956bae4aebad77074e4bGarfield, Tan}
371