Friday, April 27, 2012

Deep look at Android Networking. Part 1. Introduction.

Most modern applications are actively using internet to interact with outer world. Internet has become an integral part of mobile development. Android OS is based on the Linux kernel and contains mighty set of networking capabilities inherent from it lower layer.
This topic is not about application layer of network stack. Examples about how to get content of some url or download file can be easily found in internet (including android developers). Purpose of the topic is to consider basic points of network stack in context of android and java.
Lets start from Network Interface - point of interconnection between a your device and a private or public network. It's generally a network interface card (NIC), but doesn't have to have a physical form - network interface can be implemented in software layer. For example, every android device (even when wifi is disabled and no mobile network configured) has the loopback interface (127.0.0.1 for IPv4 and ::1 for IPv6) - it's not a physical device but a piece of software which simulating a network interface.
To get list of available interfaces use NetworkInterface#getNetworkInterfaces:
 NetworkInterface.getNetworkInterfaces()  
Width disabled wifi and mobile connection you will typically get only one network interface - loopback interface lo0. NetworkInterface doesn't provide any particular information about network interface card (NIC) which it represents (however, it is worth noting that since sdk 9 a few additional method were added). Only things you can get - local name of interface and assigned ip address (like pdo0 and 46.133.18.123). Considering fact that only 'raised' interface will be found by NetworkInterface#getNetworkInterfaces it's hard to find any practical use of NetworkInterface (it can't be used to figure out connected or interface which performs data transmission or to check metric of interface) - it's interesting only in theoretical context (it's must less functional than NetworkInterface from java SE sdk).
Unfortunately, android shell (adb shell) doen't provide all linux network commands (like ifconfig). But even supported commands, like, netcfg, not always works like expected. For example, with enabled (and connected wifi) we will see:
$ netcfg
lo       UP    127.0.0.1       255.0.0.0       0x00000049
usb0     DOWN  0.0.0.0         0.0.0.0         0x00001002
tunl0    DOWN  0.0.0.0         0.0.0.0         0x00000080
gre0     DOWN  0.0.0.0         0.0.0.0         0x00000080
sit0     DOWN  0.0.0.0         0.0.0.0         0x00000080
svnet0   UP    0.0.0.0         0.0.0.0         0x000000d1
eth0     UP    192.168.100.163 255.255.255.0   0x00001043
while with wifi disabled:
$ netcfg
lo       UP    127.0.0.1       255.0.0.0       0x00000049
usb0     DOWN  0.0.0.0         0.0.0.0         0x00001002
tunl0    DOWN  0.0.0.0         0.0.0.0         0x00000080
gre0     DOWN  0.0.0.0         0.0.0.0         0x00000080
sit0     DOWN  0.0.0.0         0.0.0.0         0x00000080
svnet0   UP    0.0.0.0         0.0.0.0         0x000000d1
So, we can see the same problem that we had for NetworkInterface - disabled interface not found.
Let's try to understand why.
Here is what we can see (in logcat) when we try to enable wifi on device with wifi disabled:
I/WifiHW  ( 3643): [WIFI] Load Driver
I/WifiHW  ( 3643): [WiFi.c] insmod() Start!! 
I/WifiHW  ( 3643): [WiFi.c] start init_module() Start!! 
I/WifiHW  ( 3643): [WIFI] DRIVER OK
I/WifiHW  ( 3643): wifi_start_supplicant: Enter
D/WifiHW  ( 3643): /data/wifi/bcm_supp.conf exits
E/WifiHW  ( 3643): wifi_start_supplicant: pi->serial=117440528, serial=0
I/WifiHW  ( 3643): wifi_start_supplicant: Exit. supp_status=running
...
end when wifi is enabled and connected and we are disabling it:
I/WifiHW  ( 3643): wifi_stop_supplicant: Enter
I/WifiHW  ( 3643): wifi_stop_supplicant: connecting supplicant is done
I/WifiHW  ( 3643): wifi_stop_supplicant: status of  supplicant(connected), count(49) 
I/wpa_supplicant( 5070): CTRL-EVENT-TERMINATING - signal 15 received
I/wpa_supplicant( 5070): CTRL-EVENT-TERMINATING - signal 0 received
I/WifiHW  ( 3643): wifi_stop_supplicant: exit normally
D/WifiStateTracker( 3643): Reset connections and stopping DHCP
I/WifiHW  ( 3643): wifi_close_supplicant_connection: enter
I/WifiHW  ( 3643): wifi_close_supplicant_connection: exit
...
I/WifiHW  ( 3643): wifi_unload_driver: enter
...
E/WifiHW  ( 3643): [WIFI] Unload Driver
I/WifiHW  ( 3643): wifi_unload_driver: exit
What we have here? Assuming that WifiHW tag is used to mark operations related to wifi stuff (quite logical assumption) we can see, that in wifi disabled state not just supplicant is 'stopped', but even wifi driver is unloaded (insmod is used to load it). Otherwise, supplicant received signal 15 (termination signal) and then wifi driver is unloaded. Please note once again: all this assumptions are based on logs of devices.
What does this tell us? This tells us, that Android is quite smart and economical (at least battery) system ... and that most like we not able to write application to monitor network interfaces (at least list all of them) of our device - when NIC is not used it's 'unloaded' from system. As far as you know, it's not possible to keep 2 network connections (wifi and mobile) raised in simultaneously (w.o. some funny tricks i'm going to show later in next topics) - system will disable mobile connection when wifi is connected. Obviously, this is correct behavior - save your battery and save your money (mobile internet sometimes very expensive). So that's why, apparently, we are not able to get all out network interfaces using sdk api.
Also we are not able to manage our network interfaces with this basic api. Fortunately Android sdk provides WifiManager to help us with wifi stuff. A bit more complicated to work with mobile networks (but possible). And finally vpn api is introduced in sdk 14. I'm going to talk about these things in the next few chapters.

Friday, April 20, 2012

Dialog box by PopupWindow

While screen size is increasing dialog boxes become essential part of most applications. Once in early February 2011 first Motorolla Xoom appeared on the shelves this problem became actual for most android developers. Of course, simple dialogs (to confirm some stuff deletion or agree with license agreement) have been used previously to smartphone applications. But the key points of the user interface were spread to the individual pages (Activities). Pages which looked good on small screens of smartphones became very ugly (because a lot of wasted space) on large screens of tablets.
As a quick solution for our problem Android SDK 11 offers us set of holographic themes (more commonly known as themes) among which there are Theme_Holo_Dialog and Theme_Holo_DialogWhenLarge (as well as few derived from them themes stylized for light colors and w.o. action bar). We won't deepen in these topics - I think every one faced with these stuff (besides, internal implementation of these themes deserves own investigation). Just note that using these themes we got quite nice dialogs stylized for holographic themes.
This dialog boxes were quite limited in styling - to perform even small changes in dialog positioning or appearance sometimes developer had to engaged in a tedious search for correct property in appropriate style. Obviously, we can't have 2 activity in foreground, so the question about the 2 open dialogs at the same time no longer relevant. Also do not forget the 'heaviness' of Activities. But support of activity may be a partial compensation for previous inconvenience.

Let's look at alternative approach (in my opinion unjustly deprived of attention) - PopupWindow. Been present from very first sdk, PopupWindow wasn't very popular (at least, I could not find more information than simple example how to create simple popup window). In my opinion, this is very configurable container, which gives us much more advantages than activity-dialog, so let's look on it closer.
First of all, there are 2 views to hold content:
   private View mContentView;  
   private View mPopupView;  

Depending on whether was mBackground provided or not (using PopupWindow#setBackgroundDrawable) mPopupView will be assigned whole mContentView or even composite PopupViewContainer (FrameLayout actually):
   private void preparePopup(WindowManager.LayoutParams p) {  
     ...  
     if (mBackground != null) {  
       final ViewGroup.LayoutParams layoutParams = mContentView.getLayoutParams();  
       int height = ViewGroup.LayoutParams.MATCH_PARENT;  
       if (layoutParams != null &&  
           layoutParams.height == ViewGroup.LayoutParams.WRAP_CONTENT) {  
         height = ViewGroup.LayoutParams.WRAP_CONTENT;  
       }  
       // when a background is available, we embed the content view  
       // within another view that owns the background drawable  
       PopupViewContainer popupViewContainer = new PopupViewContainer(mContext);  
       PopupViewContainer.LayoutParams listParams = new PopupViewContainer.LayoutParams(  
           ViewGroup.LayoutParams.MATCH_PARENT, height  
       );  
       popupViewContainer.setBackgroundDrawable(mBackground);  
       popupViewContainer.addView(mContentView, listParams);  
       mPopupView = popupViewContainer;  
     } else {  
       mPopupView = mContentView;  
     }  
     ...  
   }  
PopupViewContainer is a key point to answer on frequently asked question 'why do we need set setBackgroundDrawable to close our popup window when outside area is touched?' - PopupViewContainer is listening to the touch event and dismisses popup window:
     @Override  
     public boolean onTouchEvent(MotionEvent event) {  
       final int x = (int) event.getX();  
       final int y = (int) event.getY();  
       if ((event.getAction() == MotionEvent.ACTION_DOWN)  
           && ((x < 0) || (x >= getWidth()) || (y < 0) || (y >= getHeight()))) {  
         dismiss();  
         return true;  
       } else if (event.getAction() == MotionEvent.ACTION_OUTSIDE) {  
         dismiss();  
         return true;  
       } else {  
         return super.onTouchEvent(event);  
       }  
     }  
Content of PopupWindow is added to Activity by WindowManager (ViewManager#addView method is used). We are not limited in number of PopupWindows that can be added to page. But since ViewManager#addView creates new 'layer' for every PopupWindow they will be closed (in case of touch at outside area) in reverse order about how they were added.
From the fact that content of PopupWindow is View follows that we can apply animations to dialog box (using, for example, View#startAnimation). It may be useful when we want to show/hide dialog box with move effect or something like this (this often happens when we copy the behavior of ios apps :))
Finally, very often problem when you tried to create to show PopupWindow from activity lifecycle method:
 E/AndroidRuntime( 524): java.lang.RuntimeException: Unable to resume activity {packagename/packagename.ActivityName}: android.view.WindowManager$BadTokenException: Unable to add window -- token null is not valid; is your activity running?  

For those who haven't faced this problem here is solution: add your popup window showing to the message queue (using post method) to be run after all the lifecycle methods finish:
     viewRoot.post(new Runnable() {  
       public void run() {  
         popupWindow.showAtLocation(viewRoot, Gravity.TOP | Gravity.LEFT, 0, 0);  
       }  
     });  
Looks like this is essential requirement. I couldn't find explanation why this happens, looks like we have to wait until everything in Activity is set up.
Summing up, I want to say, that PopupWindow is a great choice when you need lightweight (and configurable) mechanism to communicate with user.

Thursday, April 12, 2012

Where am I?

When your mobile application requires registration quite often user's location become a relevant question. It's very convenient when registration form contains your location (at least country) preselected. I know at least 3 ways to do this in Android (each with its own advantages and disadvantages):
  1. using Locale:
  2.      Locale myLocale = Locale.getDefault();      
    
    This is the easiest and probably most incorrect way. Actually, locale represents not current user's language/country combination, but values selected in Android Settings. For example, when selected locale is English (South Africa) your locale object will tell you, that your country code (Locale#getCountry) is ZA and your country name (Locale#getDisplayCountry) is South Africa. In principle, all is correct. But it's possible to select not your current locale. Moreover, your locale may not be available on your device. In this case it's not possible to determine your country using this approach. So that the only advantage of this approach is ease of implementation. Also no need for internet connection in this case but it is unlikely that this is a great advantage.
  3. using TelephonyManager:
  4.      TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);  
         String iso = telephonyManager.getNetworkCountryIso();   
    
    TelephonyManager#getNetworkCountryIso due to documentation:
    Returns the ISO country code equivalent of the current registered operator's MCC (Mobile Country Code). Availability: Only when user is registered to a network. Result may be unreliable on CDMA networks (use getPhoneType() to determine if on a CDMA network).
    So, it's good technique, but requirement to be registered in the mobile network is a very serious limitation especially for tablets.
  5. using LocationManager:
  6. Imho, the most accurate solution which based on real geographical location. It's requires internet connection and permission to collect your location data:


    It also requires permission in manifest:
     <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>  
    

    And finally:
         LocationManager mlocManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);  
         LocationListener mlocListener = new LocationListener() {  
           @Override  
           public void onLocationChanged(Location location) {  
             final Geocoder geocoder = new Geocoder(GApp.sInstance.getApplicationContext());  
             try {  
               List<Address> addresses = geocoder.getFromLocation(location.getLatitude(), location.getLongitude(), 1);  
               if (addresses != null) {  
                 Address address = addresses.get(0);  
               }  
             } catch (Exception e) {  
               e.printStackTrace();  
             }  
           }  
           @Override  
           public void onStatusChanged(String s, int i, Bundle bundle) {  
           }  
           @Override  
           public void onProviderEnabled(String s) {  
           }  
           @Override  
           public void onProviderDisabled(String s) {  
           }  
         };  
         mlocManager.requestLocationUpdates( LocationManager.NETWORK_PROVIDER, 0, 0, mlocListener);  
    
    It is a little bit more complicated than the previous two methods, but using Address we are able to identify not just current country, but also city (Address#getLocality) and even some thoroughfare (Address#getThoroughfare).

Saturday, April 7, 2012

Inside AsyncTask

Most likely, AsynkTask is used by every Android developer. Being very simple and limited in earlier Android, AsyncTask became powerful instrument since 11 (first Honeycomb) sdk. But in some reason, this very useful class was deprived of due attention in official documentation, which doesn't cover even half of object's scalability and power. Let's skip all the obvious things, that can be read in variety of documents (including official documentation) and take a look inside AsyncTask.
First of all, every background operation (AsyncTask#doInBackground) is executed (submitted) by Executor, i.e. system reserves static thread pool to optimize process of previously created threads reusing (since new Thread creation is quite expensive operation). Second, in the evolution of Android SDK this Executor has undergone significant changes: been finally defined in early sdk:
 private static final ThreadPoolExecutor sExecutor = ... 
it became flexible for Honeycomb sdk:
private static volatile Executor sDefaultExecutor

Old implementation is not very interesting and quite boring, so let's take a look to the new one. It offers us 2 different implementation for Executor to cover different execution strategy: one is used to execute tasks in parallel, another - one task at time in serial order (of course, serialization is global to a particular process only). Despite the fact, that synchronous execution is default, during debug we can see, that parallel executor is used by default (most likely it's set by AsynkTask#setDefaultExecutor method).

Let's look closely to proposed implementations. First is parallel executor. This approach is inherited from old sdk and default for sdk 11 and above:
   /**  
    * An {@link Executor} that can be used to execute tasks in parallel.  
    */  
   public static final Executor THREAD_POOL_EXECUTOR  
       = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,  
           TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);  

   private static final int CORE_POOL_SIZE = 5;  
   private static final int MAXIMUM_POOL_SIZE = 128;  
   private static final int KEEP_ALIVE = 1;  

   private static final BlockingQueue<Runnable> sPoolWorkQueue =  
       new LinkedBlockingQueue<Runnable>(10);  

   private static final ThreadFactory sThreadFactory = new ThreadFactory() {  
     private final AtomicInteger mCount = new AtomicInteger(1);  
     public Thread newThread(Runnable r) {  
       return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());  
     }  
   };  

So, as we can see, pool is keeping 5 threads, whereas max number of available threads is 128. I think this is enough. Task are waiting for their turn to execution in BlockingQueue.

Synchronous executor is based on parallel:
   private static class SerialExecutor implements Executor {  
     final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();  
     Runnable mActive;  
     public synchronized void execute(final Runnable r) {  
       mTasks.offer(new Runnable() {  
         public void run() {  
           try {  
             r.run();  
           } finally {  
             scheduleNext();  
           }  
         }  
       });  
       if (mActive == null) {  
         scheduleNext();  
       }  
     }  
     protected synchronized void scheduleNext() {  
       if ((mActive = mTasks.poll()) != null) {  
         THREAD_POOL_EXECUTOR.execute(mActive);  
       }  
     }  
   }  
For this executor ArrayDeque is used as tasks holder. It's a good choice, since we don't need internal synchronization. Before actual task submission executor checks that we don't have active task now and schedule new only in this case. Consistency of tasks execution is provided by Runnable wrapper (this wrapper is created for every new task), which invokes scheduleNext at the end of it's execution. Direct submission is performed by THREAD_POOL_EXECUTOR.
Nothing forbids us to create own implementation for executor to meet our needs. How to use is will be considered below.

But first let's answer 2 questions: "how correct cancel of AsyncTask is ensured ?" and "why AsyncTask can be executed only once?". To answer these questions let's take a look constructor:
     private final WorkerRunnable<Params, Result> mWorker;  
     private final FutureTask<Result> mFuture;  
     
     public AsyncTask() {  
       mWorker = new WorkerRunnable<Params, Result>() {  
         public Result call() throws Exception {  
           ...  
         }  
       };  
       mFuture = new FutureTask<Result>(mWorker) {  
         @Override  
         protected void done() {  
           ...  
         }  
     }; 

     private static abstract class WorkerRunnable implements Callable {
         Params[] mParams;
     }
 

Callable mWorker is used to preserve input params and return result of computation (AsyncTask#doInBackground):
     
        mWorker = new WorkerRunnable() {
            public Result call() throws Exception {
                mTaskInvoked.set(true);

                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                return postResult(doInBackground(mParams));
            }
        };

Last expression of call method executes our asynchronous operation and posts result via internal handler to ui thread (by calling AsyncTask#onPostExecute). mFuture being a FutureTask can be submitted to an Executor for asynchronous execution:
     
    public final AsyncTask execute(Params... params) {
        return executeOnExecutor(sDefaultExecutor, params);
    }

    public final AsyncTask executeOnExecutor(Executor exec,
            Params... params) {
        if (mStatus != Status.PENDING) {
            switch (mStatus) {
                case RUNNING:
                    throw new IllegalStateException("Cannot execute task:"
                            + " the task is already running.");
                case FINISHED:
                    throw new IllegalStateException("Cannot execute task:"
                            + " the task has already been executed "
                            + "(a task can be executed only once)");
            }
        }

        mStatus = Status.RUNNING;

        onPreExecute();

        mWorker.mParams = params;
        exec.execute(mFuture);

        return this;
    }

Now we can easily answer our questions:
1) AsyncTask cancellation is performed by FutureTask#cancel
2) initial check in executeOnExecutor doesn't allow for AsyncTask to be executed more than once. It's essential since once the computation of FutureTask has completed, the computation cannot be restarted (it laid the internal basis for this object).

And in the end I want to consider two very "tasty" methods (available from sdk 11). First of them is
 public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,  
       Params... params)   
It's called with default (parallel) executor in AsyncTask#execute. But it's interesting for us because it allows to execute tasks with certain executor and we can use not only proposed by sdk, but own implementation too:
     new AsyncTask<Void, Void, String>() {  
       ...  
     }.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);  

Another very useful method in new api is
     public static void execute(Runnable runnable) {
        sDefaultExecutor.execute(runnable);
    }  

It allow us to execute our Runnables in global pool AsyncTask's global pool. This may freeing us of having own thread pools and save some system resource. Unfortunately, we can't change default executor. Here is example:
     new AsyncTask<Void, Void, String>() {  
       ...  
     }.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);  

Another very useful method in new api is
     public static void execute(Runnable runnable) {
        AsyncTask.execute(runnable);
    }  

Thank you for attention.

Sunday, April 1, 2012

Rich TextView

When we want to have beauty and stylish text we call html for help. According to Formatting and Styling document there are only 3 supported tags: b, i, and u. It also contains some mentions about fromHtml method, but it doesn't nearly cover some of the useful cases.
Let's taking closer to implementation. Containing not just CharSequence, but being able to convert this buffer to SpannableString (in setText method) TextView became powerful markup container (since SpannableString implements Spannable - interface for text whith markup objects). As for possible markup values within your string resources: in the depths of AssetManager we can see, that array of StringBlock is used to retrieve data from compiled string resources and return them via getString method. So, after considering applyStyles we can list supported tags:
  • <a href="">(supports attributes "href")
  • <annotation>
  • <b>
  • <big>
  • <font> (be aware, use "fgcolor" attribute instead "color")
  • <i>
  • <li>
  • <marquee>
  • <small>
  • <strike>
  • <sub>
  • <sup>
  • <tt>
  • <u>
  • <ul>

Html#fromHtml gives us even more. It uses HtmlToSpannedConverter, which supports:
  • <a href="">(supports attributes "href")
  • <b>
  • <big>
  • <blockquote>
  • <br>
  • <cite>
  • <dfn>
  • <div>
  • <em>
  • <font>(supports attributes "color" and "face")
  • <i>
  • <img>
  • <p>
  • <small>
  • <strong>
  • <sub>
  • <sup>
  • <tt>
  • <u>

Let's take a look to example. Here is strings.xml:
 <?xml version="1.0" encoding="utf-8"?>  
 <resources>  
   <string name="simple_raw_string">I\'m simple raw string</string>  
   <string name="html_string_1">  
     <font bgcolor='#ff440050'><b>I\'m</b> <i>html</i> <font fgcolor='#ffff5400'>string</font></font>  
   </string>  
   <string name="html_string_2"><![CDATA[  
     <em>I\'m</em> <font color=\'#0054ff\'>another</font> <br> <dfn>html</dfn> <big>string</big>]]>  
   </string>  
 </resources>  

Layout

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
              android:layout_width="fill_parent"
              android:layout_height="fill_parent">

    <TextView
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:text="@string/simple_raw_string"/>

    <TextView
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:text="@string/html_string_1"/>

    <TextView
            android:id="@+id/html_text"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"/>


</LinearLayout>
And main activity
   @Override  
   public void onCreate(Bundle savedInstanceState) {  
     super.onCreate(savedInstanceState);  
     setContentView(R.layout.layout);  
     ((TextView) findViewById(R.id.html_text)).setText(Html.fromHtml(getString(R.string.html_string_2)));  
   }  
And how it looks on device