| /* | |
| * Copyright (C) 2016 The Android Open Source Project | |
| * | |
| * Licensed under the Apache License, Version 2.0 (the "License"); | |
| * you may not use this file except in compliance with the License. | |
| * You may obtain a copy of the License at | |
| * | |
| * http://www.apache.org/licenses/LICENSE-2.0 | |
| * | |
| * Unless required by applicable law or agreed to in writing, software | |
| * distributed under the License is distributed on an "AS IS" BASIS, | |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| * See the License for the specific language governing permissions and | |
| * limitations under the License. | |
| */ | |
| package com.android.documentsui.services; | |
| import static android.os.SystemClock.elapsedRealtime; | |
| import static com.android.documentsui.base.SharedMinimal.DEBUG; | |
| import static com.android.documentsui.services.FileOperationService.EXTRA_CANCEL; | |
| import static com.android.documentsui.services.FileOperationService.EXTRA_JOB_ID; | |
| import static com.android.documentsui.services.FileOperationService.EXTRA_OPERATION; | |
| import androidx.annotation.IntDef; | |
| import android.app.Activity; | |
| import android.content.Context; | |
| import android.content.Intent; | |
| import androidx.annotation.VisibleForTesting; | |
| import android.util.Log; | |
| import com.android.documentsui.services.FileOperationService.OpType; | |
| import java.lang.annotation.Retention; | |
| import java.lang.annotation.RetentionPolicy; | |
| import javax.annotation.Nullable; | |
| /** | |
| * Helper functions for starting various file operations. | |
| */ | |
| public final class FileOperations { | |
| private static final String TAG = "FileOperations"; | |
| private static final IdBuilder idBuilder = new IdBuilder(); | |
| private FileOperations() {} | |
| public static String createJobId() { | |
| return idBuilder.getNext(); | |
| } | |
| /** | |
| * Tries to start the activity. Returns the job id. | |
| * @param jobId Optional job id. If null, then it will be auto-generated. | |
| */ | |
| public static String start(Context context, FileOperation operation, Callback callback, | |
| @Nullable String jobId) { | |
| if (DEBUG) { | |
| Log.d(TAG, "Handling generic 'start' call."); | |
| } | |
| String newJobId = jobId != null ? jobId : createJobId(); | |
| Intent intent = createBaseIntent(context, newJobId, operation); | |
| if (callback != null) { | |
| callback.onOperationResult(Callback.STATUS_ACCEPTED, operation.getOpType(), | |
| operation.getSrc().getItemCount()); | |
| } | |
| context.startService(intent); | |
| return newJobId; | |
| } | |
| @VisibleForTesting | |
| public static void cancel(Activity activity, String jobId) { | |
| if (DEBUG) { | |
| Log.d(TAG, "Attempting to canceling operation: " + jobId); | |
| } | |
| Intent intent = new Intent(activity, FileOperationService.class); | |
| intent.putExtra(EXTRA_CANCEL, true); | |
| intent.putExtra(EXTRA_JOB_ID, jobId); | |
| activity.startService(intent); | |
| } | |
| /** | |
| * Starts the service for an operation. | |
| * | |
| * @param jobId A unique jobid for this job. | |
| * Use {@link #createJobId} if you don't have one handy. | |
| * @return Id of the job. | |
| */ | |
| public static Intent createBaseIntent( | |
| Context context, String jobId, FileOperation operation) { | |
| Intent intent = new Intent(context, FileOperationService.class); | |
| intent.putExtra(EXTRA_JOB_ID, jobId); | |
| intent.putExtra(EXTRA_OPERATION, operation); | |
| return intent; | |
| } | |
| private static final class IdBuilder { | |
| // Remember last job time so we can guard against collisions. | |
| private long mLastJobTime; | |
| // If we detect a collision, use subId to make distinct. | |
| private int mSubId; | |
| public synchronized String getNext() { | |
| long time = elapsedRealtime(); | |
| if (time == mLastJobTime) { | |
| mSubId++; | |
| } else { | |
| mSubId = 0; | |
| } | |
| mLastJobTime = time; | |
| return String.valueOf(mLastJobTime) + "-" + String.valueOf(mSubId); | |
| } | |
| } | |
| /** | |
| * A functional callback called when the file operation starts or fails to start. | |
| */ | |
| @FunctionalInterface | |
| public interface Callback { | |
| @Retention(RetentionPolicy.SOURCE) | |
| @IntDef({STATUS_ACCEPTED, STATUS_REJECTED}) | |
| @interface Status {} | |
| static final int STATUS_ACCEPTED = 0; | |
| static final int STATUS_REJECTED = 1; | |
| static final int STATUS_FAILED = 2; | |
| /** | |
| * Performs operation when the file operation starts or fails to start. | |
| * | |
| * @param status {@link Status} of this operation. | |
| * @param opType file operation type {@link OpType}. | |
| * @param docCount number of documents operated. | |
| */ | |
| void onOperationResult(@Status int status, @OpType int opType, int docCount); | |
| } | |
| } |