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.Bundle;
20d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.os.Parcel;
21d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.os.Parcelable;
22d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.text.TextUtils;
23d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
24d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.datamodel.DataModel;
25d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.datamodel.DataModelException;
26d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.datamodel.action.ActionMonitor.ActionCompletedListener;
27d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.datamodel.action.ActionMonitor.ActionExecutedListener;
28d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.util.LogUtil;
29d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
30d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport java.util.LinkedList;
31d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport java.util.List;
32d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
33d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd/**
34d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Base class for operations that perform application business logic off the main UI thread while
35d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * holding a wake lock.
36d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * .
37d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Note all derived classes need to provide real implementation of Parcelable (this is abstract)
38d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */
39d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddpublic abstract class Action implements Parcelable {
40d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static final String TAG = LogUtil.BUGLE_DATAMODEL_TAG;
41d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
42d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    // Members holding the parameters common to all actions - no action state
43d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public final String actionKey;
44d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
45d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    // If derived classes keep their data in actionParameters then parcelable is trivial
46d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    protected Bundle actionParameters;
47d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
48d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    // This does not get written to the parcel
49d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private final List<Action> mBackgroundActions = new LinkedList<Action>();
50d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
51d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
52d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Process the action locally - runs on action service thread.
53d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * TODO: Currently, there is no way for this method to indicate failure
54d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @return result to be passed in to {@link ActionExecutedListener#onActionExecuted}. It is
55d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     *         also the result passed in to {@link ActionCompletedListener#onActionSucceeded} if
56d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     *         there is no background work.
57d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
58d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    protected Object executeAction() {
59d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return null;
60d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
61d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
62d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
63d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Queues up background work ie. {@link #doBackgroundWork} will be called on the
64d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * background worker thread.
65d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
66d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    protected void requestBackgroundWork() {
67d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        mBackgroundActions.add(this);
68d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
69d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
70d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
71d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Queues up background actions for background processing after the current action has
72d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * completed its processing ({@link #executeAction}, {@link processBackgroundCompletion}
73d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * or {@link #processBackgroundFailure}) on the Action thread.
74d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @param backgroundAction
75d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
76d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    protected void requestBackgroundWork(final Action backgroundAction) {
77d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        mBackgroundActions.add(backgroundAction);
78d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
79d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
80d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
81d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Return flag indicating if any actions have been queued
82d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
83d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public boolean hasBackgroundActions() {
84d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return !mBackgroundActions.isEmpty();
85d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
86d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
87d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
88d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Send queued actions to the background worker provided
89d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
90d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public void sendBackgroundActions(final BackgroundWorker worker) {
91d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        worker.queueBackgroundWork(mBackgroundActions);
92d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        mBackgroundActions.clear();
93d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
94d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
95d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
96d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Do work in a long running background worker thread.
97d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * {@link #requestBackgroundWork} needs to be called for this method to
98d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * be called. {@link #processBackgroundFailure} will be called on the Action service thread
99d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * if this method throws {@link DataModelException}.
100d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @return response that is to be passed to {@link #processBackgroundResponse}
101d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
102d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    protected Bundle doBackgroundWork() throws DataModelException {
103d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return null;
104d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
105d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
106d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
107d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Process the success response from the background worker. Runs on action service thread.
108d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @param response the response returned by {@link #doBackgroundWork}
109d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @return result to be passed in to {@link ActionCompletedListener#onActionSucceeded}
110d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
111d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    protected Object processBackgroundResponse(final Bundle response) {
112d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return null;
113d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
114d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
115d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
116d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Called in case of failures when sending background actions. Runs on action service thread
117d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @return result to be passed in to {@link ActionCompletedListener#onActionFailed}
118d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
119d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    protected Object processBackgroundFailure() {
120d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return null;
121d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
122d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
123d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
124d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Constructor
125d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
126d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    protected Action(final String key) {
127d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        this.actionKey = key;
128d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        this.actionParameters = new Bundle();
129d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
130d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
131d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
132d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Constructor
133d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
134d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    protected Action() {
135d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        this.actionKey = generateUniqueActionKey(getClass().getSimpleName());
136d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        this.actionParameters = new Bundle();
137d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
138d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
139d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
140d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Queue an action and monitor for processing by the ActionService via the factory helper
141d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
142d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    protected void start(final ActionMonitor monitor) {
143d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        ActionMonitor.registerActionMonitor(this.actionKey, monitor);
144d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        DataModel.startActionService(this);
145d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
146d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
147d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
148d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Queue an action for processing by the ActionService via the factory helper
149d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
150d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public void start() {
151d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        DataModel.startActionService(this);
152d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
153d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
154d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
155d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Queue an action for delayed processing by the ActionService via the factory helper
156d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
157d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public void schedule(final int requestCode, final long delayMs) {
158d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        DataModel.scheduleAction(this, requestCode, delayMs);
159d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
160d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
161d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
162d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Called when action queues ActionService intent
163d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
164d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    protected final void markStart() {
165d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        ActionMonitor.setState(this, ActionMonitor.STATE_CREATED,
166d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                ActionMonitor.STATE_QUEUED);
167d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
168d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
169d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
170d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Mark the beginning of local action execution
171d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
172d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    protected final void markBeginExecute() {
173d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        ActionMonitor.setState(this, ActionMonitor.STATE_QUEUED,
174d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                ActionMonitor.STATE_EXECUTING);
175d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
176d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
177d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
178d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Mark the end of local action execution - either completes the action or queues
179d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * background actions
180d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
181d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    protected final void markEndExecute(final Object result) {
182d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final boolean hasBackgroundActions = hasBackgroundActions();
183d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        ActionMonitor.setExecutedState(this, ActionMonitor.STATE_EXECUTING,
184d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                hasBackgroundActions, result);
185d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (!hasBackgroundActions) {
186d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            ActionMonitor.setCompleteState(this, ActionMonitor.STATE_EXECUTING,
187d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    result, true);
188d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
189d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
190d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
191d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
192d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Update action state to indicate that the background worker is starting
193d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
194d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    protected final void markBackgroundWorkStarting() {
195d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        ActionMonitor.setState(this,
196d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                ActionMonitor.STATE_BACKGROUND_ACTIONS_QUEUED,
197d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                ActionMonitor.STATE_EXECUTING_BACKGROUND_ACTION);
198d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
199d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
200d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
201d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Update action state to indicate that the background worker has posted its response
202d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * (or failure) to the Action service
203d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
204d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    protected final void markBackgroundCompletionQueued() {
205d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        ActionMonitor.setState(this,
206d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                ActionMonitor.STATE_EXECUTING_BACKGROUND_ACTION,
207d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                ActionMonitor.STATE_BACKGROUND_COMPLETION_QUEUED);
208d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
209d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
210d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
211d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Update action state to indicate the background action failed but is being re-queued for retry
212d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
213d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    protected final void markBackgroundWorkQueued() {
214d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        ActionMonitor.setState(this,
215d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                ActionMonitor.STATE_EXECUTING_BACKGROUND_ACTION,
216d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                ActionMonitor.STATE_BACKGROUND_ACTIONS_QUEUED);
217d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
218d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
219d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
220d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Called by ActionService to process a response from the background worker
221d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @param response the response returned by {@link #doBackgroundWork}
222d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
223d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    protected final void processBackgroundWorkResponse(final Bundle response) {
224d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        ActionMonitor.setState(this,
225d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                ActionMonitor.STATE_BACKGROUND_COMPLETION_QUEUED,
226d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                ActionMonitor.STATE_PROCESSING_BACKGROUND_RESPONSE);
227d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final Object result = processBackgroundResponse(response);
228d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        ActionMonitor.setCompleteState(this,
229d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                ActionMonitor.STATE_PROCESSING_BACKGROUND_RESPONSE, result, true);
230d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
231d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
232d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
233d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Called by ActionService when a background action fails
234d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
235d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    protected final void processBackgroundWorkFailure() {
236d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final Object result = processBackgroundFailure();
237d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        ActionMonitor.setCompleteState(this, ActionMonitor.STATE_UNDEFINED,
238d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                result, false);
239d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
240d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
241d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static final Object sLock = new Object();
242d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static long sActionIdx = System.currentTimeMillis() * 1000;
243d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
244d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
245d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Helper method to generate a unique operation index
246d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
247d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    protected static long getActionIdx() {
248d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        long idx = 0;
249d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        synchronized (sLock) {
250d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            idx = ++sActionIdx;
251d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
252d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return idx;
253d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
254d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
255d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
256d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * This helper can be used to generate a unique key used to identify an action.
257d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @param baseKey - key generated to identify the action parameters
258d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @return - composite key generated by appending unique index
259d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
260d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    protected static String generateUniqueActionKey(final String baseKey) {
261d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final StringBuilder key = new StringBuilder();
262d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (!TextUtils.isEmpty(baseKey)) {
263d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            key.append(baseKey);
264d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
265d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        key.append(":");
266d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        key.append(getActionIdx());
267d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return key.toString();
268d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
269d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
270d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
271d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Most derived classes use this base implementation (unless they include files handles)
272d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
273d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    @Override
274d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public int describeContents() {
275d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return 0;
276d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
277d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
278d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
279d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Derived classes need to implement writeToParcel (but typically should call this method
280d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * to parcel Action member variables before they parcel their member variables).
281d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
282d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public void writeActionToParcel(final Parcel parcel, final int flags) {
283d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        parcel.writeString(this.actionKey);
284d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        parcel.writeBundle(this.actionParameters);
285d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
286d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
287d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
288d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Helper for derived classes to implement parcelable
289d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
290d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public Action(final Parcel in) {
291d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        this.actionKey = in.readString();
292d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // Note: Need to set classloader to ensure we can un-parcel classes from this package
293d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        this.actionParameters = in.readBundle(Action.class.getClassLoader());
294d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
295d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd}
296