FileOperationService.java revision c83baa0574ee9e34c0e06bda1ff08928d880ee36
1c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay/* 2c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay * Copyright (C) 2015 The Android Open Source Project 3c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay * 4c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay * Licensed under the Apache License, Version 2.0 (the "License"); 5c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay * you may not use this file except in compliance with the License. 6c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay * You may obtain a copy of the License at 7c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay * 8c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay * http://www.apache.org/licenses/LICENSE-2.0 9c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay * 10c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay * Unless required by applicable law or agreed to in writing, software 11c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay * distributed under the License is distributed on an "AS IS" BASIS, 12c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay * See the License for the specific language governing permissions and 14c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay * limitations under the License. 15c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay */ 16c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay 17c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKaypackage com.android.documentsui.services; 18c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay 19c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKayimport static android.os.SystemClock.elapsedRealtime; 20c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKayimport static com.android.documentsui.Shared.DEBUG; 21c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKayimport static com.android.internal.util.Preconditions.checkArgument; 22c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKayimport static com.android.internal.util.Preconditions.checkNotNull; 23c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKayimport static com.android.internal.util.Preconditions.checkState; 24c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay 25c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKayimport android.annotation.IntDef; 26c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKayimport android.app.IntentService; 27c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKayimport android.app.NotificationManager; 28c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKayimport android.content.Intent; 29c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKayimport android.os.PowerManager; 30c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKayimport android.support.annotation.Nullable; 31c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKayimport android.support.annotation.VisibleForTesting; 32c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKayimport android.util.Log; 33c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay 34c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKayimport com.android.documentsui.Shared; 35c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKayimport com.android.documentsui.model.DocumentInfo; 36c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKayimport com.android.documentsui.model.DocumentStack; 37c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay 38c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKayimport com.google.common.base.Objects; 39c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay 40c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKayimport java.lang.annotation.Retention; 41c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKayimport java.lang.annotation.RetentionPolicy; 42c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKayimport java.util.ArrayList; 43c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKayimport java.util.List; 44c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay 45c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKaypublic class FileOperationService extends IntentService implements Job.Listener { 46c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay public static final String TAG = "FileOperationService"; 47c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay 48c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay public static final String EXTRA_JOB_ID = "com.android.documentsui.JOB_ID"; 49c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay public static final String EXTRA_OPERATION = "com.android.documentsui.OPERATION"; 50c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay public static final String EXTRA_CANCEL = "com.android.documentsui.CANCEL"; 51c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay public static final String EXTRA_SRC_LIST = "com.android.documentsui.SRC_LIST"; 52c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay public static final String EXTRA_FAILURE = "com.android.documentsui.FAILURE"; 53c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay 54c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay public static final int OPERATION_UNKNOWN = -1; 55c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay public static final int OPERATION_COPY = 1; 56c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay public static final int OPERATION_MOVE = 2; 57c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay public static final int OPERATION_DELETE = 3; 58c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay 59c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay @IntDef(flag = true, value = { 60c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay OPERATION_UNKNOWN, 61c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay OPERATION_COPY, 62c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay OPERATION_MOVE, 63c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay OPERATION_DELETE 64c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay }) 65c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay @Retention(RetentionPolicy.SOURCE) 66c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay public @interface OpType {} 67c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay 68c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay // TODO: Move it to a shared file when more operations are implemented. 69c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay public static final int FAILURE_COPY = 1; 70c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay 71c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay private PowerManager mPowerManager; 72c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay 73c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay private NotificationManager mNotificationManager; 74c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay 75c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay // TODO: Rework service to support multiple concurrent jobs. 76c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay private volatile Job mJob; 77c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay 78c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay // For testing only. 79c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay @Nullable private TestOnlyListener mJobFinishedListener; 80c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay 81c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay public FileOperationService() { 82c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay super("FileOperationService"); 83c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay } 84c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay 85c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay @Override 86c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay public void onCreate() { 87c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay super.onCreate(); 88c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay 89c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay if (DEBUG) Log.d(TAG, "Created."); 90c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay mPowerManager = getSystemService(PowerManager.class); 91c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay mNotificationManager = getSystemService(NotificationManager.class); 92c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay } 93c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay 94c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay @Override 95c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay public int onStartCommand(Intent intent, int flags, int startId) { 96c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay if (DEBUG) Log.d(TAG, "onStartCommand: " + intent); 97c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay if (intent.hasExtra(EXTRA_CANCEL)) { 98c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay handleCancel(intent); 99c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay return START_REDELIVER_INTENT; 100c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay } else { 101c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay return super.onStartCommand(intent, flags, startId); 102c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay } 103c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay } 104c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay 105c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay @Override 106c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay protected void onHandleIntent(Intent intent) { 107c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay if (DEBUG) Log.d(TAG, "onHandleIntent: " + intent); 108c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay 109c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay String jobId = intent.getStringExtra(EXTRA_JOB_ID); 110c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay @OpType int operationType = intent.getIntExtra(EXTRA_OPERATION, OPERATION_UNKNOWN); 111c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay checkArgument(jobId != null); 112c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay if (intent.hasExtra(EXTRA_CANCEL)) { 113c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay handleCancel(intent); 114c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay return; 115c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay } 116c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay 117c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay checkArgument(operationType != OPERATION_UNKNOWN); 118c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay 119c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay PowerManager.WakeLock wakeLock = mPowerManager.newWakeLock( 120c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay PowerManager.PARTIAL_WAKE_LOCK, TAG); 121c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay 122c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay ArrayList<DocumentInfo> srcs = intent.getParcelableArrayListExtra(EXTRA_SRC_LIST); 123c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay DocumentStack stack = intent.getParcelableExtra(Shared.EXTRA_STACK); 124c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay 125c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay Job job = createJob(operationType, jobId, srcs, stack); 126c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay 127c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay try { 128c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay wakeLock.acquire(); 129c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay 130c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay mNotificationManager.notify(job.id, 0, job.getSetupNotification()); 131c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay job.run(this); 132c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay 133c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay } catch (Exception e) { 134c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay // Catch-all to prevent any copy errors from wedging the app. 135c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay Log.e(TAG, "Exceptions occurred during copying", e); 136c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay } finally { 137c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay if (DEBUG) Log.d(TAG, "Cleaning up after copy"); 138c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay 139c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay job.cleanup(); 140c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay wakeLock.release(); 141c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay 142c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay // Dismiss the ongoing copy notification when the copy is done. 143c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay mNotificationManager.cancel(job.id, 0); 144c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay 145c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay if (job.failed()) { 146c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay Log.e(TAG, job.failedFiles.size() + " files failed to copy"); 147c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay mNotificationManager.notify(job.id, 0, job.getFailureNotification()); 148c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay } 149c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay 150c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay // TEST ONLY CODE...<raised eyebrows> 151c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay if (mJobFinishedListener != null) { 152c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay mJobFinishedListener.onFinished(job.failedFiles); 153c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay } 154c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay 155c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay deleteJob(job); 156c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay if (DEBUG) Log.d(TAG, "Done cleaning up"); 157c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay } 158c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay } 159c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay 160c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay /** 161c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay * Cancels the operation corresponding to job id, identified in "EXTRA_JOB_ID". 162c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay * 163c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay * @param intent The cancellation intent. 164c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay */ 165c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay private void handleCancel(Intent intent) { 166c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay checkArgument(intent.hasExtra(EXTRA_CANCEL)); 167c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay String jobId = checkNotNull(intent.getStringExtra(EXTRA_JOB_ID)); 168c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay 169c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay // Do nothing if the cancelled ID doesn't match the current job ID. This prevents racey 170c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay // cancellation requests from affecting unrelated copy jobs. However, if the current job ID 171c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay // is null, the service most likely crashed and was revived by the incoming cancel intent. 172c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay // In that case, always allow the cancellation to proceed. 173c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay if (mJob != null && Objects.equal(jobId, mJob.id)) { 174c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay mJob.cancel(); 175c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay } 176c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay 177c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay // Dismiss the progress notification here rather than in the copy loop. This preserves 178c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay // interactivity for the user in case the copy loop is stalled. 179c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay // Try to cancel it even if we don't have a job id...in case there is some sad 180c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay // orphan notification. 181c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay mNotificationManager.cancel(jobId, 0); 182c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay } 183c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay 184c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay public static String createJobId() { 185c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay return String.valueOf(elapsedRealtime()); 186c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay } 187c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay 188c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay Job createJob( 189c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay @OpType int operationType, String id, ArrayList<DocumentInfo> srcs, 190c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay DocumentStack stack) { 191c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay 192c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay checkState(mJob == null); 193c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay 194c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay switch (operationType) { 195c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay case OPERATION_COPY: 196c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay mJob = new CopyJob(this, getApplicationContext(), this, id, stack, srcs); 197c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay break; 198c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay case OPERATION_MOVE: 199c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay mJob = new MoveJob(this, getApplicationContext(), this, id, stack, srcs); 200c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay break; 201c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay case OPERATION_DELETE: 202c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay throw new UnsupportedOperationException(); 203c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay default: 204c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay throw new UnsupportedOperationException(); 205c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay } 206c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay 207c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay return checkNotNull(mJob); 208c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay } 209c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay 210c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay void deleteJob(Job job) { 211c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay checkArgument(job == mJob); 212c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay mJob = null; 213c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay } 214c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay 215c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay @Override 216c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay public void onProgress(CopyJob job) { 217c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay if (DEBUG) Log.d(TAG, "On copy progress..."); 218c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay mNotificationManager.notify(job.id, 0, job.getProgressNotification()); 219c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay } 220c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay 221c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay @Override 222c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay public void onProgress(MoveJob job) { 223c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay if (DEBUG) Log.d(TAG, "On move progress..."); 224c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay mNotificationManager.notify(job.id, 0, job.getProgressNotification()); 225c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay } 226c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay 227c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay /** 228c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay * Sets a callback to be run when the next run job is finished. 229c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay * This is test ONLY instrumentation. The alternative is for us to add 230c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay * broadcast intents SOLELY for the purpose of testing. 231c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay * @param listener 232c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay */ 233c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay @VisibleForTesting 234c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay void addFinishedListener(TestOnlyListener listener) { 235c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay this.mJobFinishedListener = listener; 236c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay } 237c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay 238c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay /** 239c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay * Only used for testing. Is that obvious enough? 240c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay */ 241c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay @VisibleForTesting 242c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay interface TestOnlyListener { 243c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay void onFinished(List<DocumentInfo> failed); 244c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay } 245c83baa0574ee9e34c0e06bda1ff08928d880ee36Steve McKay} 246