1d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd/* 2d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Copyright (C) 2015 The Android Open Source Project 3d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * 4d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Licensed under the Apache License, Version 2.0 (the "License"); 5d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * you may not use this file except in compliance with the License. 6d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * You may obtain a copy of the License at 7d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * 8d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * http://www.apache.org/licenses/LICENSE-2.0 9d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * 10d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Unless required by applicable law or agreed to in writing, software 11d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * distributed under the License is distributed on an "AS IS" BASIS, 12d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * See the License for the specific language governing permissions and 14d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * limitations under the License. 15d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 16d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 17d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddpackage com.android.messaging.datamodel.action; 18d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 19d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.os.Handler; 20d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.support.v4.util.SimpleArrayMap; 21d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.text.TextUtils; 22d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 23d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.util.Assert.RunsOnAnyThread; 24d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.util.Assert.RunsOnMainThread; 25d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.util.LogUtil; 26d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.util.ThreadUtil; 27d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.google.common.annotations.VisibleForTesting; 28d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 29d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport java.text.SimpleDateFormat; 30d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport java.util.Date; 31d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport java.util.TimeZone; 32d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 33d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd/** 34d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Base class for action monitors 35d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Actions come in various flavors but 36d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * o) Fire and forget - no monitor 37d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * o) Immediate local processing only - will trigger ActionCompletedListener when done 38d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * o) Background worker processing only - will trigger ActionCompletedListener when done 39d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * o) Immediate local processing followed by background work followed by more local processing 40d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * - will trigger ActionExecutedListener once local processing complete and 41d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * ActionCompletedListener when second set of local process (dealing with background 42d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * worker response) is complete 43d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 44d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddpublic class ActionMonitor { 45d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd private static final String TAG = LogUtil.BUGLE_DATAMODEL_TAG; 46d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 47d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** 48d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Interface used to notify on completion of local execution for an action 49d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 50d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public interface ActionExecutedListener { 51d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** 52d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * @param result value returned by {@link Action#executeAction} 53d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 54d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd @RunsOnMainThread 55d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd abstract void onActionExecuted(ActionMonitor monitor, final Action action, 56d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final Object data, final Object result); 57d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 58d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 59d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** 60d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Interface used to notify action completion 61d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 62d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public interface ActionCompletedListener { 63d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** 64d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * @param result object returned from processing the action. This is the value returned by 65d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * {@link Action#executeAction} if there is no background work, or 66d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * else the value returned by 67d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * {@link Action#processBackgroundResponse} 68d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 69d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd @RunsOnMainThread 70d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd abstract void onActionSucceeded(ActionMonitor monitor, 71d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final Action action, final Object data, final Object result); 72d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** 73d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * @param result value returned by {@link Action#processBackgroundFailure} 74d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 75d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd @RunsOnMainThread 76d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd abstract void onActionFailed(ActionMonitor monitor, final Action action, 77d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final Object data, final Object result); 78d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 79d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 80d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** 81d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Interface for being notified of action state changes - used for profiling, testing only 82d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 83d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd protected interface ActionStateChangedListener { 84d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** 85d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * @param action the action that is changing state 86d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * @param state the new state of the action 87d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 88d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd @RunsOnAnyThread 89d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd void onActionStateChanged(Action action, int state); 90d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 91d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 92d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** 93d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Operations always start out as STATE_CREATED and finish as STATE_COMPLETE. 94d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Some common state transition sequences in between include: 95d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * <ul> 96d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * <li>Local data change only : STATE_QUEUED - STATE_EXECUTING 97d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * <li>Background worker request only : STATE_BACKGROUND_ACTIONS_QUEUED 98d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * - STATE_EXECUTING_BACKGROUND_ACTION 99d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * - STATE_BACKGROUND_COMPLETION_QUEUED 100d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * - STATE_PROCESSING_BACKGROUND_RESPONSE 101d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * <li>Local plus background worker request : STATE_QUEUED - STATE_EXECUTING 102d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * - STATE_BACKGROUND_ACTIONS_QUEUED 103d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * - STATE_EXECUTING_BACKGROUND_ACTION 104d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * - STATE_BACKGROUND_COMPLETION_QUEUED 105d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * - STATE_PROCESSING_BACKGROUND_RESPONSE 106d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * </ul> 107d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 108d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd protected static final int STATE_UNDEFINED = 0; 109d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd protected static final int STATE_CREATED = 1; // Just created 110d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd protected static final int STATE_QUEUED = 2; // Action queued for processing 111d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd protected static final int STATE_EXECUTING = 3; // Action processing on datamodel thread 112d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd protected static final int STATE_BACKGROUND_ACTIONS_QUEUED = 4; 113d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd protected static final int STATE_EXECUTING_BACKGROUND_ACTION = 5; 114d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd // The background work has completed, either returning a success response or resulting in a 115d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd // failure 116d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd protected static final int STATE_BACKGROUND_COMPLETION_QUEUED = 6; 117d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd protected static final int STATE_PROCESSING_BACKGROUND_RESPONSE = 7; 118d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd protected static final int STATE_COMPLETE = 8; // Action complete 119d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 120d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** 121d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Lock used to protect access to state and listeners 122d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 123d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd private final Object mLock = new Object(); 124d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 125d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** 126d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Current state of action 127d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 128d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd @VisibleForTesting 129d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd protected int mState; 130d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 131d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** 132d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Listener which is notified on action completion 133d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 134d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd private ActionCompletedListener mCompletedListener; 135d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 136d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** 137d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Listener which is notified on action executed 138d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 139d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd private ActionExecutedListener mExecutedListener; 140d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 141d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** 142d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Listener which is notified of state changes 143d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 144d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd private ActionStateChangedListener mStateChangedListener; 145d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 146d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** 147d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Handler used to post results back to caller 148d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 149d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd private final Handler mHandler; 150d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 151d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** 152d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Data passed back to listeners (associated with the action when it is created) 153d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 154d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd private final Object mData; 155d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 156d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** 157d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * The action key is used to determine equivalence of operations and their requests 158d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 159d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd private final String mActionKey; 160d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 161d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** 162d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Get action key identifying associated action 163d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 164d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public String getActionKey() { 165d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return mActionKey; 166d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 167d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 168d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** 169d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Unregister listeners so that they will not be called back - override this method if needed 170d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 171d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public void unregister() { 172d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd clearListeners(); 173d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 174d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 175d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** 176d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Unregister listeners so that they will not be called 177d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 178d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd protected final void clearListeners() { 179d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd synchronized (mLock) { 180d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd mCompletedListener = null; 181d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd mExecutedListener = null; 182d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 183d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 184d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 185d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** 186d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Create a monitor associated with a particular action instance 187d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 188d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd protected ActionMonitor(final int initialState, final String actionKey, 189d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final Object data) { 190d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd mHandler = ThreadUtil.getMainThreadHandler(); 191d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd mActionKey = actionKey; 192d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd mState = initialState; 193d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd mData = data; 194d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 195d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 196d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** 197d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Return flag to indicate if action is complete 198d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 199d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public boolean isComplete() { 200d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd boolean complete = false; 201d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd synchronized (mLock) { 202d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd complete = (mState == STATE_COMPLETE); 203d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 204d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return complete; 205d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 206d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 207d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** 208d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Set listener that will be called with action completed result 209d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 210d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd protected final void setCompletedListener(final ActionCompletedListener listener) { 211d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd synchronized (mLock) { 212d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd mCompletedListener = listener; 213d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 214d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 215d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 216d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** 217d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Set listener that will be called with local execution result 218d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 219d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd protected final void setExecutedListener(final ActionExecutedListener listener) { 220d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd synchronized (mLock) { 221d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd mExecutedListener = listener; 222d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 223d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 224d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 225d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** 226d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Set listener that will be called with local execution result 227d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 228d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd protected final void setStateChangedListener(final ActionStateChangedListener listener) { 229d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd synchronized (mLock) { 230d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd mStateChangedListener = listener; 231d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 232d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 233d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 234d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** 235d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Perform a state update transition 236d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * @param action - action whose state is updating 237d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * @param expectedOldState - expected existing state of action (can be UNKNOWN) 238d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * @param newState - new state which will be set 239d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 240d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd @VisibleForTesting 241d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd protected void updateState(final Action action, final int expectedOldState, 242d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final int newState) { 243d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd ActionStateChangedListener listener = null; 244d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd synchronized (mLock) { 245d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (expectedOldState != STATE_UNDEFINED && 246d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd mState != expectedOldState) { 247d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd throw new IllegalStateException("On updateState to " + newState + " was " + mState 248d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd + " expecting " + expectedOldState); 249d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 250d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (newState != mState) { 251d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd mState = newState; 252d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd listener = mStateChangedListener; 253d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 254d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 255d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (listener != null) { 256d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd listener.onActionStateChanged(action, newState); 257d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 258d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 259d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 260d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** 261d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Perform a state update transition 262d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * @param action - action whose state is updating 263d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * @param expectedOldState - expected existing state of action (can be UNKNOWN) 264d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * @param newState - new state which will be set 265d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 266d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd static void setState(final Action action, final int expectedOldState, 267d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final int newState) { 268d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd int oldMonitorState = expectedOldState; 269d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd int newMonitorState = newState; 270d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final ActionMonitor monitor 271d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd = ActionMonitor.lookupActionMonitor(action.actionKey); 272d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (monitor != null) { 273d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd oldMonitorState = monitor.mState; 274d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd monitor.updateState(action, expectedOldState, newState); 275d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd newMonitorState = monitor.mState; 276d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 277d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (LogUtil.isLoggable(TAG, LogUtil.VERBOSE)) { 278d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS"); 279d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd df.setTimeZone(TimeZone.getTimeZone("UTC")); 280d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd LogUtil.v(TAG, "Operation-" + action.actionKey + ": @" + df.format(new Date()) 281d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd + "UTC State = " + oldMonitorState + " - " + newMonitorState); 282d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 283d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 284d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 285d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** 286d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Mark action complete 287d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * @param action - action whose state is updating 288d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * @param expectedOldState - expected existing state of action (can be UNKNOWN) 289d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * @param result - object returned from processing the action. This is the value returned by 290d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * {@link Action#executeAction} if there is no background work, or 291d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * else the value returned by {@link Action#processBackgroundResponse} 292d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * or {@link Action#processBackgroundFailure} 293d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 294d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd private final void complete(final Action action, 295d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final int expectedOldState, final Object result, 296d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final boolean succeeded) { 297d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd ActionCompletedListener completedListener = null; 298d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd synchronized (mLock) { 299d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd setState(action, expectedOldState, STATE_COMPLETE); 300d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd completedListener = mCompletedListener; 301d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd mExecutedListener = null; 302d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd mStateChangedListener = null; 303d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 304d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (completedListener != null) { 305d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd // Marshal to UI thread 306d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd mHandler.post(new Runnable() { 307d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd @Override 308d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public void run() { 309d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd ActionCompletedListener listener = null; 310d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd synchronized (mLock) { 311d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (mCompletedListener != null) { 312d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd listener = mCompletedListener; 313d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 314d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd mCompletedListener = null; 315d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 316d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (listener != null) { 317d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (succeeded) { 318d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd listener.onActionSucceeded(ActionMonitor.this, 319d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd action, mData, result); 320d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } else { 321d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd listener.onActionFailed(ActionMonitor.this, 322d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd action, mData, result); 323d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 324d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 325d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 326d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd }); 327d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 328d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 329d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 330d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** 331d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Mark action complete 332d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * @param action - action whose state is updating 333d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * @param expectedOldState - expected existing state of action (can be UNKNOWN) 334d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * @param result - object returned from processing the action. This is the value returned by 335d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * {@link Action#executeAction} if there is no background work, or 336d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * else the value returned by {@link Action#processBackgroundResponse} 337d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * or {@link Action#processBackgroundFailure} 338d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 339d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd static void setCompleteState(final Action action, final int expectedOldState, 340d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final Object result, final boolean succeeded) { 341d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd int oldMonitorState = expectedOldState; 342d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final ActionMonitor monitor 343d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd = ActionMonitor.lookupActionMonitor(action.actionKey); 344d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (monitor != null) { 345d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd oldMonitorState = monitor.mState; 346d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd monitor.complete(action, expectedOldState, result, succeeded); 347d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd unregisterActionMonitorIfComplete(action.actionKey, monitor); 348d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 349d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (LogUtil.isLoggable(TAG, LogUtil.VERBOSE)) { 350d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS"); 351d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd df.setTimeZone(TimeZone.getTimeZone("UTC")); 352d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd LogUtil.v(TAG, "Operation-" + action.actionKey + ": @" + df.format(new Date()) 353d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd + "UTC State = " + oldMonitorState + " - " + STATE_COMPLETE); 354d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 355d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 356d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 357d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** 358d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Mark action complete 359d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * @param action - action whose state is updating 360d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * @param expectedOldState - expected existing state of action (can be UNKNOWN) 361d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * @param hasBackgroundActions - has the completing action requested background work 362d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * @param result - the return value of {@link Action#executeAction} 363d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 364d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final void executed(final Action action, 365d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final int expectedOldState, final boolean hasBackgroundActions, final Object result) { 366d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd ActionExecutedListener executedListener = null; 367d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd synchronized (mLock) { 368d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (hasBackgroundActions) { 369d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd setState(action, expectedOldState, STATE_BACKGROUND_ACTIONS_QUEUED); 370d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 371d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd executedListener = mExecutedListener; 372d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 373d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (executedListener != null) { 374d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd // Marshal to UI thread 375d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd mHandler.post(new Runnable() { 376d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd @Override 377d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public void run() { 378d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd ActionExecutedListener listener = null; 379d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd synchronized (mLock) { 380d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (mExecutedListener != null) { 381d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd listener = mExecutedListener; 382d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd mExecutedListener = null; 383d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 384d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 385d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (listener != null) { 386d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd listener.onActionExecuted(ActionMonitor.this, 387d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd action, mData, result); 388d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 389d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 390d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd }); 391d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 392d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 393d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 394d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** 395d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Mark action complete 396d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * @param action - action whose state is updating 397d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * @param expectedOldState - expected existing state of action (can be UNKNOWN) 398d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * @param hasBackgroundActions - has the completing action requested background work 399d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * @param result - the return value of {@link Action#executeAction} 400d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 401d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd static void setExecutedState(final Action action, 402d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final int expectedOldState, final boolean hasBackgroundActions, final Object result) { 403d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd int oldMonitorState = expectedOldState; 404d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final ActionMonitor monitor 405d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd = ActionMonitor.lookupActionMonitor(action.actionKey); 406d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (monitor != null) { 407d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd oldMonitorState = monitor.mState; 408d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd monitor.executed(action, expectedOldState, hasBackgroundActions, result); 409d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 410d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (LogUtil.isLoggable(TAG, LogUtil.VERBOSE)) { 411d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS"); 412d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd df.setTimeZone(TimeZone.getTimeZone("UTC")); 413d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd LogUtil.v(TAG, "Operation-" + action.actionKey + ": @" + df.format(new Date()) 414d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd + "UTC State = " + oldMonitorState + " - EXECUTED"); 415d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 416d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 417d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 418d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** 419d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Map of action monitors indexed by actionKey 420d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 421d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd @VisibleForTesting 422d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd static SimpleArrayMap<String, ActionMonitor> sActionMonitors = 423d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd new SimpleArrayMap<String, ActionMonitor>(); 424d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 425d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** 426d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Insert new monitor into map 427d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 428d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd static void registerActionMonitor(final String actionKey, 429d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final ActionMonitor monitor) { 430d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (monitor != null 431d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd && (TextUtils.isEmpty(monitor.getActionKey()) 432d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd || TextUtils.isEmpty(actionKey) 433d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd || !actionKey.equals(monitor.getActionKey()))) { 434d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd throw new IllegalArgumentException("Monitor key " + monitor.getActionKey() 435d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd + " not compatible with action key " + actionKey); 436d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 437d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd synchronized (sActionMonitors) { 438d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd sActionMonitors.put(actionKey, monitor); 439d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 440d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 441d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 442d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** 443d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Find monitor associated with particular action 444d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 445d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd private static ActionMonitor lookupActionMonitor(final String actionKey) { 446d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd ActionMonitor monitor = null; 447d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd synchronized (sActionMonitors) { 448d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd monitor = sActionMonitors.get(actionKey); 449d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 450d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return monitor; 451d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 452d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 453d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** 454d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Remove monitor from map 455d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 456d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd @VisibleForTesting 457d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd static void unregisterActionMonitor(final String actionKey, 458d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final ActionMonitor monitor) { 459d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (monitor != null) { 460d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd synchronized (sActionMonitors) { 461d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd sActionMonitors.remove(actionKey); 462d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 463d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 464d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 465d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 466d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** 467d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Remove monitor from map if the action is complete 468d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 469d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd static void unregisterActionMonitorIfComplete(final String actionKey, 470d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final ActionMonitor monitor) { 471d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (monitor != null && monitor.isComplete()) { 472d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd synchronized (sActionMonitors) { 473d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd sActionMonitors.remove(actionKey); 474d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 475d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 476d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 477d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd} 478