Initial checkin of AOSP Messaging app.
b/23110861 Change-Id: I11db999bd10656801e618f78ab2b2ef74136fff1
This commit is contained in:
@@ -0,0 +1,295 @@
|
||||
/*
|
||||
* Copyright (C) 2015 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.messaging.datamodel.action;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.android.messaging.datamodel.DataModel;
|
||||
import com.android.messaging.datamodel.DataModelException;
|
||||
import com.android.messaging.datamodel.action.ActionMonitor.ActionCompletedListener;
|
||||
import com.android.messaging.datamodel.action.ActionMonitor.ActionExecutedListener;
|
||||
import com.android.messaging.util.LogUtil;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Base class for operations that perform application business logic off the main UI thread while
|
||||
* holding a wake lock.
|
||||
* .
|
||||
* Note all derived classes need to provide real implementation of Parcelable (this is abstract)
|
||||
*/
|
||||
public abstract class Action implements Parcelable {
|
||||
private static final String TAG = LogUtil.BUGLE_DATAMODEL_TAG;
|
||||
|
||||
// Members holding the parameters common to all actions - no action state
|
||||
public final String actionKey;
|
||||
|
||||
// If derived classes keep their data in actionParameters then parcelable is trivial
|
||||
protected Bundle actionParameters;
|
||||
|
||||
// This does not get written to the parcel
|
||||
private final List<Action> mBackgroundActions = new LinkedList<Action>();
|
||||
|
||||
/**
|
||||
* Process the action locally - runs on action service thread.
|
||||
* TODO: Currently, there is no way for this method to indicate failure
|
||||
* @return result to be passed in to {@link ActionExecutedListener#onActionExecuted}. It is
|
||||
* also the result passed in to {@link ActionCompletedListener#onActionSucceeded} if
|
||||
* there is no background work.
|
||||
*/
|
||||
protected Object executeAction() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Queues up background work ie. {@link #doBackgroundWork} will be called on the
|
||||
* background worker thread.
|
||||
*/
|
||||
protected void requestBackgroundWork() {
|
||||
mBackgroundActions.add(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Queues up background actions for background processing after the current action has
|
||||
* completed its processing ({@link #executeAction}, {@link processBackgroundCompletion}
|
||||
* or {@link #processBackgroundFailure}) on the Action thread.
|
||||
* @param backgroundAction
|
||||
*/
|
||||
protected void requestBackgroundWork(final Action backgroundAction) {
|
||||
mBackgroundActions.add(backgroundAction);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return flag indicating if any actions have been queued
|
||||
*/
|
||||
public boolean hasBackgroundActions() {
|
||||
return !mBackgroundActions.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Send queued actions to the background worker provided
|
||||
*/
|
||||
public void sendBackgroundActions(final BackgroundWorker worker) {
|
||||
worker.queueBackgroundWork(mBackgroundActions);
|
||||
mBackgroundActions.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Do work in a long running background worker thread.
|
||||
* {@link #requestBackgroundWork} needs to be called for this method to
|
||||
* be called. {@link #processBackgroundFailure} will be called on the Action service thread
|
||||
* if this method throws {@link DataModelException}.
|
||||
* @return response that is to be passed to {@link #processBackgroundResponse}
|
||||
*/
|
||||
protected Bundle doBackgroundWork() throws DataModelException {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the success response from the background worker. Runs on action service thread.
|
||||
* @param response the response returned by {@link #doBackgroundWork}
|
||||
* @return result to be passed in to {@link ActionCompletedListener#onActionSucceeded}
|
||||
*/
|
||||
protected Object processBackgroundResponse(final Bundle response) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called in case of failures when sending background actions. Runs on action service thread
|
||||
* @return result to be passed in to {@link ActionCompletedListener#onActionFailed}
|
||||
*/
|
||||
protected Object processBackgroundFailure() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
protected Action(final String key) {
|
||||
this.actionKey = key;
|
||||
this.actionParameters = new Bundle();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
protected Action() {
|
||||
this.actionKey = generateUniqueActionKey(getClass().getSimpleName());
|
||||
this.actionParameters = new Bundle();
|
||||
}
|
||||
|
||||
/**
|
||||
* Queue an action and monitor for processing by the ActionService via the factory helper
|
||||
*/
|
||||
protected void start(final ActionMonitor monitor) {
|
||||
ActionMonitor.registerActionMonitor(this.actionKey, monitor);
|
||||
DataModel.startActionService(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Queue an action for processing by the ActionService via the factory helper
|
||||
*/
|
||||
public void start() {
|
||||
DataModel.startActionService(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Queue an action for delayed processing by the ActionService via the factory helper
|
||||
*/
|
||||
public void schedule(final int requestCode, final long delayMs) {
|
||||
DataModel.scheduleAction(this, requestCode, delayMs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when action queues ActionService intent
|
||||
*/
|
||||
protected final void markStart() {
|
||||
ActionMonitor.setState(this, ActionMonitor.STATE_CREATED,
|
||||
ActionMonitor.STATE_QUEUED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark the beginning of local action execution
|
||||
*/
|
||||
protected final void markBeginExecute() {
|
||||
ActionMonitor.setState(this, ActionMonitor.STATE_QUEUED,
|
||||
ActionMonitor.STATE_EXECUTING);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark the end of local action execution - either completes the action or queues
|
||||
* background actions
|
||||
*/
|
||||
protected final void markEndExecute(final Object result) {
|
||||
final boolean hasBackgroundActions = hasBackgroundActions();
|
||||
ActionMonitor.setExecutedState(this, ActionMonitor.STATE_EXECUTING,
|
||||
hasBackgroundActions, result);
|
||||
if (!hasBackgroundActions) {
|
||||
ActionMonitor.setCompleteState(this, ActionMonitor.STATE_EXECUTING,
|
||||
result, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update action state to indicate that the background worker is starting
|
||||
*/
|
||||
protected final void markBackgroundWorkStarting() {
|
||||
ActionMonitor.setState(this,
|
||||
ActionMonitor.STATE_BACKGROUND_ACTIONS_QUEUED,
|
||||
ActionMonitor.STATE_EXECUTING_BACKGROUND_ACTION);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update action state to indicate that the background worker has posted its response
|
||||
* (or failure) to the Action service
|
||||
*/
|
||||
protected final void markBackgroundCompletionQueued() {
|
||||
ActionMonitor.setState(this,
|
||||
ActionMonitor.STATE_EXECUTING_BACKGROUND_ACTION,
|
||||
ActionMonitor.STATE_BACKGROUND_COMPLETION_QUEUED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update action state to indicate the background action failed but is being re-queued for retry
|
||||
*/
|
||||
protected final void markBackgroundWorkQueued() {
|
||||
ActionMonitor.setState(this,
|
||||
ActionMonitor.STATE_EXECUTING_BACKGROUND_ACTION,
|
||||
ActionMonitor.STATE_BACKGROUND_ACTIONS_QUEUED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by ActionService to process a response from the background worker
|
||||
* @param response the response returned by {@link #doBackgroundWork}
|
||||
*/
|
||||
protected final void processBackgroundWorkResponse(final Bundle response) {
|
||||
ActionMonitor.setState(this,
|
||||
ActionMonitor.STATE_BACKGROUND_COMPLETION_QUEUED,
|
||||
ActionMonitor.STATE_PROCESSING_BACKGROUND_RESPONSE);
|
||||
final Object result = processBackgroundResponse(response);
|
||||
ActionMonitor.setCompleteState(this,
|
||||
ActionMonitor.STATE_PROCESSING_BACKGROUND_RESPONSE, result, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by ActionService when a background action fails
|
||||
*/
|
||||
protected final void processBackgroundWorkFailure() {
|
||||
final Object result = processBackgroundFailure();
|
||||
ActionMonitor.setCompleteState(this, ActionMonitor.STATE_UNDEFINED,
|
||||
result, false);
|
||||
}
|
||||
|
||||
private static final Object sLock = new Object();
|
||||
private static long sActionIdx = System.currentTimeMillis() * 1000;
|
||||
|
||||
/**
|
||||
* Helper method to generate a unique operation index
|
||||
*/
|
||||
protected static long getActionIdx() {
|
||||
long idx = 0;
|
||||
synchronized (sLock) {
|
||||
idx = ++sActionIdx;
|
||||
}
|
||||
return idx;
|
||||
}
|
||||
|
||||
/**
|
||||
* This helper can be used to generate a unique key used to identify an action.
|
||||
* @param baseKey - key generated to identify the action parameters
|
||||
* @return - composite key generated by appending unique index
|
||||
*/
|
||||
protected static String generateUniqueActionKey(final String baseKey) {
|
||||
final StringBuilder key = new StringBuilder();
|
||||
if (!TextUtils.isEmpty(baseKey)) {
|
||||
key.append(baseKey);
|
||||
}
|
||||
key.append(":");
|
||||
key.append(getActionIdx());
|
||||
return key.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Most derived classes use this base implementation (unless they include files handles)
|
||||
*/
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Derived classes need to implement writeToParcel (but typically should call this method
|
||||
* to parcel Action member variables before they parcel their member variables).
|
||||
*/
|
||||
public void writeActionToParcel(final Parcel parcel, final int flags) {
|
||||
parcel.writeString(this.actionKey);
|
||||
parcel.writeBundle(this.actionParameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper for derived classes to implement parcelable
|
||||
*/
|
||||
public Action(final Parcel in) {
|
||||
this.actionKey = in.readString();
|
||||
// Note: Need to set classloader to ensure we can un-parcel classes from this package
|
||||
this.actionParameters = in.readBundle(Action.class.getClassLoader());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user