Wednesday, May 9, 2012

Gmail Attachment Issues

Android will allow a user to put more than one app on it that does something, for example send email So you have your email account app out of box, your gmail account and let's say a third party super duper email app that you can't live without installed on your phone. When you click the email link, it will launch a picker that lists these three apps. You select the one that you want to process the message and it does it. All fine and dandy. Once that picker comes up, you're out of your app and in the picker app. In other words, you don't have much control over error handling. Here's the problem: Gmail can't process attachments. It throws an exception that can't be caught and I can't control what gets processed by the app. For example, having gmail handle a link to an web site instead of putting the attachment right into the message. The only workaround that I have is a link in the message (the images I'm trying to send are on a web server anyway) to the image which should make it work on every app. Android bug report http://code.google.com/p/android/issues/detail?id=27269&q=gmail%20attachments&colspec=ID%20Type%20Status%20Owner%20Summary%20Stars Google http://groups.google.com/a/googleproductforums.com/forum/#!category-topic/gmail/android/PsZ68HiLc_o http://thenextweb.com/mobile/2010/11/10/google-acknowledges-android-gmail-attachment-issues-invites-users-to-help-debug/

Tuesday, May 8, 2012

Debugging HTTP Connections

Most of my Android apps have multiple and sometimes a dozen or so of backend Get, POST and other http api calls. Part of debugging them is figuring out http header request and response data. This code snippet below is a useful utility method that allows you to log out http headers:


public static void logHttpHeaders(Header[] headers)
{
Log.d(TAG,"Logging http headers: " + headers.length );

for (int i = 0; i < headers.length; i++)
    {
    Header h = headers[i];
    Log.d(TAG,"Header: " + h.getName() + " " + h.getValue());
    }

}

Friday, May 4, 2012

Creating an iPhone like PickerWheel

One of the most useful interfaces that iPhone has is the picker wheel which I like to call roulette wheel.  Android date pickers and out of box select boxes are very html-like and not very slick looking. Designing and implementing one that is like the iPhone picker wheel is actually pretty complex/ About two years ago, I put one together for a customer but I was never quite happy with it and it never really felt exactly right.    Luckily the Android open source community has lots of really smart folk, doing some great work and if you're looking for a nice interface to extend in your project, this open source wheel project is what you're looking for.


Android Wheel Control. https://code.google.com/p/android-wheel/

I've used it on a couple of projects and it works great.  It's relatively easy to customize and has some great sample code that pretty much will do what you need to do out of box.  It's one of my favorite Android projects and worth a look to see if it jazzes up your app.

Monday, April 30, 2012

Prevent autolaunch of soft keyboard


Android will want to give focus to an edittext when an activity loads which will automatically popup the soft keyboard. You may not want the keyboard to display until the user taps an edittext field. To prevent Android from launching the keyboard, simply request focus to some other (non-editable) field like a textview like in the code below.

TextView textViewTV = (TextView) findViewById(R.id.mytextview);
        textViewTV.setFocusable(true);
        textViewTV.setFocusableInTouchMode(true);
        textViewTV.requestFocus();

Friday, April 27, 2012

Limiting Debug Trace to your App

I tend to debug on a device rather than an emulater and depending on which device I'm using., there might be tons of logging which basically makes trace statements unusable. Luckily in Eclipse, it's easy to create a log filter to get rid of the messages I don't want to see.
In debug mode, you'll see the logcat trace down at the bottom and probably a saved filter list to the left of the logging.  Click the green cross icon and a dialog will popup with a few edit fields. The two that I use the most are Filter name (which gives your saved filter a name :-) ) and by Application Name which will limit trace to whatever application you want. The application name is basically the package name in your android manifest


manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.appulearn.coolapp.android"

So I would paste in com.appulearn.coolapp.android

You can also filter out by TAG, and depending on what I have running (like for example a bunch of services) I might create a tag filter which would match the tag name you use in your log.d(TAG, "whoops! error"); statement.

Tuesday, April 24, 2012

Message and Handlers


Message and Handlers

Handlers are a useful too for doing a task within a class in response to a change in a variable state or to an action. A common use for a handler is to update the UI once a thread is done processing (if you choose to do it this way versus asynctask.)  I often use a handler when I want an activity to do something in response to the completion of a service or to button clicks or to form validation and other things that might generate UI changes. For example, let's say that the app starts up and kicks off a service. When the service completes, it fires an Intent that the activity is listening for which triggers the handler to redirect off a splash screen either to a login screen or a main screen based on what the service returns.

Now how does the activity know what to do? By opening up the intent and getting the bundle. The example below uses a handler to receive a broadcast from a service category download. If the service has processed successfully, the icon will update itself to a success icon, otherwise the error message from the service will be displayed.   The service generates an intent with a bundle, and broadcasts it.  The activity listens for that broadcast and processes it (code below is basically logging the intent and builds a message out of it to pass to the handler.The trigger to update the UI is a message that I create through a utility method.


 private BroadcastReceiver mReceiver = new BroadcastReceiver() 

 { 

      @Override 

      public void onReceive(Context context, Intent intent) 

      { 

           Bundle data= intent.getExtras(); 

           mHaveCategoryError = data.getBoolean(GlobalConstants.EXTRA_ERROR_STATUS, false); 

           mDoRedirect = data.getBoolean(GlobalConstants.EXTRA_DO_REDIRECT, true); 

           String error= data.getString(GlobalConstants.EXTRA_ERROR_MESSAGE); 

           HashMap<String, String> dataList = new HashMap<String, String>(); 

                dataList.put(GlobalConstants.EXTRA_ERROR_MESSAGE, error); 

           Message message = Utils.createMessage(1, dataList); 

           handler.dispatchMessage(message);           

      } 

 }; 

 private Handler handler = new Handler() { 

      @Override 

      public void handleMessage(Message msg) { 

           Bundle b = msg.getData(); 

           String message = b.getString(GlobalConstants.EXTRA_ERROR_MESSAGE); 

           String messageType = b.getString(GlobalConstants.EXTRA_MESSAGE_TYPE); 

           if (messageType!=null && messageType.equals(GlobalConstants.SERVICE_CATEGORIES_DOWNLOAD)){ 

                ImageView iv1 = (ImageView) findViewById(R.id.categorySpinnerView); 

                TextView statusMessageE = (TextView) findViewById(R.id.categoryStatusMessage); 

                Drawable d= getResources().getDrawable(R.drawable.iconsuccess); 

                if (message!=null) { 

                     d= getResources().getDrawable(R.drawable.iconalert48); 

                       statusMessageE.setText(message); 

                } else { 

                     statusMessageE.setText(getResources().getString(R.string.categoriesDownloaded));      

                } 

                 iv1.clearAnimation(); 

                  iv1.setImageDrawable(d); 

           }  

      } 

 } 

 public static Message createMessage(int messageId, HashMap<String, String> dataList) 

   { 

           Message msg = new Message(); 

           msg.what=messageId; 

           Bundle data = new Bundle(); 

           if (dataList == null) 

           { 

                dataList= new HashMap<String, String>(); 

           } 

           Set<Entry<String, String>> entries = dataList.entrySet(); 

           Iterator<Entry<String, String>> it = entries.iterator(); 

           while (it.hasNext()) 

           { 

                Entry<String, String> entry = (Entry<String, String>) it.next(); 

                data.putString(entry.getKey(), entry.getValue()); 

           } 

           msg.setData(data); 

           return msg; 

   }  

Sunday, April 22, 2012

Showing Progress in a Long Running Process

One of the great things about Android is that there often is several different ways you can implement a specific programming task. Let's say that you want to have some sort of indication that a background process is occurring, for example downloading bootstrap data or posting data to an api or simply displaying a splash screen when the app launches for a few seconds.

Iphone apps use a little spinner icon to denote this.

You could do this as out of box progress bar and there is a DownloadManager api that looks pretty interesting and I'm going to be trying it on my next project. The disadvantage of the progress bar is that phone manufacturers can change the default image associated with it which makes your GUI look different to different users.  

Now another approach would be to use an imageview and Android's animation framework to spin an icon.  Code is below and it's simple. This allows you to customize the spinning icon to your heart's content. On a surf report app I wrote, I spun a surfboard. On a ski report app, I spun a snowflake. On another Find Your Friend app, I actually spun to two little man images one doing a cartwheel to the left of a "LOADING...." textview and one doing a cartwheel to the right of that textview.  You'll see that I'm controlling the visibility of the image view which you set and unset in your asynctask or thread handler.


 <ImageView  
         android:id="@+id/spinnerView"  
         android:layout_width="wrap_content"  
         android:layout_height="wrap_content"  
         android:layout_marginTop="12dp"  
         android:visibility="invisible"  
         android:layout_centerHorizontal="true"  
         android:layout_below="@id/logo"  
         android:src="@drawable/loadingimagewhite" />  
  protected void startSpinner()  
   {  
           ImageView iv = (ImageView) findViewById(R.id.spinnerView);  
           iv.setVisibility(View.VISIBLE);  
                Drawable d = getResources().getDrawable(R.drawable.loadingimagewhite);  
             iv.setImageDrawable(d);  
             float width = d.getMinimumWidth() / 2;  
             float height = d.getMinimumHeight() / 2;  
             RotateAnimation a = new RotateAnimation(0, 360, width, height);  
             a.setDuration(3000);  
             a.setRepeatCount(RotateAnimation.INFINITE);  
             a.setInterpolator(new LinearInterpolator());  
             a.setRepeatMode(RotateAnimation.RESTART);  
             iv.startAnimation(a);  
   }  
      protected void stopSpinner()  
   {  
           ImageView iv = (ImageView) findViewById(R.id.spinnerView);  
           iv.setVisibility(View.INVISIBLE);  
        iv.clearAnimation();  
   }