115a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root/*
215a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root * Copyright (C) 2010 The Android Open Source Project
315a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root *
415a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root * Licensed under the Apache License, Version 2.0 (the "License");
515a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root * you may not use this file except in compliance with the License.
615a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root * You may obtain a copy of the License at
715a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root *
815a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root *      http://www.apache.org/licenses/LICENSE-2.0
915a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root *
1015a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root * Unless required by applicable law or agreed to in writing, software
1115a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root * distributed under the License is distributed on an "AS IS" BASIS,
1215a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1315a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root * See the License for the specific language governing permissions and
1415a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root * limitations under the License.
1515a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root */
1615a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root
177a96c39c510923ef73bbb06ab20109f0168b8eb1Jeff Sharkeypackage com.android.server.content;
18307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana
1957286f970641493b315b0b42aba7ac6b672cc8b8Alon Albertimport android.content.pm.PackageManager;
207a96c39c510923ef73bbb06ab20109f0168b8eb1Jeff Sharkeyimport android.content.SyncAdapterType;
217a96c39c510923ef73bbb06ab20109f0168b8eb1Jeff Sharkeyimport android.content.SyncAdaptersCache;
226ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkeyimport android.content.pm.RegisteredServicesCache.ServiceInfo;
2356dbf8f23677d28615e61ef2fbb0e738cca02528Matthew Williamsimport android.os.Bundle;
24918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintanaimport android.os.SystemClock;
25918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintanaimport android.text.format.DateUtils;
26307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintanaimport android.util.Log;
276ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkeyimport android.util.Pair;
286ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey
296ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkeyimport com.google.android.collect.Maps;
30307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana
31307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintanaimport java.util.ArrayList;
32a706e2fd0059b1bb86c487722dbc9fc0fda9c980Jeff Sharkeyimport java.util.Collection;
33918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintanaimport java.util.HashMap;
34307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintanaimport java.util.Iterator;
35918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintanaimport java.util.Map;
36307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana
37307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana/**
38a706e2fd0059b1bb86c487722dbc9fc0fda9c980Jeff Sharkey * Queue of pending sync operations. Not inherently thread safe, external
39a706e2fd0059b1bb86c487722dbc9fc0fda9c980Jeff Sharkey * callers are responsible for locking.
40307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana *
41307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana * @hide
42307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana */
43307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintanapublic class SyncQueue {
44307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana    private static final String TAG = "SyncManager";
456ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey    private final SyncStorageEngine mSyncStorageEngine;
466ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey    private final SyncAdaptersCache mSyncAdapters;
4757286f970641493b315b0b42aba7ac6b672cc8b8Alon Albert    private final PackageManager mPackageManager;
48307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana
49307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana    // A Map of SyncOperations operationKey -> SyncOperation that is designed for
50307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana    // quick lookup of an enqueued SyncOperation.
51a706e2fd0059b1bb86c487722dbc9fc0fda9c980Jeff Sharkey    private final HashMap<String, SyncOperation> mOperationsMap = Maps.newHashMap();
52307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana
5357286f970641493b315b0b42aba7ac6b672cc8b8Alon Albert    public SyncQueue(PackageManager packageManager, SyncStorageEngine syncStorageEngine,
5457286f970641493b315b0b42aba7ac6b672cc8b8Alon Albert            final SyncAdaptersCache syncAdapters) {
5557286f970641493b315b0b42aba7ac6b672cc8b8Alon Albert        mPackageManager = packageManager;
56307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana        mSyncStorageEngine = syncStorageEngine;
576ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey        mSyncAdapters = syncAdapters;
586ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey    }
596ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey
606ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey    public void addPendingOperations(int userId) {
616ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey        for (SyncStorageEngine.PendingOperation op : mSyncStorageEngine.getPendingOperations()) {
628ef2204c8f5f9744a2ff7abdbbf2d26a5ea02837Matthew Williams            final SyncStorageEngine.EndPoint info = op.target;
6356dbf8f23677d28615e61ef2fbb0e738cca02528Matthew Williams            if (info.userId != userId) continue;
6456dbf8f23677d28615e61ef2fbb0e738cca02528Matthew Williams
6556dbf8f23677d28615e61ef2fbb0e738cca02528Matthew Williams            final Pair<Long, Long> backoff = mSyncStorageEngine.getBackoff(info);
6656dbf8f23677d28615e61ef2fbb0e738cca02528Matthew Williams            SyncOperation operationToAdd;
6756dbf8f23677d28615e61ef2fbb0e738cca02528Matthew Williams            if (info.target_provider) {
6856dbf8f23677d28615e61ef2fbb0e738cca02528Matthew Williams                final ServiceInfo<SyncAdapterType> syncAdapterInfo = mSyncAdapters.getServiceInfo(
6956dbf8f23677d28615e61ef2fbb0e738cca02528Matthew Williams                        SyncAdapterType.newKey(info.provider, info.account.type), info.userId);
7056dbf8f23677d28615e61ef2fbb0e738cca02528Matthew Williams                if (syncAdapterInfo == null) {
7156dbf8f23677d28615e61ef2fbb0e738cca02528Matthew Williams                    if (Log.isLoggable(TAG, Log.VERBOSE)) {
728ef2204c8f5f9744a2ff7abdbbf2d26a5ea02837Matthew Williams                        Log.v(TAG, "Missing sync adapter info for authority " + op.target);
7356dbf8f23677d28615e61ef2fbb0e738cca02528Matthew Williams                    }
7456dbf8f23677d28615e61ef2fbb0e738cca02528Matthew Williams                    continue;
7556dbf8f23677d28615e61ef2fbb0e738cca02528Matthew Williams                }
7656dbf8f23677d28615e61ef2fbb0e738cca02528Matthew Williams                operationToAdd = new SyncOperation(
7756dbf8f23677d28615e61ef2fbb0e738cca02528Matthew Williams                        info.account, info.userId, op.reason, op.syncSource, info.provider,
7856dbf8f23677d28615e61ef2fbb0e738cca02528Matthew Williams                        op.extras,
796428046767ee4195617fb41b5639eefa2ca7a939Matthew Williams                        op.expedited ? -1 : 0 /* delay */,
8056dbf8f23677d28615e61ef2fbb0e738cca02528Matthew Williams                        0 /* flex */,
816428046767ee4195617fb41b5639eefa2ca7a939Matthew Williams                        backoff != null ? backoff.first : 0L,
8256dbf8f23677d28615e61ef2fbb0e738cca02528Matthew Williams                        mSyncStorageEngine.getDelayUntilTime(info),
8356dbf8f23677d28615e61ef2fbb0e738cca02528Matthew Williams                        syncAdapterInfo.type.allowParallelSyncs());
8456dbf8f23677d28615e61ef2fbb0e738cca02528Matthew Williams                operationToAdd.pendingOperation = op;
8556dbf8f23677d28615e61ef2fbb0e738cca02528Matthew Williams                add(operationToAdd, op);
8656dbf8f23677d28615e61ef2fbb0e738cca02528Matthew Williams            } else if (info.target_service) {
8756dbf8f23677d28615e61ef2fbb0e738cca02528Matthew Williams                try {
8856dbf8f23677d28615e61ef2fbb0e738cca02528Matthew Williams                    mPackageManager.getServiceInfo(info.service, 0);
8956dbf8f23677d28615e61ef2fbb0e738cca02528Matthew Williams                } catch (PackageManager.NameNotFoundException e) {
9056dbf8f23677d28615e61ef2fbb0e738cca02528Matthew Williams                    if (Log.isLoggable(TAG, Log.VERBOSE)) {
918ef2204c8f5f9744a2ff7abdbbf2d26a5ea02837Matthew Williams                        Log.w(TAG, "Missing sync service for authority " + op.target);
9256dbf8f23677d28615e61ef2fbb0e738cca02528Matthew Williams                    }
9356dbf8f23677d28615e61ef2fbb0e738cca02528Matthew Williams                    continue;
9456dbf8f23677d28615e61ef2fbb0e738cca02528Matthew Williams                }
9556dbf8f23677d28615e61ef2fbb0e738cca02528Matthew Williams                operationToAdd = new SyncOperation(
9656dbf8f23677d28615e61ef2fbb0e738cca02528Matthew Williams                        info.service, info.userId, op.reason, op.syncSource,
9756dbf8f23677d28615e61ef2fbb0e738cca02528Matthew Williams                        op.extras,
986428046767ee4195617fb41b5639eefa2ca7a939Matthew Williams                        op.expedited ? -1 : 0 /* delay */,
9956dbf8f23677d28615e61ef2fbb0e738cca02528Matthew Williams                        0 /* flex */,
10056dbf8f23677d28615e61ef2fbb0e738cca02528Matthew Williams                        backoff != null ? backoff.first : 0,
10156dbf8f23677d28615e61ef2fbb0e738cca02528Matthew Williams                        mSyncStorageEngine.getDelayUntilTime(info));
10256dbf8f23677d28615e61ef2fbb0e738cca02528Matthew Williams                operationToAdd.pendingOperation = op;
10356dbf8f23677d28615e61ef2fbb0e738cca02528Matthew Williams                add(operationToAdd, op);
1040c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana            }
105307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana        }
106307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana    }
107307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana
108307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana    public boolean add(SyncOperation operation) {
109307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana        return add(operation, null /* this is not coming from the database */);
110307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana    }
111307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana
112fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams    /**
113fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams     * Adds a SyncOperation to the queue and creates a PendingOperation object to track that sync.
114fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams     * If an operation is added that already exists, the existing operation is updated if the newly
115fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams     * added operation occurs before (or the interval overlaps).
116fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams     */
117307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana    private boolean add(SyncOperation operation,
118307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana            SyncStorageEngine.PendingOperation pop) {
119fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams        // If an operation with the same key exists and this one should run sooner/overlaps,
120fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams        // replace the run interval of the existing operation with this new one.
121fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams        // Complications: what if the existing operation is expedited but the new operation has an
122fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams        // earlier run time? Will not be a problem for periodic syncs (no expedited flag), and for
123fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams        // one-off syncs we only change it if the new sync is sooner.
124307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana        final String operationKey = operation.key;
125307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana        final SyncOperation existingOperation = mOperationsMap.get(operationKey);
126307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana
127307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana        if (existingOperation != null) {
128307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana            boolean changed = false;
129fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams            if (operation.compareTo(existingOperation) <= 0 ) {
130fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams                long newRunTime =
131fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams                        Math.min(existingOperation.latestRunTime, operation.latestRunTime);
132fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams                // Take smaller runtime.
133fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams                existingOperation.latestRunTime = newRunTime;
134fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams                // Take newer flextime.
135fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams                existingOperation.flexTime = operation.flexTime;
136fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams                changed = true;
137307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana            }
138307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana            return changed;
139307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana        }
140307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana
141307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana        operation.pendingOperation = pop;
142fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams        // Don't update the PendingOp if one already exists. This really is just a placeholder,
143fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams        // no actual scheduling info is placed here.
144307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana        if (operation.pendingOperation == null) {
14556dbf8f23677d28615e61ef2fbb0e738cca02528Matthew Williams            pop = mSyncStorageEngine.insertIntoPending(operation);
146307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana            if (pop == null) {
147307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana                throw new IllegalStateException("error adding pending sync operation "
148307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana                        + operation);
149307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana            }
150307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana            operation.pendingOperation = pop;
151307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana        }
152307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana
153307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana        mOperationsMap.put(operationKey, operation);
154307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana        return true;
155307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana    }
156307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana
15756dbf8f23677d28615e61ef2fbb0e738cca02528Matthew Williams    public void removeUserLocked(int userId) {
158135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani        ArrayList<SyncOperation> opsToRemove = new ArrayList<SyncOperation>();
159135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani        for (SyncOperation op : mOperationsMap.values()) {
16056dbf8f23677d28615e61ef2fbb0e738cca02528Matthew Williams            if (op.target.userId == userId) {
161135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani                opsToRemove.add(op);
162135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani            }
163135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani        }
16456dbf8f23677d28615e61ef2fbb0e738cca02528Matthew Williams            for (SyncOperation op : opsToRemove) {
16556dbf8f23677d28615e61ef2fbb0e738cca02528Matthew Williams                remove(op);
16656dbf8f23677d28615e61ef2fbb0e738cca02528Matthew Williams            }
167135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani    }
168135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani
169c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana    /**
170c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana     * Remove the specified operation if it is in the queue.
171c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana     * @param operation the operation to remove
172c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana     */
173307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana    public void remove(SyncOperation operation) {
1748ef2204c8f5f9744a2ff7abdbbf2d26a5ea02837Matthew Williams        boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
175307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana        SyncOperation operationToRemove = mOperationsMap.remove(operation.key);
17656dbf8f23677d28615e61ef2fbb0e738cca02528Matthew Williams        if (isLoggable) {
1778ef2204c8f5f9744a2ff7abdbbf2d26a5ea02837Matthew Williams            Log.v(TAG, "Attempting to remove: " + operation.key);
17856dbf8f23677d28615e61ef2fbb0e738cca02528Matthew Williams        }
179c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana        if (operationToRemove == null) {
18056dbf8f23677d28615e61ef2fbb0e738cca02528Matthew Williams            if (isLoggable) {
1818ef2204c8f5f9744a2ff7abdbbf2d26a5ea02837Matthew Williams                Log.v(TAG, "Could not find: " + operation.key);
18256dbf8f23677d28615e61ef2fbb0e738cca02528Matthew Williams            }
183c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana            return;
184c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana        }
185307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana        if (!mSyncStorageEngine.deleteFromPending(operationToRemove.pendingOperation)) {
186307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana            final String errorMessage = "unable to find pending row for " + operationToRemove;
187307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana            Log.e(TAG, errorMessage, new IllegalStateException(errorMessage));
188307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana        }
189307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana    }
190307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana
19156dbf8f23677d28615e61ef2fbb0e738cca02528Matthew Williams    /** Reset backoffs for all operations in the queue. */
19256dbf8f23677d28615e61ef2fbb0e738cca02528Matthew Williams    public void clearBackoffs() {
19356dbf8f23677d28615e61ef2fbb0e738cca02528Matthew Williams        for (SyncOperation op : mOperationsMap.values()) {
19456dbf8f23677d28615e61ef2fbb0e738cca02528Matthew Williams            op.backoff = 0L;
19556dbf8f23677d28615e61ef2fbb0e738cca02528Matthew Williams            op.updateEffectiveRunTime();
19656dbf8f23677d28615e61ef2fbb0e738cca02528Matthew Williams        }
19756dbf8f23677d28615e61ef2fbb0e738cca02528Matthew Williams    }
19856dbf8f23677d28615e61ef2fbb0e738cca02528Matthew Williams
19956dbf8f23677d28615e61ef2fbb0e738cca02528Matthew Williams    public void onBackoffChanged(SyncStorageEngine.EndPoint target, long backoff) {
2008ef2204c8f5f9744a2ff7abdbbf2d26a5ea02837Matthew Williams        // For each op that matches the target of the changed op, update its
201918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana        // backoff and effectiveStartTime
202307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana        for (SyncOperation op : mOperationsMap.values()) {
2038ef2204c8f5f9744a2ff7abdbbf2d26a5ea02837Matthew Williams            if (op.target.matchesSpec(target)) {
204918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                op.backoff = backoff;
205918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                op.updateEffectiveRunTime();
206307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana            }
207307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana        }
208307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana    }
209307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana
21056dbf8f23677d28615e61ef2fbb0e738cca02528Matthew Williams    public void onDelayUntilTimeChanged(SyncStorageEngine.EndPoint target, long delayUntil) {
2118ef2204c8f5f9744a2ff7abdbbf2d26a5ea02837Matthew Williams        // for each op that matches the target info of the provided op, change the delay time.
212918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana        for (SyncOperation op : mOperationsMap.values()) {
2138ef2204c8f5f9744a2ff7abdbbf2d26a5ea02837Matthew Williams            if (op.target.matchesSpec(target)) {
214918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                op.delayUntil = delayUntil;
215918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                op.updateEffectiveRunTime();
216918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana            }
217307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana        }
218307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana    }
219307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana
22056dbf8f23677d28615e61ef2fbb0e738cca02528Matthew Williams    /**
22156dbf8f23677d28615e61ef2fbb0e738cca02528Matthew Williams     * Remove all of the SyncOperations associated with a given target.
22256dbf8f23677d28615e61ef2fbb0e738cca02528Matthew Williams     *
22356dbf8f23677d28615e61ef2fbb0e738cca02528Matthew Williams     * @param info target object provided here can have null Account/provider. This is the case
22456dbf8f23677d28615e61ef2fbb0e738cca02528Matthew Williams     * where you want to remove all ops associated with a provider (null Account) or all ops
22556dbf8f23677d28615e61ef2fbb0e738cca02528Matthew Williams     * associated with an account (null provider).
22656dbf8f23677d28615e61ef2fbb0e738cca02528Matthew Williams     * @param extras option bundle to include to further specify which operation to remove. If this
22756dbf8f23677d28615e61ef2fbb0e738cca02528Matthew Williams     * bundle contains sync settings flags, they are ignored.
22856dbf8f23677d28615e61ef2fbb0e738cca02528Matthew Williams     */
22956dbf8f23677d28615e61ef2fbb0e738cca02528Matthew Williams    public void remove(final SyncStorageEngine.EndPoint info, Bundle extras) {
230307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana        Iterator<Map.Entry<String, SyncOperation>> entries = mOperationsMap.entrySet().iterator();
231307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana        while (entries.hasNext()) {
232307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana            Map.Entry<String, SyncOperation> entry = entries.next();
233307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana            SyncOperation syncOperation = entry.getValue();
23456dbf8f23677d28615e61ef2fbb0e738cca02528Matthew Williams            final SyncStorageEngine.EndPoint opInfo = syncOperation.target;
2358ef2204c8f5f9744a2ff7abdbbf2d26a5ea02837Matthew Williams            if (!opInfo.matchesSpec(info)) {
236c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana                continue;
237c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana            }
23856dbf8f23677d28615e61ef2fbb0e738cca02528Matthew Williams            if (extras != null
23956dbf8f23677d28615e61ef2fbb0e738cca02528Matthew Williams                    && !SyncManager.syncExtrasEquals(
24056dbf8f23677d28615e61ef2fbb0e738cca02528Matthew Williams                        syncOperation.extras,
24156dbf8f23677d28615e61ef2fbb0e738cca02528Matthew Williams                        extras,
24256dbf8f23677d28615e61ef2fbb0e738cca02528Matthew Williams                        false /* no config flags*/)) {
24304e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                continue;
24404e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            }
245307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana            entries.remove();
246307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana            if (!mSyncStorageEngine.deleteFromPending(syncOperation.pendingOperation)) {
247307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana                final String errorMessage = "unable to find pending row for " + syncOperation;
248307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana                Log.e(TAG, errorMessage, new IllegalStateException(errorMessage));
249307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana            }
250307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana        }
251307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana    }
252307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana
253a706e2fd0059b1bb86c487722dbc9fc0fda9c980Jeff Sharkey    public Collection<SyncOperation> getOperations() {
254a706e2fd0059b1bb86c487722dbc9fc0fda9c980Jeff Sharkey        return mOperationsMap.values();
255a706e2fd0059b1bb86c487722dbc9fc0fda9c980Jeff Sharkey    }
256a706e2fd0059b1bb86c487722dbc9fc0fda9c980Jeff Sharkey
257307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana    public void dump(StringBuilder sb) {
258918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana        final long now = SystemClock.elapsedRealtime();
259307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana        sb.append("SyncQueue: ").append(mOperationsMap.size()).append(" operation(s)\n");
260307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana        for (SyncOperation operation : mOperationsMap.values()) {
261918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana            sb.append("  ");
262918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana            if (operation.effectiveRunTime <= now) {
263918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                sb.append("READY");
264918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana            } else {
265918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                sb.append(DateUtils.formatElapsedTime((operation.effectiveRunTime - now) / 1000));
266918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana            }
267918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana            sb.append(" - ");
26857286f970641493b315b0b42aba7ac6b672cc8b8Alon Albert            sb.append(operation.dump(mPackageManager, false)).append("\n");
269307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana        }
270307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana    }
271307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana}
272