/** * Copyright (c) 2013, Sana * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the Sana nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL Sana BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.sana.android.app; import java.net.URISyntaxException; import org.sana.android.content.Intents; import org.sana.android.content.Uris; import org.sana.android.util.Logf; import android.content.Intent; import android.net.Uri; /** * This is the default workflow which mimics the behavior of the version 1.x * clients with the addition of the authentication screen. * * The Activity flow is given by * 1. Main => AuthenticationActivity * 2. AuthenticationActivity => data + OK,CANCEL * a. null + CANCEL => AuthenticationActivity (1) * b. Data + OK => NavigationActivity * 3. NavigationActivity => Intent + OK,CANCEL * Intent E [SubjectList, ProcedureList, EncounterList, NotificationList] * 4. ModelList => data + OK,CANCEL * a. data + CANCEL => NavigationActivity (3) * b. data +OK => Uri + OK * i. Uri = DIR => InsertModel * ii.Uri = Item => ViewModel (3) * 5. InsertModel => data + OK,CANCEL * a. data + CANCEL => NavigationActivity (3) * b. data + OK => NavigationActivity (3) * 6. ViewModel => NavigationActivity (3) * * @author Sana Development * */ public class DefaultActivityRunner extends ActivityRunner { public static final String TAG = DefaultActivityRunner.class.getSimpleName(); public DefaultActivityRunner(){ super(); } public DefaultActivityRunner(Intent intent){ super(intent); } public Intent evaluate(Intent input) { // Log input if we are debugging Logf.I(TAG, "next(Intent)", String.format("input=%s", ((input != null)?input.toUri(Intent.URI_INTENT_SCHEME):"null"))); Intent output = null; switch(Intents.parseActionDescriptor(input)){ // CREATE case Intents.INSERT: case Intents.INSERT_OR_EDIT: break; // READ case Intents.PICK: break; case Intents.PICK_ACTIVITY: break; // UPDATE case Intents.EDIT: break; // DELETE case Intents.DELETE: break; default: } return output; } /* * (non-Javadoc) * @see org.sana.analytics.Runner#next(java.lang.Object) */ @Override public Intent next(Intent response) { // get the previous state Intent request = (stack.size() >= 1)? stack.pop(): null; // Log request and response String reqLog = (request != null)?request.toUri(Intent.URI_INTENT_SCHEME):"null"; String respLog = (response != null)?response.toUri(Intent.URI_INTENT_SCHEME):"null"; Logf.I(TAG, "next(Intent)", String.format("request=%s;response=%s", reqLog, respLog)); // check for a null intent equivalent to CANCEL if(response == null){ stack.push(handleCancel(request)); } else { stack.push(handleOk(request, response)); } return Intents.copyOf(stack.peek()); } @Override protected Intent handleCancel(Intent request){ // Gives us the requestCode of the originating request int requestCode = (request != null) ? Intents.parseActionDescriptor(request): Intents.NULL; Uri uri = (request != null)? request.getData(): Uri.EMPTY; Logf.W(TAG, "handleCancel(Intent)", "requestCode=" + requestCode +";descriptor=" + Uris.getDescriptor(uri)); switch(requestCode){ case Intents.MAIN: // top of stack is MAIN return PICK_OBSERVER; case Intents.NULL: // If stack was empty send finish code Logf.D(TAG, "handleCancel(Intent)","....at NULL"); return new Intent(Intents.ACTION_FINISH); case Intents.PICK_ACTIVITY: // top was Navigation activity so we are effectively logging out Logf.D(TAG, "handleCancel(Intent)","....at PICK_ACTIVITY"); return PICK_OBSERVER; case Intents.PICK: // Check if we are pressing back from an observer pick which is // effectively a finish for Main Logf.D(TAG, "handleCancel(Intent)","....at PICK"); if(Uris.getDescriptor(uri) == Uris.OBSERVER_DIR) return new Intent(Intents.ACTION_FINISH); else return goTo(Intents.PICK_ACTIVITY); case Intents.VIEW: // Return to the pick immediately below Logf.D(TAG,"handleCancel(Intent)", "....at VIEW"); Intent intent = goTo(Intents.PICK); return intent; default: // everything else we unwind the stack until we get to the // navigation screen or Main Logf.D(TAG, "handleCancel(Intent)","....at default"); while(!stack.isEmpty()){ int d = Intents.parseActionDescriptor(stack.peek()); if (d == Intents.PICK_ACTIVITY) return stack.pop(); else if(d == Intents.MAIN){ return PICK_OBSERVER; } } // The stack is empty-should never get here return new Intent(Intents.ACTION_FINISH); } } @Override protected Intent handleOk(Intent request, Intent response){ int requestCode = (request != null) ? Intents.parseActionDescriptor(request): Intents.NULL; Uri uri = (response != null)? response.getData(): Uri.EMPTY; Logf.D(TAG, "handleOk(Intent)", "requestCode: "+ requestCode +", response descriptor: " + Uris.getDescriptor(uri)); boolean m = false; // determine and return what replaces the top of the stack switch(requestCode){ case Intents.NULL: Logf.D(TAG, "handleOk(Intent)","....at NULL"); // If stack was empty send finish code if(request == null){ Logf.D(TAG, ".... Empty stack or unrecognizable Uri"); return new Intent(Intents.ACTION_FINISH); }else{ Logf.D(TAG,"handleOk(Intent)", ".... Returning to pick activity"); return goTo(Intents.PICK_ACTIVITY); } case Intents.MAIN: Logf.D(TAG, "handleOk(Intent)","....at MAIN"); // MAIN should be root of stack so we return PICK_OBSERVER; case Intents.PICK_ACTIVITY: Logf.D(TAG,"handleOk(Intent)", "....at PICK_ACTIVITY"); // the returned intent should hold the next intent to launch as // the data try { return Intent.parseUri(response.getDataString(), Intent.URI_INTENT_SCHEME); } catch (URISyntaxException e) { e.printStackTrace(); throw new IllegalArgumentException(e); } case Intents.INSERT: if(!m) Logf.D(TAG,"handleOk(Intent)", "....at INSERT"); m = true; case Intents.INSERT_OR_EDIT: if(!m) Logf.D(TAG, "handleOk(Intent)","....at INSERT_OR_EDIT"); m = true; case Intents.PICK: if (!m) Logf.D(TAG, "handleOk(Intent)","....at PICK"); m = true; // content pick intent we should get data back switch(Uris.getDescriptor(uri)){ case Uris.OBSERVER_ITEM: case Uris.OBSERVER_UUID: Logf.D(TAG, "handleOk(Intent)","....at PICK Observer-Selected"); return new Intent(Intents.ACTION_PICK_ACTIVITY); case Uris.SUBJECT_ITEM: case Uris.SUBJECT_UUID: Logf.D(TAG, "handleOk(Intent)","....at PICK Subject-Selected"); return PICK_PROCEDURE; case Uris.ENCOUNTER_ITEM: case Uris.ENCOUNTER_UUID: Logf.D(TAG,"handleOk(Intent)", "....at PICK Procedure-Selected"); // require the subject to be set return new Intent(Intent.ACTION_VIEW, uri); case Uris.NOTIFICATION_ITEM: case Uris.NOTIFICATION_UUID: Logf.D(TAG,"handleOk(Intent)", "....at PICK Notification-Selected"); // require the subject to be set return new Intent(Intent.ACTION_VIEW, uri); case Uris.PROCEDURE_ITEM: case Uris.PROCEDURE_UUID: Logf.D(TAG, "handleOk(Intent)","....at PICK Procedure-Selected"); // require the subject to be set return new Intent(Intent.ACTION_VIEW, uri); // DIR should indicate create new case Uris.SUBJECT_DIR: Logf.D(TAG, "handleOk(Intent)","....at PICK Subject-None Picked"); default: return goTo(Intents.PICK_ACTIVITY); } case Intents.VIEW: // return to the predecessor of the view Logf.D(TAG, "....at VIEW"); return goTo(Intents.PICK_ACTIVITY); } // Return the result intent back to the top // stack should never be empty here return goTo(Intents.PICK_ACTIVITY); } }