Warning: Creating default object from empty value in /home/agilemed/aendeavors.com/wp-includes/ms-load.php on line 138

Warning: session_start(): Cannot send session cookie - headers already sent by (output started at /home/agilemed/aendeavors.com/wp-includes/ms-load.php:138) in /home/agilemed/aendeavors.com/wp-content/plugins/amazon-product-in-a-post-plugin/amazon-product-in-a-post.php on line 102

Warning: session_start(): Cannot send session cache limiter - headers already sent (output started at /home/agilemed/aendeavors.com/wp-includes/ms-load.php:138) in /home/agilemed/aendeavors.com/wp-content/plugins/amazon-product-in-a-post-plugin/amazon-product-in-a-post.php on line 102
Agile Tech » Applying Emerging Technologies


Bin Deploy SqlCE 4.0 and EF 4.1

When attempting to do a private deployment using SQL Compact Edition and Entity Framework, several errors continued to pop up on client installations:

  • Unable to find the requested .Net Framework Data Provider
  • Could not load file or assembly System.Data.SqlServerCe.Entity or one of its dependencies

The System.Data.SqlServerCe and other binaries were already included and copied locally, but SqlServerCe.Entity wasn't present. To get this deployment to work, the following needed to be done:

  • Make sure System.Data.SqlServerCe is referenced and set to "Copy local" in properties
  • Include the 7 needed SqlCe assembiles from Program Files\Microsoft SQL Server Compact Edition\v4.0, make sure to set as "Content" and "Copy if newer" in properties:
    • sqlceca40.dll
    • sqlcecompact40.dll
    • sqlceer40EN.dll
    • sqlceme40.dll
    • sqlceoledb40.dll
    • sqlceqp40.dll
    • sqlcese40.dll
  • Install the following library package references using NuGet (right click References->Add Library Package Reference)
    • EntityFramework
    • EntityFramework.SqlServerCompact
    • This will create packages that will contain lib directories for System.Data.SqlServerCe.Entity, reference and "Copy local" for this library
  • Add the following to app.config:


      <remove invariant="System.Data.SqlServerCe.4.0" />
      <add name="Microsoft SQL Server Compact Data Provider 4.0"
           description=".NET Framework Data Provider for Microsoft SQL Server Compact"
           type="System.Data.SqlServerCe.SqlCeProviderFactory, System.Data.SqlServerCe, Version=, Culture=neutral, PublicKeyToken=89845dcd8080cc91"/>


Deploying to SQL Azure

Warning: file_get_contents(https://ecs.amazonaws.com/onca/xml?AWSAccessKeyId=AKIAILRMGOER5ORIOURA&AssociateTag=agile08-20&IdType=ASIN&ItemId=1430229616&Operation=ItemLookup&ResponseGroup=ItemAttributes%2CImages%2COffers&Service=AWSECommerceService&Timestamp=2016-08-25T09%3A46%3A48Z&Version=2009-03-31&Signature=%2Bg5bPQNMmdOZ%2B2lytFltkYmzaTKBMHld5piFtgYzc3o%3D): failed to open stream: HTTP request failed! HTTP/1.1 400 Bad Request in /home/agilemed/aendeavors.com/wp-content/plugins/amazon-product-in-a-post-plugin/inc/aws_signed_request.php on line 404

SQL Azure and SQL Server Management Studio

During our migration from SQL Express which we had been using for development to SQL Azure, we were having issues connecting to the deployment from SQL Server Managment Studio. If you’re running into issues connection with Management Studio, try the following:

  1. Server Name: Should be the instance name from the Azure web interface (servername.database.windows.net)
  2. Login: Should be your username, as of this post, appending @host was unnecessary for a successful connection from Studio 2008 R2
  3. Before logging in, click on the “Options” button and select the “Connection Properties” tab. Under “Connect to database”, type in the name of your database. Leaving it set as <default> will result in a failed connection
  4. Try a different physical location. Many locations (hotels, airports, schools) block outgoing database connections. If you’re receiving a message like the one below, it’s possible that your current location has an outgoing port blocked:
A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: Named Pipes Provider, error: 40 - Could not open a connection to SQL Server) (Microsoft SQL Server, Error: 53)


Deploying MVC3 Razor Application to Azure

Warning: file_get_contents(https://ecs.amazonaws.com/onca/xml?AWSAccessKeyId=AKIAILRMGOER5ORIOURA&AssociateTag=agile08-20&IdType=ASIN&ItemId=0596801971&Operation=ItemLookup&ResponseGroup=ItemAttributes%2CImages%2COffers&Service=AWSECommerceService&Timestamp=2016-08-25T09%3A46%3A48Z&Version=2009-03-31&Signature=Lkht0pwXg9eYLdU26l3tBlWRDOiOs3AoCYJtrvfgEZ4%3D): failed to open stream: HTTP request failed! HTTP/1.1 400 Bad Request in /home/agilemed/aendeavors.com/wp-content/plugins/amazon-product-in-a-post-plugin/inc/aws_signed_request.php on line 404
Deploying an existing MVC 3 application to Azure is fairly simple. Right click your solution and pick Add->New Project, and then search for the “Windows Azure Cloud Service” template. After selecting ok, you will be prompted to add some roles, which you can skip by clicking ok at the bottom of the window. Next, right click the “Roles” folder in the Azure project, and select “Add->Web Role Project In Solution” (this will only be an option if an ASP project is available in the same solution). Pick the project you would like to add, and you’re almost ready to go!
If deploying MVC 3 and using the Razor view engine, you will need to include a few additional references in the project. Make sure the following references are added (either from the .NET reference tab or from C:Program Files (x86)Microsoft ASP.NETASP.NET Web Pagesv1.0Assemblies):
- System.Web.Helpers
- Microsoft.Web.Infrastructure 

- System.Web.Mvc
- System.Web.Razor
- System.Web.WebPages
- System.Web.WebPages.Deployment
- System.Web.WebPages.Razor
For each of the above files, make sure “Copy Local” is selected. To publish your application on Azure, right click the Cloud project and pick “Publish”. If this is the first deployment, you will see the following window:
Publish Window
Under “Credentials”, add a new account and fill in the details from the Azure web interface. Select your Hosted Service and Storage Account that you would like to deploy to, and your web service will be available (relatively soon) on the cloud! If you notice issues with a restart loop in your service, or you are unable to connect, try using the “IntelliTrace for .NET 4 roles” option in the publish window to download a stack trace for troubleshooting.


Deploying SQL Compact Edition (CE) with ASP MVC and Castle ActiveRecord

Warning: file_get_contents(https://ecs.amazonaws.com/onca/xml?AWSAccessKeyId=AKIAILRMGOER5ORIOURA&AssociateTag=agile08-20&IdType=ASIN&ItemId=1430234040&Operation=ItemLookup&ResponseGroup=ItemAttributes%2CImages%2COffers&Service=AWSECommerceService&Timestamp=2016-08-25T09%3A46%3A48Z&Version=2009-03-31&Signature=R1l2huZg43AwVTwlln4aW4Ir639ke20M0kdt7DMmyYs%3D): failed to open stream: HTTP request failed! HTTP/1.1 400 Bad Request in /home/agilemed/aendeavors.com/wp-content/plugins/amazon-product-in-a-post-plugin/inc/aws_signed_request.php on line 404

With the recent release of Visual Studio 2010 SP1 and its integration with IIS Express and SQL Compact Edition, we have been working to migrate our projects over to using both IIS Express and SQL CE for development. While the initial move can be a bit painful, it definitely saves a ton of startup time when changing development hardware or adding new developers. Scott Guthrie has a great blog post on getting SQL which details most of what is necessary. One initial hang up we noticed when migrating a project with Castle is making sure that the drivers get switched from Sql Server to SqlCE. When using SqlCE, you will need to add a reference and add “Copy to Local” to:


In your Web.Config file, you can then change the the NHibernate driver and dialect:

<add key="connection.driver_class" value="NHibernate.Driver.SqlServerCeDriver" />
<add key="dialect" value="NHibernate.Dialect.MsSqlCeDialect" />

Finally, if your SqlCe database is located in App_Data of your web project, the connection string is:

<add name="DatabaseService"
connectionString="Data Source=|DataDirectory|CEDBNAME.sdf"
providerName="System.Data.SqlServerCe.4.0" />
** In the above connection string, |DataDirectory| will point to your App_Data folder


Silverlight 3 and DeepZoom

Microsoft’s Silverlight 3 and the DeepZoom composer allow users to display high-resolution images interactively. This provides several benefits for either sets of images in a gallery or for smoothly viewing very large image files.

This brief tutorial will demonstrate how to set up a Silverlight 3 project with interactive zoom and panning/scrolling with a DeepZoom image.

The first thing we will do is add the MultiScaleImage control to our automatically generated UserControl. This control contains the event handlers that we will need to interact with the deep zoom image.

   1: <MultiScaleImage x:Name="_deepZoomImage" Margin="7" MouseWheel="_deepZoomImage_MouseWheel" MouseLeftButtonDown="_deepZoomImage_MouseLeftButtonDown" MouseLeftButtonUp="_deepZoomImage_MouseLeftButtonUp" MouseMove="_deepZoomImage_MouseMove" MouseLeave="_deepZoomImage_MouseLeave">

   2:     <MultiScaleImage.Effect>

   3:         <DropShadowEffect ShadowDepth="8" BlurRadius="10" Color="#FF605D5D"/>

   4:     </MultiScaleImage.Effect>

   5: </MultiScaleImage>

We’ve already added several event handlers to the control:

- MouseWheel: Event fires when the scroll wheel moves forward/backward on the mouse.

- MouseLeftButtonDown/Up: These events fire when the user clicks. Both will be necessary to determine if the user is clicking or dragging the image.

- MouseMove: Will also be used for dragging/panning the image within the control.

- MouseLeave: Indicates when the mouse cursor leaves the control area. Needed in case the user passes the edge of the control when panning.

Now that we have our control created within our XAML file, we can begin loading our images and adding the code to interact with the control. First, we need to prepare a DeepZoom image using the DeepZoom composer. There is a short video to learn how to import images and create a Silverlight DeepZoom collection. Once created, the “GeneratedImages” folder can be uploaded to a webserver of your choice, or used locally depending on the setup of your Silverlight project (be careful for cross-zone policy issues if debugging Silverlight from the ASP webserver and using local image files).

We will need three global variables to keep the status of our mouse:

   1: bool _dragging = false;

   2: Point lastMousePosition;

   3: Point lastMouseViewport;

We can then add in our basic information into the main constructor:

   1: public MainPage()

   2: {

   3:     InitializeComponent();

   4:     string baseUrl = "http://pathToImages/"

   5:     _deepZoomImage.Source = new DeepZoomImageTileSource(new Uri(baseUrl + "/dzc_output.xml"));

   6: }

The above URL can point either to the collage “dzc_output.xml” file, or to an individual deep zoom image XML file (found in the “dzc_output_images” folder). This set of code will load the image into our control as soon as the form loads. Depending on how your application functions, this can be done at any point or bound to other controls (buttons, list of albums, etc).

The application should compile at this point and be able to display the images. Now we can start to add some interactivity to the images.

First, we will add the code to tell our control when the user is dragging the image:

   1: // Set dragging to true when user clicks their mouse within the control

   2: private void _deepZoomImage_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)

   3: {

   4:     _dragging = true;

   5: }


   7: // Set dragging to false when user stops click

   8: // If the mouse position hasn't changed, zoom in on the current location

   9: private void _deepZoomImage_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)

  10: {

  11:     _dragging = false;

  12:     if (e.GetPosition(_deepZoomImage).Equals(lastMousePosition))

  13:     {

  14:         Point mouse = e.GetPosition(_deepZoomImage);

  15:         _deepZoomImage.ZoomAboutLogicalPoint(1.6, (_deepZoomImage.ElementToLogicalPoint(mouse)).X, (_deepZoomImage.ElementToLogicalPoint(mouse)).Y);

  16:     }

  17: }

The first value within “ZoomAboutLogicalPoint” can be adjusted based on how far in or out you would like the image to zoom. The additional values indicate the “LogicalPoint” within the image that was clicked (a value of 0 to 1 indicating the far left/top to far right/bottom). To prevent some general bugginess within the application, we’ll also add a “stop dragging” command for when the user leaves the control:

   1: // Set dragging to false when mouse leaves the control area

   2: private void _deepZoomImage_MouseLeave(object sender, MouseEventArgs e)

   3: {

   4:     _dragging = false;

   5: }

Now to actually handle the dragging. These statements get placed in the MouseMove event handler. If our user has clicked (_dragging == true), we can move the image. If our user hasn’t clicked, set the last position for use with dragging:

   1: // Code to handle panning our image

   2: private void _deepZoomImage_MouseMove(object sender, MouseEventArgs e)

   3: {

   4:     if (_dragging)

   5:     {

   6:         Point newOrigin = new Point();

   7:         newOrigin = lastMouseViewport; // Set the last mouse position


   9:         // Add the X and Y values of our current mouse position

  10:         newOrigin.X += ((lastMousePosition.X - e.GetPosition(_deepZoomImage).X) / _deepZoomImage.ActualWidth * _deepZoomImage.ViewportWidth);

  11:         newOrigin.Y += ((lastMousePosition.Y - e.GetPosition(_deepZoomImage).Y) / _deepZoomImage.ActualWidth * _deepZoomImage.ViewportWidth);


  13:         // Set the Viewport origin to the new mouse location

  14:         _deepZoomImage.ViewportOrigin = newOrigin;

  15:     }

  16:     else

  17:     {

  18:         lastMousePosition = e.GetPosition(_deepZoomImage);

  19:         lastMouseViewport = _deepZoomImage.ViewportOrigin;

  20:     }

  21: }

In the above code, the X and Y scroll distance is calculated by subtracting the current mouse position from the last recorded location. This value is then divided by the image’s ActualWidth and multiplied by the ViewportWidth to compensate for any zooming within the image (otherwise the image will scroll very fast or very slow if the user has zoomed in or out).

Almost done! We’re also going to add an event so that the use can scroll in and out using their mouse wheel:

   1: private void _deepZoomImage_MouseWheel(object sender, MouseWheelEventArgs e)

   2: {

   3:     Point mouse = e.GetPosition(_deepZoomImage);

   4:     if (e.Delta > 0) // If scrolling in

   5:     {

   6:         _deepZoomImage.ZoomAboutLogicalPoint(1.2, (_deepZoomImage.ElementToLogicalPoint(mouse)).X, (_deepZoomImage.ElementToLogicalPoint(mouse)).Y);

   7:     }

   8:     else // If scrolling out

   9:     {

  10:         _deepZoomImage.ZoomAboutLogicalPoint(0.8, (_deepZoomImage.ElementToLogicalPoint(mouse)).X, (_deepZoomImage.ElementToLogicalPoint(mouse)).Y);

  11:     }

  12: }

We use our Delta value to determine if the user was scrolling in or out, and then zoom using ZoomAboutLogicalPoint accordingly. Again, the first value can be changed to alter the “speed” of zooming. This works great for desktop users, but adding additional functionality for people without scroll wheels (particularly laptop users) would be necessary for a full-featured application.

Finally, we’re going to add one piece of XAML and an event handler in case the image gets lost so that the user can reset the zoom and position of the original image:

   1: <Button x:Name="resetZoom" Height="27" HorizontalAlignment="Right" Margin="0,47,128,0" VerticalAlignment="Top" Width="29" Content="Reset
Zoom" Opacity="0.25" FontSize="8" Click="resetZoom_Click">

   2:     <Button.Background>

   3:         <SolidColorBrush Opacity="0.5" Color="#FF1F3B53"/>

   4:     </Button.Background>

   5: </Button>

   1: private void resetZoom_Click(object sender, RoutedEventArgs e)

   2: {

   3:     _deepZoomImage.ZoomAboutLogicalPoint(_deepZoomImage.ViewportWidth, 0.5, 0.5);

   4:     _deepZoomImage.ViewportOrigin = new Point(0, 0);

   5: }

Since the ViewportWidth indicates how far the image is zoomed, we simply tell our control to ZoomAboutLogicalPoint with ViewportWidth as the first argument. We then reset the position to the center of the image.

To view the final project: http://www.agilemedicine.com/resources/DeepZoomExample

We’ll get the full source code posted soon. If you have any questions or comments, feel free to leave them below or e-mail us at info@agilemedicine.com.


Adobe Flex: WebService XML Array Binding, Value-Enabled ComboBox

While working on a new application using Adobe Flex, one shortcoming of the ComboBox was readily apparent: there is no way to store a value and display a different string like one can do with HTML:

   1: <SELECT>

   2:   <OPTION value="123">First String</OPTION>

   3:   <OPTION value="124">Second String</OPTION>

   4:   <OPTION value="125">Third String</OPTION>

   5: </SELECT>

While browsing the internet, there were several pages that either made a custom ComboBox to store the data, or went through a decent amount of loops and arrays. One other task that was difficult was trying to use the HTTPService to bind XML data to an array.

HTTPService to Array

This solution doesn’t bind directly to an array, but uses the XMLListCollection instead, which works similar to an ArrayCollection. The HTTPService is set up like the main examples for binding to other objects:

   1: <mx:HTTPService id="xmlList"

   2:     url="http://www.mywebserver.com/webService.php"

   3:     result="handleXml(event)"

   4:     fault="handleFault(event)"

   5:     resultFormat="e4x">

   6:     <mx:request>

   7:         <type>{requestedType}</type>

   8:         <format>{requestedFormat}</format>

   9:     </mx:request>

  10: </mx:HTTPService>

To set this data to an array (or in this case an XMLListCollection):

   1: private var myXmlCollection:XMLListCollection;


   3: public function handleXml(event:ResultEvent):void{

   4:     if(event.result != ""){

   5:         // Set the data to the XMLListCollection for lookup

   6:         myXmlCollection= new XMLListCollection(event.result.node);

   7:         // Bind the ListCollection to the comboBox

   8:         myComboBox.dataProvider = myXmlCollection;

   9:     }

  10: }

Use XMLListCollection for Value-Enabled ComboBox

To have the ComboBox use the current ID when we change it, we then use the “change” attribute:

   1: <mx:Label text="My List Data: "

   2:        x="10" y="40"/>

   3: <mx:ComboBox id="xmlList"

   4:     x="60" y="38"

   5:     width="250"

   6:     labelField="description"

   7:     change="getCurrentId()" />

And finally, we lookup our current value/ID:

   1: public function getCurrentId():void{

   2:     var o:Object = myXmlCollection.getItemAt(xmlList.selectedIndex);

   3:     var currentId:String = o.nodeid.toString();

   4:     // Do whatever we want with our selected ID

   5: }

This can then be used to update other combo boxes (such as displaying a list of cities once a state is selected) or any other tasks where your ID and display value may differ for UI reasons.


Android Programming: Transferring Data Between Intents

While working on the development of some new applications, I have tried transferring complex variables to new intents. For example:

Transferring a single variable, or set of single variable is easily accomplished by adding them to the intent.

   1: Intent i = new Intent();

   2: i.setClassName("packageName", "packageName.IntentClass");

   3: String term = "data to pass";

   4: i.putExtra("packageName.term", term);

   5: startActivity(i);

In the called intent, we then get this data by calling getExtras():

   1: Bundle extras = getIntent().getExtras();

   2: String term = extras.getString("packageName.term");

However, what if we want to pass more complex data? As you can see above, the data types that can be added as extras are somewhat limited. In order to pass an object, it must first implement either the Parcelable or Serializable class. Our next post will be on how to implement the Parcelable class, followed by a post on how to integrate a data service.


Android Programming: Basic Animation

Saving space is a constant necessity of programming on mobile platforms. While mobile devices are extremely convenient, providing a large amount of computing power in an easy-to-carry size, the screen size can make it difficult to use complex applications. One benefit of both the iPhone/iPod and the Android platforms is the ability to use animations and views to provide additional screen real estate. On the Android platform, the easiest way to do this is by using the ViewFlipper widget. This is the method we use in our AgileMedCalc application to provide equation information along with the calculators.

To use this approach, the ViewFlipper widget is added similar to a layout in the application’s XML view. Each widget or layout within the ViewFlipper will be rotated through when the showNext() property is called by the application. Because of this, if you want to have more than one widget within a single view, you will need to have additional layouts added:

   1: <?xml version="1.0" encoding="utf-8"?>
   2: <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
   3:     android:orientation="vertical"
   4:     android:layout_width="fill_parent"
   5:     android:layout_height="fill_parent">
   6:     <ViewFlipper
   7:         android:id="@+id/flipper"
   8:         android:layout_width="fill_parent"
   9:         android:layout_height="fill_parent">
  10:         <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  11:             android:orientation="vertical"
  12:             android:layout_width="fill_parent"
  13:             android:layout_height="fill_parent">
  14:             <TextView
  15:                 android:id="@+id/albuminLbl"
  16:                 android:layout_width="wrap_content"
  17:                 android:layout_height="wrap_content"
  18:                 android:text="nAlbumin (g/dL):"
  19:                 android:gravity="center_vertical" />
  20:             <EditText
  21:                 android:id="@+id/albumin"
  22:                 android:layout_width="fill_parent"
  23:                 android:layout_height="wrap_content"
  24:                 android:singleLine="true"
  25:                 android:layout_toRightOf="@+id/albuminLbl" />
  26:             <ImageView
  27:                 android:id="@+id/viewInfo"
  28:                 android:layout_width="wrap_content"
  29:                 android:layout_height="wrap_content"
  30:                 android:src="@drawable/questionicon"
  31:                 android:layout_below="@+id/calc"
  32:                 android:layout_alignParentRight="true" />
  33:         </RelativeLayout>
  34:         <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  35:             android:orientation="vertical"
  36:             android:layout_width="fill_parent"
  37:             android:layout_height="fill_parent">
  38:             <TextView
  39:                 android:id="@+id/calcInfo"
  40:                 android:layout_width="fill_parent"
  41:                 android:layout_height="wrap_content"
  42:                 android:text="Corrected Calcium = Measured Calcium + (0.8 * (Normal Albumin - Measured Albumin))nNormal Albumin = 4.0" />
  43:             <ImageView
  44:                 android:id="@+id/done"
  45:                 android:layout_width="wrap_content"
  46:                 android:layout_height="wrap_content"
  47:                 android:src="@drawable/backicon"
  48:                 android:layout_below="@+id/calcInfo"
  49:                 android:layout_alignParentRight="true" />
  50:         </RelativeLayout>
  51:     </ViewFlipper>
  52: </RelativeLayout>

In the above code, our ViewFlipper has 2 RelativeLayouts. This allows us to switch between one layout or the other, thereby switching the entire layout’s contents with very little code. In our Java class, we add the following code to bind to our buttons (or in our case, an ImageView):

   1: private void setFlipper(){
   2:     ViewFlipper infoFlipper = (ViewFlipper)findViewById(R.id.flipper);
   3:     infoFlipper.setInAnimation(AnimationUtils.loadAnimation(this, R.anim.push_left_in));
   4:     infoFlipper.setOutAnimation(AnimationUtils.loadAnimation(this, R.anim.push_left_out));
   6:     final ImageView info = (ImageView)findViewById(R.id.viewInfo);
   7:     info.setOnClickListener(new View.OnClickListener() {
   8:         public void onClick(View v)
   9:         {
  10:             infoFlipper.showNext();
  11:         }
  12:     });
  13:     final ImageView done = (ImageView)findViewById(R.id.done);
  14:     done.setOnClickListener(new View.OnClickListener() {
  15:         public void onClick(View v)
  16:         {
  17:             infoFlipper.showNext();
  18:         }
  19:     });
  20: }

After adding our ViewFlipper object, we set a couple of animations on when the view moves in or out (we’ll talk more about this in a second). In addition, we set our onClickListeners to show the next view with infoFlipper.showNext(). This way, when a user clicks the icon, it will slide out the calculator and slide in the equation info.

This can be done either with or without fancy animations. Several animations are included with the Android SDK (SDKpathsamplesApiDemosresanim). To use these, simply copy the animation from the SDK path into your application by creating the resanim folder and pasting the animation file. Once this is done, you can access the animation like any other resource (such as R.anim.push_left_in). The details in these files can be customized to your liking to add different effects to the animation.

While the above examples are more complicated than doing a single view, it is much easier and saves a lot of typing when compared to making several different intents to display the same information. It also makes the applications look “shiny” which makes the GUI a little more friendly.


Android Programming: AgileMedCalc

Quick, easy to use specialty applications are fantastic on mobile platforms. However, for some utilities, a single application with multiple functions can save a lot of “application space” on menus. To help address this, we’ve created AgileMedCalc to work as a multi-function medical calculator. We’ve rolled in one of our past applications, AgileBloodGas, into this application to cut down on multiple apps for users to download.

With the concept of “saving space” in mind, we’ve also included some animations that will allow users to view details about the calculations being performed on the calculators. A coming post will talk about the animations from the Android platform we used to accomplish this task.


Android Programming: Google Service/App Authentication

While many of the Google applications already have Android-based ports, some of the more “specialty apps” such as AdSense don’t have a mobile interface. Luckily, the Google API allows for an easy login method using an HTTP Post request. One of our current applications, SimpleAdMonitor, uses this method to download an AdSense user’s daily and all time totals.

While the solution is fairly easy to implement, the actual POST request appears to run quite slowly, at least over the Android emulator and somewhat on the device as well.

The first step to generating an authorized session is to post the user’s login details to the Google ServiceLogin:

   1: String login = "https://www.google.com/accounts/ServiceLoginAuth?service=adsense&hl=en-US&ltmpl=login&ifr=true&passive=true&rm=hide&nui=3&alwf=true&continue=https%3A%2F%2Fwww.google.com%2Fadsense%2Fgaiaauth&followup=https%3A%2F%2Fwww.google.com%2Fadsense%2Fgaiaauth";
   2: DefaultHttpClient client = new DefaultHttpClient();
   3: String websiteData = null;
   4: URI uri = new URI(login);
   5: HttpPost method = new HttpPost(uri);
   6: method.addHeader("User-Agent", "User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv: Gecko/20071115 Firefox/");
   7: method.addHeader("Pragma", "no-cache");
   8: method.addHeader("Content-Type", "application/x-www-form-urlencoded");

On line 1, the address specifies a Google service to authorize against. This service can be changed if you need to access some other application. Once this request is formed, the user’s login information can be added using a NameValuePair list. These are then set on the HttpPost method using setEntity:

   1: List <NameValuePair> loginInfo = new ArrayList <NameValuePair>();
   2: loginInfo.add(new BasicNameValuePair("Email", username));
   3: loginInfo.add(new BasicNameValuePair("Passwd", password));
   4: loginInfo.add(new BasicNameValuePair("null", "Sign+in"));
   5: HttpEntity entity = new UrlEncodedFormEntity(nvps, HTTP.UTF_8);
   7: method.setEntity(entity);
   8: HttpResponse res = client.execute(method);

One item to note on line 3 is that the param used for the password is “Passwd”. Once this data is posted, the server will return a response that should be evaluated for a correct login. If the login is valid, the page should respond with a link to a redirect page that needs to again be posted to:

   1: String login2 = "https://www.google.com/accounts/CheckCookie?continue=https%3A%2F%2Fwww.google.com%2Fadsense%2Fgaiaauth&followup=https%3A%2F%2Fwww.google.com%2Fadsense%2Fgaiaauth&hl=en-US&service=adsense&ltmpl=login&chtml=LoginDoneHtml";
   2: method.setURI(new URI(login2));
   3: res = client.execute(method);

At this point, the server should respond with the data from the redirect URL, in this case, the main AdSense page. Further requests can now be made to the server using the same method without needing to re-authorize the user. As I mentioned previously, there are some latency issues with this method that I haven’t quite sorted out yet. The lag isn’t horrible, but is fairly significant when waiting for two fairly small pieces of data. Some additional digging will hopefully find out what is causing the delay and how to improve it.

Older posts «