Android – Adding Custom cookies to a WebView

This is just a quick post about adding cookies to a web view. If you’ve ever tried to do this the way most people have said that it should be done, you’ve failed miserably and found this post. 🙂

The way it’s supposed to work is you set the cookie on the CookieManager and then tell the CookieSyncManager to sync.

1
2
CookieManager.getInstance().setCookie(domain, value);
CookieSyncManager.getInstance().sync();

I’ve never got this to work as described. With or without async tasks waiting for the threads to catch up.

Instead, I just add the cookie in the header of all the loadUrl calls.

1
2
3
Map<String, String> headers = new HashMap<String, String>();
headers.put("Cookie", "cookieName=cookieValue;domain=domain.com;path=/;Expires=Thu, 2 Aug 2021 20:47:11 UTC;");
webView.loadUrl("myurl.com", headers );

Caveat: I only need to initially load the appropriate cookie for the request, if you want to cover nested calls from inside the browser, you need to override shouldOverrideUrlLoading.

1
2
3
4
5
6
7
webView.setWebViewClient(new WebViewClient() {
     @Override
     public boolean shouldOverrideUrlLoading(WebView view, String url) {
         view.loadUrl(url, headers);
         return false;
     }
});

If you need to inject the cookie for all requests(including images, js, etc), you’re going to need to override shouldInterceptRequest, which I didn’t have to do so no example, sorry. Good luck!! 🙂

Volley HTTP library for Android with BasicAuth

Volley is an incredibly useful library for Android. It alleviates almost all of the headaches of asynchronous web service calls. Here’s a video of the Google I/O session on Volley that I was lucky enough to attend.

Use git to clone volley from here if you don’t have it already: https://android.googlesource.com/platform/frameworks/volley

I don’t want to go into the intro to Volley, there are tons of those blog posts out there already.

For my latest app that I’m working on, I had to extend it a small bit to get BasicAuth working so I thought I would share an example.

It’s pretty straightforward to get BasicAuth working. You just have to extend the type of request that you want to use. In my case, I had to extend JSONArrayRequest and JSONObjectRequest. Here’s the array extension class as an example. The object version is the same extension, just add the basic auth header in the constructor of the request class.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
package com.myapp.services;
 
import java.util.HashMap;
import java.util.Map;
 
import org.json.JSONArray;
 
import android.util.Base64;
 
import com.android.volley.AuthFailureError;
import com.android.volley.Response;
import com.android.volley.Response.ErrorListener;
import com.android.volley.Response.Listener;
import com.android.volley.toolbox.JsonArrayRequest;
 
public class MyArrayRequest extends JsonArrayRequest{
 
	public MyArrayRequest(String url, JSONArray jsonRequest,
			Listener<JSONArray> listener, ErrorListener errorListener) {
		super(url, listener, errorListener);
	}
 
	public MyArrayRequest(String url, Response.Listener<JSONArray> listener,
						Response.ErrorListener errorListener, String username, String password) {
		super(url, listener, errorListener);
		if (username != null && password != null) {
			String loginEncoded = new String(Base64.encode((username + ":" + password).getBytes(), Base64.NO_WRAP));
			this.headers.put("Authorization", "Basic " + loginEncoded);
		}
	}
 
	private Map<String, String> headers = new HashMap<String, String>();
		@Override
		public Map<String, String> getHeaders() throws AuthFailureError {
			return headers;
	}
 
	public void setHeader(String title, String content) {
		headers.put(title, content);
	}
}

I’m going to Google I/O finally!

I always got the short end of the stick on trying to get a ticket in real time. It always is an insta-sellout faster than a Dave Chappelle show. Luckily, a friend called in a favor and I got invited!!

I can’t wait!!!!!!!

One APK to rule them all

I wrote this a while back on a forum post and never posted it here. I figured it was good information and could help other Android nerds as well.

Having one apk to rule them all is a tricky thing to manage. I just recently launched with normal, large, and xlarge layouts along with landscape for large and xlarge. It is not easy, it takes a ton of regression testing, but is totally worth it.

There are some people that are developing separate apps for tablet. I wouldn’t recommend it, personally. Maybe if you pull out all business logic and throw it in a library it may be easier but there would still be a ton of redundant work. Abstract out the work of building out the views, and that will allow you to manage each resolution re-using the same techniques.

One tip is to have a very easily accessible flag that allows you to differentiate which device size you’re running on.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//check to see if we have a tablet, large or phone, and then set the global flag
int screenLayout = getResources().getConfiguration().screenLayout;
model.isTablet = 
   ((screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) == Configuration.SCREENLAYOUT_SIZE_XLARGE);
 
//if isTablet is false, check to see if we have a Large device, else
we have a phone
if(model.isTablet == false){
   model.isLarge = 
       ((screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) == Configuration.SCREENLAYOUT_SIZE_LARGE);
   if(model.isLarge){
      model.deviceSize = "Large";
   }else{
      model.deviceSize = "Phone";
   }
}else{
   model.deviceSize = "Tablet";
   model.isLarge = false;
}
 
//throw in a isLandscape if that matters as well. 
public boolean isLandscape(Context context) {
   int orientation = context.getResources().getConfiguration().orientation;
   return (orientation == Configuration.ORIENTATION_LANDSCAPE);
}

by using these flags on simple singleton model, you can easily build out the appropriate view for any scenario….except for small. just add a new flag for that 😉

Deep copy of Objects in C# Metro for Windows RT/WoA

Hey Guys! I don’t write blogs as much as I should. I swear I have tons of fun little snippets of code that I use all the time. I just don’t post them. :X

Here’s a great one that I’ve just finally figured out. Deep Copy in C# for Metro is very tricky. All the examples you will find are based on older version of .NET that aren’t included or are deprecated completely in Windows RTM.

Here is a super simple helper function that you can easily throw in an extension class.
 

using System.IO;
using System.Runtime.Serialization;
using Windows.Foundation;

namespace Extensions
{
#pragma warning disable 1591
    public static class ObjectExtension
    {
        public static Object DeepCopy(this Object objectToCopy)
        {
            Object copy;
            DataContractSerializer serializer = new DataContractSerializer(typeof(Object));
            using (MemoryStream ms = new MemoryStream())
            {
                serializer.WriteObject(ms, objectToCopy);
                ms.Position = 0;
                copy = (Object)serializer.ReadObject(ms);
            }
            return copy;
        }
    }

#pragma warning restore 1591
}

In the example class above, you can easily swap out Object for any Class type you want. I wanted to make this generic but couldn’t get it working. If you can, more power to ya! 🙂

I personally have a Data object in place of Object. One gotcha that you may run into is classes with an ImageSource property or another property that can’t be serialized. You need to add these metadata tags to your class to define which properties are supposed to be copied and which are ignored.

[DataContract]
class DataClass

[DataMember]
String title { get; set;}

[IgnoreDataMember]
ImageSource imageSource { get; set;}

More info can be found in the msdn: http://msdn.microsoft.com/en-us/library/system.runtime.serialization.datacontractserializer.aspx

Android Gallery convertView is always null

As the title says, a long standing bug has been hindering experience for the developers who use Android’s out of the box solution for a Gallery component.

The problem actually lies inside the getView method which is inherited from BaseAdapter->Adapter. One of the parameters the method is expecting is a “recycled” instance of their adapter view, but it never arrives. It allows the developer to re-use the old view that was just swiped off the stage, instead of instantiating a new view. Instantiating a new view here is an expensive process during the time of scrolling. You want this time to be seamless to the user, not choppy if they scroll too fast back and forth. During every swipe, you quickly have to instantiate multiple instances while every view that falls off the viewing area literally falls into an abyss of nothingness, never to be seen again.

I solved this problem by managing my own Array of views in the Adapter class and indexed them based on position. Looking back at it now, it was somewhat of a lazy solution for reasons I go into below….but it works. 😉

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
    public SmallGameVO[] featuredItems;
 
    private SmallGameVO tempGame;
 
    private View[] viewArray;
 
    public FeaturedAdapter(Context c, SmallGameVO[] featuredGames) {
 		featuredItems = featuredGames;
 		viewArray =  new View[featuredItems.length];
    }
 
    public int getCount() {
        return featuredItems.length;
    }
 
    public Object getItem(int position) {
        return position;
    }
 
    public long getItemId(int position) {
        return position;
    }
 
 
    public View getView(int position, View convertView, ViewGroup parent) {	   	
  		LayoutInflater linflater = (LayoutInflater) parent.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);			
  		LinearLayout tempView = null;
 
                if(convertView != null){
    		        NVDebug.log("re-using the convertView!");
    		        tempView = convertView;
    	        }else{
                        //no convertView, need to do the heavy lifting ourselves
                        //check our viewArray to see if we have a view at the position or we need to create a new one
 
				if(viewArray[position] != null){					
					tempView = (LinearLayout) viewArray[i];
					break;					
				} else {					
					tempView = (LinearLayout) linflater.inflate(R.layout.feature_gallery_capsule, null);
					viewArray[position] = tempView;
					break;					
				}
			}	
    	         }
 
    	        NVWebImageView img = (NVWebImageView) tempView.findViewById(R.id.galleryImage);
 
		if(position <= featuredItems.length - 1){			
			tempGame = featuredItems[position];
			if(img.imageUrl != tempGame.getFeaturedImage()){
				img.setImageUrl(tempGame.getFeaturedImage());
				img.loadImage();
			}		
		}else{
			tempView = new LinearLayout(parent.getContext());
		}    	
 
        return tempView;
    }

This wouldn’t be the best idea for situations where you have a larger number of items(20+) in your gallery. In that situation, I would recommend implementing you’re own “cache” of views at your disposal. Depending on the size of the view, you really only have 4-5 views in the viewing area at one time, so it’s pretty easy to see how you could manage them swiping to the n-th scale if needed with an array of just 10 views. Luckily, my gallery will never go higher than 10-15.

So that’s it, nothing too fancy. Just instead of relying on the view to be there, waste some space and make your own array of views. 🙂

Tegra Zone coming soon….

We just announced the Android app that I’ve been working on. It’s getting a ton of press and is really going to be a game changer for the Tegra 2 devices that are coming out. The users are going to get some great differentiated content optimized for their device. There’s a ton of really awesome games finally coming to Android. It’s been pretty bleak in the Market for a long time. 3D games are few and far between. The unreal engine is going to bring PC quality titles to your phone/tablet with cross platform multiplayer over 4g.

http://www.nvidia.com/object/tegra-zone.html

Obligatory press 😛
http://www.engadget.com/2011/01/07/nvidia-shows-off-tegra-2-gameplay-on-atrix-4g-and-optimus-2x/
http://www.androidcentral.com/android-centrals-best-ces-2011
http://androidcommunity.com/nvidia-tegra-zone-coming-to-android-market-20110112/
http://techie-buzz.com/mobile-news/nvidia-tegra-zone-android-market-games.html

Android 2.2 -> Android 2.3 Rating Bar changes

There isn’t anything mentioned in the API differences or anywhere that I can find so far, on changes made to the underlying skin of the RatingBar component.

If you have a rating bar in your 2.2 project using Widget.RatingBar.Small as a parent for your custom skin, you’ll most likely see a weird background skin now surrounding your rating bar. This could be the AbsSeekBar or ProgressBar, but to me it looks like a ToggleButton. Regardless, it’s not your desired look and here’s how to get rid of it. Just remove the .Small from Widget.RatingBar.Small and make sure you have set min/max heights for your stars so they shrink or grow to your desired size.

ps. I’ll get an example once I get a good enough plugin that doesn’t crash my wordpress when I drop some XML in it. 🙂

Android Gallery and bad performance gotcha

If you’re using the Gallery component from android and experiencing “snappy” animations when your item is selected, you’re most likely doing too much in the UI thread OnItemSelected.

Always try and create a separate thread to do expensive tasks so your UI thread can keep the user happy. Also, look for ways to optimize what you’re trying to do in that method. For instance, instead of swapping out resources to reflect a UI update, make a stateful skin.