Android Building Free Wallpapers App – Part 1

Today I am going to show to how to build a free wallpapers app using Picasa Web Albums API. In this tutorial you can learn how to integrate multiple android components like splash screen, navigation drawer, grid view, volley library in a single app.

As this tutorial seems very lengthy, I divided this into two parts. In 1st part we do all basic setup like creating the Picasa albums, planning the app design and creating the android project and write some reusable components required for the app. In the 2nd part the actual implementation of the app starts where we add one by one module to the app like splash screen, navigation drawer, grid view and other things to complete the app.

android free wallpapers app part 2

1. Prerequisite

As this app is a complete application we need to integrate several components together. Please go through below articles before getting into this tutorial as these concepts are main building blocks for this app.

1. How to implement Android Splash Screen This explains how to add a splash screen to your app when the app needs to make few HTTP calls and fetch some data before going in to actual app flow.

2. Android Sliding Menu using Navigation Drawer This article helps in adding a slider menu for the app where we can show list of categories for wallpapers.

3. Android working with Volley Library We use volley to make network calls like downloading the json and images. Also another main advantage of using volley is image cache which makes the app faster.

4. Android Full Screen Image Slider with Swipe and Pinch Zoom Gestures This is another important article helps in creating the app’s main Grid View screen where the thumbnail preview of each wallpaper will be displayed in a grid fashion.

2. Google’s Picasa Web Albums API

The major and difficult task in this app is building the server side components like an admin panel to manage your wallpaper data by providing file upload option and other things. For this you should also able to code in other technologies like HTML, CSS, JSP, PHP or MySQL which is again a difficult task for android beginners.

So I selected Picasa Web Albums as a robust solution for this. Picasa web albums is free of cost and importantly it exposes an API (json and xml) for developers. You can go through Picasa Web Albums Data API to know more about the API’s exposed.

We are specifically interested in following API calls for this app which doesn’t require any authentication as we perform read operations only on public albums.

1. Request a list of albums
(username should be replaced with your Google username)

https://picasaweb.google.com/data/feed/api/user/username?kind=album&alt=json

2. List photos recently uploaded
(username should be replaced with your Google username)

https://picasaweb.google.com/data/feed/api/user/username?kind=photo&alt=json

3. List photos in album
(albumid should be replaced with actual album id which can find in albums response)

https://picasaweb.google.com/data/feed/api/user/username/albumid/albumid?alt=json

If you want to provide more options like providing user to comment, edit or delete options you need to implement authentication as mentioned in the document.

Hint: alt parameter decides the type of response we are expecting either json or xml. Pass alt=json in the url to get the response in JSON format.

3. Adding wallpapers in Picasa Web Albums

Before starting the app, we’ll add few wallpapers in Picasa albums for testing. You can login into Picasa using your Google account. Follow below steps to create albums and wallpapers in Picasa web albums.

1. Login into Picasa.
(If you are redirected to your Google+ account, click on Click here to go back to Picasa Web Albums to navigate back to Picasa Web or go with Google+ if you are comfortable)

2. Click on upload and enter your album name. These albums act as wallpaper categories in our app which will be listed in navigation drawer menu. Example: Animals, Cars, Food, Movies, Vintage etc.,

3. Once you created the album, upload few wallpapers to the album. Make sure that you are uploading the wallpapers with good high resolution.

4. Now make the album visibility as Public by clicking on Edit link displayed on the right. Note: If you don’t make your album as public, it will not be accessible via your android app. In other words you can’t see the album in the json response.

5. Follow 2nd, 3rd and 4th steps to create few more albums and wallpapers.

Checkout the below video which takes you through uploading process.


4. Designing The App

The design of this app is very minimalistic with very few color combinations. Overall it contains following components.

1. Navigation drawer (Slider Menu) to display wallpaper categories.
2. Grid view screen to display the thumbnail of wallpapers under a category.
3. Full screen view of wallpaper with Set As Wallpaper and Download Wallpaper options.
4. Settings screen to configure Picasa username, number of columns in grid and gallery image directory.

Below are screen shots of the final app.

Splash Screen

android freewallpapers app splash screen

Navigation Drawer

android wallpapers navigation drawer

Wallpapers thumbnail view

android wallpapers app grid view

Full screen view with Set As Wallpaper and Download options

android wallpapers app fullscreen view

Settings view

android wallpapers settings screen

5. Downloading Volley Library (volley.jar)

To make calls to Picasa API we are going to use Volley Library instead of using the java library mentioned in the documentation. I already published an article about Volley Library explaining about the advantages of choosing volley. In this project it plays a major role in caching the images.

Download the precompiled volley.jar

Now it’s time to start the android app. I am naming this app as Awesome Wallpapers.

6. Creating New Project

1. In Eclipse create a new project by navigating to File ⇒ New ⇒ Android Application Project and fill required details. I gave my project package name as info.androidhive.awesomewallpapers

2. Once the project is created paste the volley.jar in libs folder.

3. Download the resources and place them in your project’s respective folders. In this downloaded zip you will find splash screen background image and other app icons.

4. Now add below resource values in strings.xml, colors.xml. These values are used in various places in the project.

strings.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <string name="app_name">Awesome Wallpapers</string>
    <string name="action_settings">Settings</string>
    <string name="nav_drawer_recently_added">Recently Added</string>
    <string name="toast_saved">Wallpapaer saved to #</string>
    <string name="toast_saved_failed">Sorry! Failed to save wallpaper</string>
    <string name="toast_wallpaper_set">Wallpapaer updated!</string>
    <string name="toast_wallpaper_set_failed">Sorry! Unable to set wallpapaer</string>
    <string name="splash_error">Unable to download wallpapers. Verify your google\'s user name in settings or device doesn\'t have internet connection!</string>
    <string name="set_wallpaper">Set</string>
    <string name="download_wallpaper">Download</string>
    <string name="msg_unknown_error">Sorry! Unknown error occurred.</string>
    <string name="msg_wall_fetch_error">Sorry! Unable to fetch wallpaper(s). Verify app settings or device doesn\'t have internet connection.</string>
    <string name="toast_enter_google_username">Please enter google username</string>
    <string name="toast_enter_valid_grid_columns">Please enter valid number of columns</string>
    <string name="toast_enter_gallery_name">Please enter gallery directory name</string>
    <string name="lbl_google_username">Google username</string>
    <string name="lbl_no_grid_columns">Number of grid columns</string>
    <string name="lbl_gallery_name">Gallery directory name</string>
    <string name="lbl_btn_save">Save</string>

</resources>

colors.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <color name="list_item_title">#d7ddee</color>
    <color name="list_background">#1a1b1d</color>
    <color name="list_background_pressed">#131315</color>
    <color name="list_divider">#272727</color>
    <color name="counter_text_bg">#626262</color>
    <color name="counter_text_color">#c5c4c4</color>
    <color name="black">#000000</color>
    <color name="grid_bg">#000000</color>
    <color name="grid_item_bg">#1a1b1d</color>
    <color name="action_bar">#141416</color>
    <color name="action_bar_title">#ffffff</color>
    <color name="white">#ffffff</color>
    <color name="settings_label">#323232</color>

</resources>

5. Now create five packages named app, helper, util and picasa.model under src folder. Right Click on src ⇒ New ⇒ Package.

info.androidhive.awesomewallpapers.app
info.androidhive.awesomewallpapers.helper
info.androidhive.awesomewallpapers.picasa.model
info.androidhive.awesomewallpapers.util

6. Now create AppConst.java in app package. All the app configuration like google username, picasa api urls, gallery directory name and other static variables goes in this class.

package info.androidhive.awesomewallpapers.app;


public class AppConst {

	// Number of columns of Grid View
	// by default 2 but user can configure this in settings activity
	public static final int NUM_OF_COLUMNS = 2;

	// Gridview image padding
	public static final int GRID_PADDING = 4; // in dp

	// Gallery directory name to save wallpapers
	public static final String SDCARD_DIR_NAME = "Awesome Wallpapers";

	// Picasa/Google web album username
	public static final String PICASA_USER = "freewallpapersapp";

	// Public albums list url
	public static final String URL_PICASA_ALBUMS = "https://picasaweb.google.com/data/feed/api/user/_PICASA_USER_?kind=album&alt=json";

	// Picasa album photos url
	public static final String URL_ALBUM_PHOTOS = "https://picasaweb.google.com/data/feed/api/user/_PICASA_USER_/albumid/_ALBUM_ID_?alt=json";

	// Picasa recenlty added photos url
	public static final String URL_RECENTLY_ADDED = "https://picasaweb.google.com/data/feed/api/user/_PICASA_USER_?kind=photo&alt=json";

}

7. Create another class named AppController.java under app package. This class extends from Application and this is a singleton class which initializes volley’s core objects and few other classes those can be used across the app.

package info.androidhive.awesomewallpapers.app;

import info.androidhive.awesomewallpapers.util.LruBitmapCache;
import info.androidhive.awesomewallpapers.util.PrefManager;
import android.app.Application;
import android.text.TextUtils;

import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.toolbox.ImageLoader;
import com.android.volley.toolbox.Volley;

public class AppController extends Application {

	public static final String TAG = AppController.class.getSimpleName();

	private RequestQueue mRequestQueue;
	private ImageLoader mImageLoader;
	LruBitmapCache mLruBitmapCache;

	private static AppController mInstance;
	private PrefManager pref;

	@Override
	public void onCreate() {
		super.onCreate();
		mInstance = this;
		pref = new PrefManager(this);
	}

	public static synchronized AppController getInstance() {
		return mInstance;
	}

	public PrefManager getPrefManger() {
		if (pref == null) {
			pref = new PrefManager(this);
		}

		return pref;
	}

	public RequestQueue getRequestQueue() {
		if (mRequestQueue == null) {
			mRequestQueue = Volley.newRequestQueue(getApplicationContext());
		}

		return mRequestQueue;
	}

	public ImageLoader getImageLoader() {
		getRequestQueue();
		if (mImageLoader == null) {
			getLruBitmapCache();
			mImageLoader = new ImageLoader(this.mRequestQueue, mLruBitmapCache);
		}

		return this.mImageLoader;
	}

	public LruBitmapCache getLruBitmapCache() {
		if (mLruBitmapCache == null)
			mLruBitmapCache = new LruBitmapCache();
		return this.mLruBitmapCache;
	}

	public <T> void addToRequestQueue(Request<T> req, String tag) {
		req.setTag(TextUtils.isEmpty(tag) ? TAG : tag);
		getRequestQueue().add(req);
	}

	public <T> void addToRequestQueue(Request<T> req) {
		req.setTag(TAG);
		getRequestQueue().add(req);
	}

	public void cancelPendingRequests(Object tag) {
		if (mRequestQueue != null) {
			mRequestQueue.cancelAll(tag);
		}
	}
}

8. Create Utils.java under util package. This class contains few helper methods.

package info.androidhive.awesomewallpapers.util;

import info.androidhive.awesomewallpapers.R;

import java.io.File;
import java.io.FileOutputStream;
import java.util.Random;

import android.app.WallpaperManager;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Point;
import android.os.Environment;
import android.util.Log;
import android.view.Display;
import android.view.WindowManager;
import android.widget.Toast;

public class Utils {
	private String TAG = Utils.class.getSimpleName();
	private Context _context;
	private PrefManager pref;

	// constructor
	public Utils(Context context) {
		this._context = context;
		pref = new PrefManager(_context);
	}

	/*
	 * getting screen width
	 */
	@SuppressWarnings("deprecation")
	public int getScreenWidth() {
		int columnWidth;
		WindowManager wm = (WindowManager) _context
				.getSystemService(Context.WINDOW_SERVICE);
		Display display = wm.getDefaultDisplay();

		final Point point = new Point();
		try {
			display.getSize(point);
		} catch (java.lang.NoSuchMethodError ignore) {
			// Older device
			point.x = display.getWidth();
			point.y = display.getHeight();
		}
		columnWidth = point.x;
		return columnWidth;
	}

	public void saveImageToSDCard(Bitmap bitmap) {
		File myDir = new File(
				Environment
						.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),
				pref.getGalleryName());

		myDir.mkdirs();
		Random generator = new Random();
		int n = 10000;
		n = generator.nextInt(n);
		String fname = "Wallpaper-" + n + ".jpg";
		File file = new File(myDir, fname);
		if (file.exists())
			file.delete();
		try {
			FileOutputStream out = new FileOutputStream(file);
			bitmap.compress(Bitmap.CompressFormat.JPEG, 90, out);
			out.flush();
			out.close();
			Toast.makeText(
					_context,
					_context.getString(R.string.toast_saved).replace("#",
							"\"" + pref.getGalleryName() + "\""),
					Toast.LENGTH_SHORT).show();
			Log.d(TAG, "Wallpaper saved to: " + file.getAbsolutePath());

		} catch (Exception e) {
			e.printStackTrace();
			Toast.makeText(_context,
					_context.getString(R.string.toast_saved_failed),
					Toast.LENGTH_SHORT).show();
		}
	}

	public void setAsWallpaper(Bitmap bitmap) {
		try {
			WallpaperManager wm = WallpaperManager.getInstance(_context);

			wm.setBitmap(bitmap);
			Toast.makeText(_context,
					_context.getString(R.string.toast_wallpaper_set),
					Toast.LENGTH_SHORT).show();
		} catch (Exception e) {
			e.printStackTrace();
			Toast.makeText(_context,
					_context.getString(R.string.toast_wallpaper_set_failed),
					Toast.LENGTH_SHORT).show();
		}
	}
}

9. Create LruBitmapCache.java and paste the below code. This class used to keep the volley cached objects on the disk.

package info.androidhive.awesomewallpapers.util;

import com.android.volley.toolbox.ImageLoader.ImageCache;

import android.graphics.Bitmap;
import android.support.v4.util.LruCache;

public class LruBitmapCache extends LruCache<String, Bitmap> implements
		ImageCache {
	public static int getDefaultLruCacheSize() {
		final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
		final int cacheSize = maxMemory / 8;

		return cacheSize;
	}

	public LruBitmapCache() {
		this(getDefaultLruCacheSize());
	}

	public LruBitmapCache(int sizeInKiloBytes) {
		super(sizeInKiloBytes);
	}

	@Override
	protected int sizeOf(String key, Bitmap value) {
		return value.getRowBytes() * value.getHeight() / 1024;
	}

	@Override
	public Bitmap getBitmap(String url) {
		return get(url);
	}

	@Override
	public void putBitmap(String url, Bitmap bitmap) {
		put(url, bitmap);
	}
}

10. Create two classes named Category.java and Wallpaper.java under picasa.model package. These POJO classes will be useful while parsing the json data fetched from Picasa.

package info.androidhive.awesomewallpapers.picasa.model;

public class Category {
	public String id, title;

	public Category() {		
	}

	public Category(String id, String title) {		
		this.id = id;
		this.title = title;
	}

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public String getTitle() {
		return title;
	}

	public void setTitle(String title) {
		this.title = title;
	}
}
package info.androidhive.awesomewallpapers.picasa.model;

import java.io.Serializable;

public class Wallpaper implements Serializable {
	private static final long serialVersionUID = 1L;
	private String url, photoJson;
	private int width, height;

	public Wallpaper() {
	}

	public Wallpaper(String photoJson, String url, int width, int height) {		
		this.photoJson = photoJson;
		this.url = url;
		this.width = width;
		this.height = height;
	}

	public String getUrl() {
		return url;
	}

	public void setUrl(String url) {
		this.url = url;
	}

	public String getPhotoJson() {
		return photoJson;
	}

	public void setPhotoJson(String photoJson) {
		this.photoJson = photoJson;
	}

	public int getWidth() {
		return width;
	}

	public void setWidth(int width) {
		this.width = width;
	}

	public int getHeight() {
		return height;
	}

	public void setHeight(int height) {
		this.height = height;
	}
}

11. Finally create another class named PrefManager.java under utils package. This class takes care of storing the data in Shared Preferences. The data like google username, picasa wallpaper categories, gallery name and other things will be stored in shared preferences.

package info.androidhive.awesomewallpapers.util;

import info.androidhive.awesomewallpapers.app.AppConst;
import info.androidhive.awesomewallpapers.picasa.model.Category;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.util.Log;

import com.google.gson.Gson;

public class PrefManager {
	private static final String TAG = PrefManager.class.getSimpleName();

	// Shared Preferences
	SharedPreferences pref;

	// Editor for Shared preferences
	Editor editor;

	// Context
	Context _context;

	// Shared pref mode
	int PRIVATE_MODE = 0;

	// Sharedpref file name
	private static final String PREF_NAME = "AwesomeWallpapers";

	// Google's username
	private static final String KEY_GOOGLE_USERNAME = "google_username";

	// No of grid columns
	private static final String KEY_NO_OF_COLUMNS = "no_of_columns";

	// Gallery directory name
	private static final String KEY_GALLERY_NAME = "gallery_name";

	// gallery albums key
	private static final String KEY_ALBUMS = "albums";

	public PrefManager(Context context) {
		this._context = context;
		pref = _context.getSharedPreferences(PREF_NAME, PRIVATE_MODE);

	}

	/**
	 * Storing google username
	 * */
	public void setGoogleUsername(String googleUsername) {
		editor = pref.edit();

		editor.putString(KEY_GOOGLE_USERNAME, googleUsername);

		// commit changes
		editor.commit();
	}

	public String getGoogleUserName() {
		return pref.getString(KEY_GOOGLE_USERNAME, AppConst.PICASA_USER);
	}

	/**
	 * store number of grid columns
	 * */
	public void setNoOfGridColumns(int columns) {
		editor = pref.edit();

		editor.putInt(KEY_NO_OF_COLUMNS, columns);

		// commit changes
		editor.commit();
	}

	public int getNoOfGridColumns() {
		return pref.getInt(KEY_NO_OF_COLUMNS, AppConst.NUM_OF_COLUMNS);
	}

	/**
	 * storing gallery name
	 * */
	public void setGalleryName(String galleryName) {
		editor = pref.edit();

		editor.putString(KEY_GALLERY_NAME, galleryName);

		// commit changes
		editor.commit();
	}

	public String getGalleryName() {
		return pref.getString(KEY_GALLERY_NAME, AppConst.SDCARD_DIR_NAME);
	}

	/**
	 * Storing albums in shared preferences
	 * */
	public void storeCategories(List<Category> albums) {
		editor = pref.edit();
		Gson gson = new Gson();

		Log.d(TAG, "Albums: " + gson.toJson(albums));

		editor.putString(KEY_ALBUMS, gson.toJson(albums));

		// save changes
		editor.commit();
	}

	/**
	 * Fetching albums from shared preferences. Albums will be sorted before
	 * returning in alphabetical order
	 * */
	public List<Category> getCategories() {
		List<Category> albums = new ArrayList<Category>();

		if (pref.contains(KEY_ALBUMS)) {
			String json = pref.getString(KEY_ALBUMS, null);
			Gson gson = new Gson();
			Category[] albumArry = gson.fromJson(json, Category[].class);

			albums = Arrays.asList(albumArry);
			albums = new ArrayList<Category>(albums);
		} else
			return null;

		List<Category> allAlbums = albums;

		// Sort the albums in alphabetical order
		Collections.sort(allAlbums, new Comparator<Category>() {
			public int compare(Category a1, Category a2) {
				return a1.getTitle().compareToIgnoreCase(a2.getTitle());
			}
		});

		return allAlbums;

	}

	/**
	 * Comparing albums titles for sorting
	 * */
	public class CustomComparator implements Comparator<Category> {
		@Override
		public int compare(Category c1, Category c2) {
			return c1.getTitle().compareTo(c2.getTitle());
		}
	}
}

Now we have all the required classes in place. So let’s start adding one by one component to the app in Android Building Free Wallpapers App – Part 2

Ravi is hardcore Android programmer and Android programming has been his passion since he compiled his first hello-world program. Solving real problems of Android developers through tutorials has always been interesting part for him.