package vandy.mooc.presenter;
import java.lang.ref.WeakReference;
import java.util.List;
import vandy.mooc.MVP;
import vandy.mooc.common.GenericAsyncTask;
import vandy.mooc.common.GenericAsyncTaskOps;
import vandy.mooc.model.AcronymModel;
import vandy.mooc.model.aidl.AcronymExpansion;
import vandy.mooc.model.aidl.AcronymResults;
import android.content.Context;
import android.content.res.Configuration;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
/**
* This class plays the "Presenter" role in the Model-View-Presenter
* (MVP) pattern by acting upon the Model and the View, i.e., it
* retrieves data from the Model (e.g., AcronymModel) and formats it
* for display in the View (e.g., DisplayExpansionActivity). It
* implements GenericAsyncTaskOps so its doInBackground() method runs
* in a background task. It implements MVP.ProvidedPresenterOps and
* MVP.RequiredModelOps to decouple the MVP layers. It implements
* AcronymResults so it can be the target of asynchronous callback
* methods from the Model layer.
*/
public class AcronymPresenter
implements GenericAsyncTaskOps<String, Void, List<AcronymExpansion>>,
MVP.ProvidedPresenterOps,
MVP.RequiredPresenterOps,
AcronymResults {
/**
* Debugging tag used by the Android logger.
*/
protected final static String TAG =
AcronymPresenter.class.getSimpleName();
/**
* Used to enable garbage collection.
*/
private WeakReference<MVP.RequiredViewOps> mAcronymView;
/**
* Reference to the AcronymModel.
*/
private AcronymModel mAcronymModel;
/**
* The GenericAsyncTask used to expand an acronym in a background
* thread via the Acronym web service.
*/
private GenericAsyncTask<String,
Void,
List<AcronymExpansion>,
AcronymPresenter> mAsyncTask;
/**
* Keeps track of whether a call is already in progress and
* ignores subsequent calls until the first call is done.
*/
private boolean mCallInProgress;
/**
* Store Acronym for error reporting purposes.
*/
private String mAcronym;
/**
* Constructor initializes the fields.
*/
public void onCreate(MVP.RequiredViewOps view) {
// Initialize the WeakReference.
mAcronymView = new WeakReference<>(view);
// Create the AcronymModel.
mAcronymModel = new AcronymModel();
mAcronymModel.onCreate(this);
}
/**
* Called after a runtime configuration change occurs.
*/
public void onConfigurationChanged(Configuration newConfig) {
// Checks the orientation of the screen.
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE)
Log.d(TAG,
"Now running in landscape mode");
else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT)
Log.d(TAG,
"Now running in portrait mode");
}
/**
* Hook method called to shutdown the Model layer.
*
* @param isChangeConfigurations
* True if a runtime configuration triggered the onDestroy() call.
*/
@Override
public void onDestroy(boolean isChangingConfigurations) {
// Destroy the model.
mAcronymModel.onDestroy(isChangingConfigurations);
}
/**
* Initiate the synchronous acronym lookup when the user presses
* the "Lookup Acronym Sync" button. It uses an AsyncTask to
* avoid blocking the UI thread.
*
* @return false if a call is already in progress, else true.
*/
public boolean expandAcronymSync(String acronym) {
if (mCallInProgress)
return false;
else {
// Don't allow concurrent calls to get the weather.
mCallInProgress = true;
// Store this for error reporting purposes.
mAcronym = acronym;
// Execute the AsyncTask to expand the acronym without
// blocking the caller.
mAsyncTask = new GenericAsyncTask<>(this);
mAsyncTask.execute(mAcronym);
return true;
}
}
/**
* Retrieve the expanded acronym results via a synchronous two-way
* method call, which runs in a background thread to avoid
* blocking the UI thread.
*/
@Override
public List<AcronymExpansion> doInBackground(String... acronyms) {
// Get the acronym expansions synchronously.
return mAcronymModel.getAcronymExpansions(acronyms[0]);
}
/**
* Display the results in the UI Thread.
*/
@Override
public void onPostExecute(List<AcronymExpansion> acronymExpansions) {
displayResults(acronymExpansions,
"no expansions for "
+ mAcronym
+ " found");
}
/**
* Initiate the synchronous acronym lookup when the user presses
* the "Lookup Acronym Async" button.
*
* @return false if a call is already in progress, else true.
*/
public boolean expandAcronymAsync(String acronym) {
if (mCallInProgress)
return false;
else {
// Don't allow concurrent calls to get the weather.
mCallInProgress = true;
// Store this for error reporting purposes.
mAcronym = acronym;
// Get the acronym expansions asynchronously. The results
// are returned via the sendResults() and sendError() hook
// methods below.
mAcronymModel.getAcronymExpansions(acronym,
this);
return true;
}
}
/**
* This hook method is called back by the Model layer and returns
* AcronymExpansion results back to the View layer.
*/
public void sendResults(final List<AcronymExpansion> acronymExpansions)
throws RemoteException {
displayResults(acronymExpansions,
(String) null);
}
/**
* This hook method is called back by the Model layer and returns
* error results back to the View layer.
*/
public void sendError(final String reason)
throws RemoteException {
displayResults(null,
reason);
}
/**
* Call back to the View layer to display the results.
*/
@Override
public void displayResults(List<AcronymExpansion> results,
String failureReason) {
// Display the results.
mAcronymView.get().displayResults(results,
failureReason);
// Call is no longer in progress.
mCallInProgress = false;
}
/**
* Return the Activity context.
*/
@Override
public Context getActivityContext() {
return mAcronymView.get().getActivityContext();
}
/**
* Return the Application context.
*/
@Override
public Context getApplicationContext() {
return mAcronymView.get().getApplicationContext();
}
/**
* A no-op needed to make the compiler happy since we implement
* the AcronymResult interface.
*/
@Override
public IBinder asBinder() {
return null;
}
}