In the 1st Part we prepared required classes for this app. In this we’ll start adding one by one screen to the app and at the end of the article we should be able to complete the application.

android-free-wallpapers-app-banner-2

Styling The Action Bar

12. You might noticed that this app action bar is having customized background color. That can be done by defining a custom theme in res ⇒ values ⇒ styles.xml folder. Also this is not a complete action bar customization. I am just changing the background color of it.

If you want to customize it completely, Styling the Action Bar will helps you. Add below code in res ⇒ values ⇒ styles.xml. If you don’t find styles.xml, create a new file in values folder.

<resources>

    <style name="FreeWallTheme" parent="@android:style/Theme.Holo.Light">
        <item name="android:actionBarStyle">@style/MyActionBarTheme</item>
        <item name="android:actionOverflowButtonStyle">@style/OverFlow</item>
    </style>

    <style name="MyActionBarTheme" parent="@android:style/Widget.Holo.Light.ActionBar">
        <item name="android:background">@color/action_bar</item>
        <item name="android:titleTextStyle">@style/TitleTextStyle</item>
    </style>

    <style name="TitleTextStyle" parent="android:TextAppearance.Holo.Widget.ActionBar.Title">
        <item name="android:textColor">@color/action_bar_title</item>
    </style>

    <style name="OverFlow" parent="android:style/Widget.Holo.ActionButton.Overflow">
        <item name="android:src">@drawable/ic_action_overflow</item>
    </style>

</resources>

13. Now in order to apply this style, open the AndroidManifest.xml file and add the style using android:theme attribute for tag. Also add below permissions too.

INTERNET – To consume internet
WRITE_EXTERNAL_STORAGE – To store wallpapers in SDCard
SET_WALLPAPER – To update the device wallpaper

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="info.androidhive.awesomewallpapers"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="14"
        android:targetSdkVersion="19" />

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.SET_WALLPAPER" />

    <application
        android:name="info.androidhive.awesomewallpapers.app.AppController"
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/FreeWallTheme" >
        <!-- all the activities goes here -->
    </application>

</manifest>

Now if you run the app, you should see the action bar color changed.

Adding the Splash Screen

Splash screens are not necessary for every app. But for our app it make sense to have a splash screen as we have to download wallpapers categories before going into the app. In brief we make a request to Picasa to get list of public albums (in our case those are wallpapers categories) and store them in shared preferences. So let’s create the necessary files for the splash screen.

14. Create an xml file named activity_splash.xml under res ⇒ layout folder.

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

    <ImageView android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:src="@drawable/splash_screen"
        android:scaleType="centerCrop"/>
    

</LinearLayout>
android freewallpapers app splash screen

15. Now create a class named SplashActivity.java in the app main package and paste the below code. Here we are making a json call to Picasa and fetching list of albums. Once albums are fetched we are storing them in Shared Preferences. Later these categories will be loaded into navigation drawer.

package info.androidhive.awesomewallpapers;

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

import java.util.ArrayList;
import java.util.List;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.Window;
import android.widget.Toast;

import com.android.volley.Request.Method;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.JsonObjectRequest;

public class SplashActivity extends Activity {
	private static final String TAG = SplashActivity.class.getSimpleName();
	private static final String TAG_FEED = "feed", TAG_ENTRY = "entry",
			TAG_GPHOTO_ID = "gphoto$id", TAG_T = "$t",
			TAG_ALBUM_TITLE = "title";

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		getWindow().requestFeature(Window.FEATURE_ACTION_BAR);
		getActionBar().hide();
		setContentView(R.layout.activity_splash);

		// Picasa request to get list of albums
		String url = AppConst.URL_PICASA_ALBUMS
				.replace("_PICASA_USER_", AppController.getInstance()
						.getPrefManger().getGoogleUserName());
		
		Log.d(TAG, "Albums request url: " + url);

		// Preparing volley's json object request
		JsonObjectRequest jsonObjReq = new JsonObjectRequest(Method.GET, url,
				null, new Response.Listener<JSONObject>() {

					@Override
					public void onResponse(JSONObject response) {
						Log.d(TAG, "Albums Response: " + response.toString());
						List<Category> albums = new ArrayList<Category>();
						try {
							// Parsing the json response
							JSONArray entry = response.getJSONObject(TAG_FEED)
									.getJSONArray(TAG_ENTRY);

							// loop through albums nodes and add them to album
							// list
							for (int i = 0; i < entry.length(); i++) {
								JSONObject albumObj = (JSONObject) entry.get(i);
								// album id
								String albumId = albumObj.getJSONObject(
										TAG_GPHOTO_ID).getString(TAG_T);

								// album title
								String albumTitle = albumObj.getJSONObject(
										TAG_ALBUM_TITLE).getString(TAG_T);

								Category album = new Category();
								album.setId(albumId);
								album.setTitle(albumTitle);

								// add album to list
								albums.add(album);

								Log.d(TAG, "Album Id: " + albumId
										+ ", Album Title: " + albumTitle);
							}

							// Store albums in shared pref
							AppController.getInstance().getPrefManger()
									.storeCategories(albums);

							// String the main activity
							Intent intent = new Intent(getApplicationContext(),
									MainActivity.class);
							startActivity(intent);
							// closing spalsh activity
							finish();

						} catch (JSONException e) {
							e.printStackTrace();
							Toast.makeText(getApplicationContext(),
									getString(R.string.msg_unknown_error),
									Toast.LENGTH_LONG).show();
						}

					}
				}, new Response.ErrorListener() {

					@Override
					public void onErrorResponse(VolleyError error) {
						Log.e(TAG, "Volley Error: " + error.getMessage());

						// show error toast
						Toast.makeText(getApplicationContext(),
								getString(R.string.splash_error),
								Toast.LENGTH_LONG).show();

						// Unable to fetch albums
						// check for existing Albums data in Shared Preferences
						if (AppController.getInstance().getPrefManger()
								.getCategories() != null && AppController.getInstance().getPrefManger()
								.getCategories().size() > 0) {
							// String the main activity
							Intent intent = new Intent(getApplicationContext(),
									MainActivity.class);
							startActivity(intent);
							// closing spalsh activity
							finish();
						} else {
							// Albums data not present in the shared preferences
							// Launch settings activity, so that user can modify
							// the settings

							Intent i = new Intent(SplashActivity.this,
									SettingsActivity.class);
							// clear all the activities
							i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
									| Intent.FLAG_ACTIVITY_CLEAR_TASK);
							startActivity(i);
						}

					}
				});

		// disable the cache for this request, so that it always fetches updated
		// json
		jsonObjReq.setShouldCache(false);

		// Making the request
		AppController.getInstance().addToRequestQueue(jsonObjReq);

	}

}

16. Now add the SplashActivity as launcher activity in the AndroidManifest.xml inside <application>

   <application ....>
        <activity
            android:name="info.androidhive.awesomewallpapers.SplashActivity"
            android:label="@string/app_name"
            android:screenOrientation="portrait" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

Now if you run the app, you should see albums json logged in LogCat. If yes, we can move to the next step i.e adding navigation drawer and displaying the wallpaper categories.

Adding Navigation Drawer

Before following this step make sure that you read Android Sliding Menu using Navigation Drawer tutorial to make this step simple for you. To add navigation drawer, we need to create fewer layouts and classes.

17. Create drawer_list_item.xml under res ⇒ layout directory. This is the layout file for navigation drawer list item to display wallpaper category name.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="48dp" 
    android:background="@drawable/list_selector">

    <TextView
        android:id="@+id/title"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_alignParentLeft="true"        
        android:minHeight="?android:attr/listPreferredItemHeightSmall"
        android:textAppearance="?android:attr/textAppearanceListItemSmall"
        android:textColor="@color/list_item_title"
        android:gravity="center_vertical"
        android:paddingRight="10dp"
        android:paddingLeft="10dp"/>

</RelativeLayout>

18. Create NavDrawerItem.java in your project’s main package and paste the below code. This is a model class for navigation list item.

19. Now we need to create the custom list adapter class which provides data to navigation list view. Create a class named NavDrawerListAdapter.java under adapter package. This adapter class inflates the drawer_list_item.xml layout by displaying appropriate wallpaper category name.

20. Now we need to create a list view element in our main activity. Create an xml named activity_main.xml with the below content.

<android.support.v4.widget.DrawerLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <!-- Framelayout to display Fragments -->
    <FrameLayout
        android:id="@+id/frame_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <!-- Listview to display slider menu -->
    <ListView
        android:id="@+id/list_slidermenu"
        android:layout_width="240dp"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:choiceMode="singleChoice"
        android:divider="@color/list_divider"
        android:dividerHeight="1dp"        
        android:listSelector="@drawable/list_selector"
        android:background="@color/list_background"/>
</android.support.v4.widget.DrawerLayout>

21. Open your main activity class (in my case MainActivity.java) and add the below code. Eclipse might show you errors on the lines where you see GridFragment. For now comment those lines.

package info.androidhive.awesomewallpapers;

import info.androidhive.awesomewallpapers.app.AppController;
import info.androidhive.awesomewallpapers.helper.NavDrawerListAdapter;
import info.androidhive.awesomewallpapers.picasa.model.Category;

import java.util.ArrayList;
import java.util.List;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentManager;
import android.content.Intent;
import android.content.res.Configuration;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.support.v4.app.ActionBarDrawerToggle;
import android.support.v4.widget.DrawerLayout;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;

public class MainActivity extends Activity {
	private static final String TAG = MainActivity.class.getSimpleName();
	private DrawerLayout mDrawerLayout;
	private ListView mDrawerList;
	private ActionBarDrawerToggle mDrawerToggle;

	// Navigation drawer title
	private CharSequence mDrawerTitle;
	private CharSequence mTitle;
	private List<Category> albumsList;
	private ArrayList<NavDrawerItem> navDrawerItems;
	private NavDrawerListAdapter adapter;

	@SuppressLint("NewApi")
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		mTitle = mDrawerTitle = getTitle();

		mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
		mDrawerList = (ListView) findViewById(R.id.list_slidermenu);

		navDrawerItems = new ArrayList<NavDrawerItem>();

		// Getting the albums from shared preferences
		albumsList = AppController.getInstance().getPrefManger().getCategories();

		// Insert "Recently Added" in navigation drawer first position
		Category recentAlbum = new Category(null,
				getString(R.string.nav_drawer_recently_added));

		albumsList.add(0, recentAlbum);

		// Loop through albums in add them to navigation drawer adapter
		for (Category a : albumsList) {
			navDrawerItems.add(new NavDrawerItem(a.getId(), a.getTitle()));
		}

		mDrawerList.setOnItemClickListener(new SlideMenuClickListener());

		// Setting the nav drawer list adapter
		adapter = new NavDrawerListAdapter(getApplicationContext(),
				navDrawerItems);
		mDrawerList.setAdapter(adapter);

		// Enabling action bar app icon and behaving it as toggle button
		getActionBar().setDisplayHomeAsUpEnabled(true);
		getActionBar().setHomeButtonEnabled(true);
		getActionBar().setIcon(
				new ColorDrawable(getResources().getColor(
						android.R.color.transparent)));

		mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout,
				R.drawable.ic_drawer, R.string.app_name, R.string.app_name) {
			public void onDrawerClosed(View view) {
				getActionBar().setTitle(mTitle);
				// calling onPrepareOptionsMenu() to show action bar icons
				invalidateOptionsMenu();
			}

			public void onDrawerOpened(View drawerView) {
				getActionBar().setTitle(mDrawerTitle);
				// calling onPrepareOptionsMenu() to hide action bar icons
				invalidateOptionsMenu();
			}
		};
		mDrawerLayout.setDrawerListener(mDrawerToggle);

		if (savedInstanceState == null) {
			// on first time display view for first nav item
			displayView(0);
		}
	}

	/**
	 * Navigation drawer menu item click listener
	 * */
	private class SlideMenuClickListener implements
			ListView.OnItemClickListener {
		@Override
		public void onItemClick(AdapterView<?> parent, View view, int position,
				long id) {
			// display view for selected nav drawer item
			displayView(position);
		}
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}

	/**
	 * On menu item selected
	 * */
	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		// toggle nav drawer on selecting action bar app icon/title
		if (mDrawerToggle.onOptionsItemSelected(item)) {
			return true;
		}
		// Handle action bar actions click
		switch (item.getItemId()) {
		case R.id.action_settings:
			// Selected settings menu item
			// launch Settings activity
			Intent intent = new Intent(MainActivity.this,
					SettingsActivity.class);
			startActivity(intent);
			return true;
		default:
			return super.onOptionsItemSelected(item);
		}
	}

	/**
	 * Called when invalidateOptionsMenu() is triggered
	 */
	@Override
	public boolean onPrepareOptionsMenu(Menu menu) {
		// if nav drawer is opened, hide the action items
		boolean drawerOpen = mDrawerLayout.isDrawerOpen(mDrawerList);
		menu.findItem(R.id.action_settings).setVisible(!drawerOpen);
		return super.onPrepareOptionsMenu(menu);
	}

	/**
	 * Diplaying fragment view for selected nav drawer list item
	 * */
	private void displayView(int position) {
		// update the main content by replacing fragments
		Fragment fragment = null;
		switch (position) {
		case 0:
			// Recently added item selected
			// don't pass album id to grid fragment
			fragment = GridFragment.newInstance(null);
			break;

		default:
			// selected wallpaper category
			// send album id to grid fragment to list all the wallpapers
			String albumId = albumsList.get(position).getId();
			fragment = GridFragment.newInstance(albumId);
			break;
		}

		if (fragment != null) {
			FragmentManager fragmentManager = getFragmentManager();
			fragmentManager.beginTransaction()
					.replace(R.id.frame_container, fragment).commit();

			// update selected item and title, then close the drawer
			mDrawerList.setItemChecked(position, true);
			mDrawerList.setSelection(position);
			setTitle(albumsList.get(position).getTitle());
			mDrawerLayout.closeDrawer(mDrawerList);
		} else {
			// error in creating fragment
			Log.e(TAG, "Error in creating fragment");
		}
	}

	@Override
	public void setTitle(CharSequence title) {
		mTitle = title;
		getActionBar().setTitle(mTitle);
	}

	/**
	 * When using the ActionBarDrawerToggle, you must call it during
	 * onPostCreate() and onConfigurationChanged()...
	 */

	@Override
	protected void onPostCreate(Bundle savedInstanceState) {
		super.onPostCreate(savedInstanceState);
		// Sync the toggle state after onRestoreInstanceState has occurred.
		mDrawerToggle.syncState();
	}

	@Override
	public void onConfigurationChanged(Configuration newConfig) {
		super.onConfigurationChanged(newConfig);
		// Pass any configuration change to the drawer toggls
		mDrawerToggle.onConfigurationChanged(newConfig);
	}
}

22. Add the MainActivity.java activity in the AndroidManifest.xml inside <application> tag.

<application ...>
        <activity
            android:name="info.androidhive.awesomewallpapers.MainActivity"
            android:screenOrientation="portrait" >
        </activity>
</application>

Now run the app and test it once. You should see the wallpaper categories displayed in navigation drawer.

android free wallpapers app navigation drawer

Wallpapers Grid Thumbnail Preview

The next step is displaying the wallpapers of selected category in a thumbnail fashion. For this we need a GridView and few other class files.

23. Create an xml file named grid_item_photo.xml under res ⇒ layout and add the below code. This layout defines single grid item tile in the GridView. Here we are using volley’s NetworkImageView to download the image from an URL and display.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="@color/grid_item_bg" >

    <ImageView
        android:id="@+id/imgLoader"
        android:layout_width="30dp"
        android:layout_height="30dp"
        android:layout_centerInParent="true"
        android:src="@drawable/ico_loader" />

    <!-- Thumbnail Image -->

    <com.android.volley.toolbox.NetworkImageView
        android:id="@+id/thumbnail"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

</RelativeLayout>

24. Create another layout file named fragment_grid.xml under res ⇒ layout folder. This layout contains actual GridView and a ProgressBar to show to loading progress while the request is in process.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" 
    android:background="@color/black">

    <ProgressBar
        android:id="@+id/pbLoader"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true" 
        style="?android:attr/progressBarStyle">
    </ProgressBar>

    <GridView
        android:id="@+id/grid_view"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:background="@color/grid_bg"
        android:gravity="center"
        android:numColumns="auto_fit"
        android:stretchMode="columnWidth">
    </GridView>

</RelativeLayout>

25. Now just like navigation drawer adapter, we need to create another adapter class to provide data to GridView. So create a class named GridViewAdapter.java under adapter package. This class inflates grid_item_photo.xml layout with appropriate wallpaper image.

package info.androidhive.awesomewallpapers.helper;

import info.androidhive.awesomewallpapers.R;
import info.androidhive.awesomewallpapers.app.AppController;
import info.androidhive.awesomewallpapers.picasa.model.Wallpaper;

import java.util.ArrayList;
import java.util.List;

import android.app.Activity;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.RelativeLayout;

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

public class GridViewAdapter extends BaseAdapter {

	private Activity _activity;
	private LayoutInflater inflater;
	private List<Wallpaper> wallpapersList = new ArrayList<Wallpaper>();
	private int imageWidth;
	ImageLoader imageLoader = AppController.getInstance().getImageLoader();

	public GridViewAdapter(Activity activity, List<Wallpaper> wallpapersList,
			int imageWidth) {
		this._activity = activity;
		this.wallpapersList = wallpapersList;
		this.imageWidth = imageWidth;
	}

	@Override
	public int getCount() {
		return this.wallpapersList.size();
	}

	@Override
	public Object getItem(int position) {
		return this.wallpapersList.get(position);
	}

	@Override
	public long getItemId(int position) {
		return position;
	}

	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		if (inflater == null)
			inflater = (LayoutInflater) _activity
					.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
		if (convertView == null)
			convertView = inflater.inflate(R.layout.grid_item_photo, null);

		if (imageLoader == null)
			imageLoader = AppController.getInstance().getImageLoader();

		// Grid thumbnail image view
		NetworkImageView thumbNail = (NetworkImageView) convertView
				.findViewById(R.id.thumbnail);

		Wallpaper p = wallpapersList.get(position);

		thumbNail.setScaleType(ImageView.ScaleType.CENTER_CROP);
		thumbNail.setLayoutParams(new RelativeLayout.LayoutParams(imageWidth,
				imageWidth));
		thumbNail.setImageUrl(p.getUrl(), imageLoader);

		return convertView;
	}

}

26. Create a class named GridFragment.java under the project’s main package. This is where we implement actual GridView implementation. This is main fragment class will be loaded when an item from navigation drawer selected. Briefly it works as below

> User selects a wallpaper category from navigation drawer.
> The selected category id (in other words album id) will be passed to GridFragment
> Using the category id, we make another request to Picasa to get all the photos under that category.
> Finally the photos json will be parsed and wallpaper model objects will be passed to GridViewAdpater to render the wallpapers in grid view.

package info.androidhive.awesomewallpapers;

import info.androidhive.awesomewallpapers.app.AppConst;
import info.androidhive.awesomewallpapers.app.AppController;
import info.androidhive.awesomewallpapers.helper.GridViewAdapter;
import info.androidhive.awesomewallpapers.picasa.model.Wallpaper;
import info.androidhive.awesomewallpapers.util.PrefManager;
import info.androidhive.awesomewallpapers.util.Utils;

import java.util.ArrayList;
import java.util.List;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.app.Fragment;
import android.content.Intent;
import android.content.res.Resources;
import android.os.Bundle;
import android.util.Log;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.GridView;
import android.widget.ProgressBar;
import android.widget.Toast;

import com.android.volley.Request.Method;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.JsonObjectRequest;

public class GridFragment extends Fragment {
	private static final String TAG = GridFragment.class.getSimpleName();
	private Utils utils;
	private GridViewAdapter adapter;
	private GridView gridView;
	private int columnWidth;
	private static final String bundleAlbumId = "albumId";
	private String selectedAlbumId;
	private List<Wallpaper> photosList;
	private ProgressBar pbLoader;
	private PrefManager pref;

	// Picasa JSON response node keys
	private static final String TAG_FEED = "feed", TAG_ENTRY = "entry",
			TAG_MEDIA_GROUP = "media$group",
			TAG_MEDIA_CONTENT = "media$content", TAG_IMG_URL = "url",
			TAG_IMG_WIDTH = "width", TAG_IMG_HEIGHT = "height", TAG_ID = "id",
			TAG_T = "$t";

	public GridFragment() {
	}

	public static GridFragment newInstance(String albumId) {
		GridFragment f = new GridFragment();
		Bundle args = new Bundle();
		args.putString(bundleAlbumId, albumId);
		f.setArguments(args);
		return f;
	}

	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container,
			Bundle savedInstanceState) {

		photosList = new ArrayList<Wallpaper>();
		pref = new PrefManager(getActivity());

		// Getting Album Id of the item selected in navigation drawer
		// if Album Id is null, user is selected recently added option
		if (getArguments().getString(bundleAlbumId) != null) {
			selectedAlbumId = getArguments().getString(bundleAlbumId);
			Log.d(TAG,
					"Selected album id: "
							+ getArguments().getString(bundleAlbumId));
		} else {
			Log.d(TAG, "Selected recentlyed added album");
			selectedAlbumId = null;
		}

		// Preparing the request url
		String url = null;
		if (selectedAlbumId == null) {
			// Recently added album url
			url = AppConst.URL_RECENTLY_ADDED.replace("_PICASA_USER_",
					pref.getGoogleUserName());
		} else {
			// Selected an album, replace the Album Id in the url
			url = AppConst.URL_ALBUM_PHOTOS.replace("_PICASA_USER_",
					pref.getGoogleUserName()).replace("_ALBUM_ID_",
					selectedAlbumId);
		}

		Log.d(TAG, "Final request url: " + url);

		View rootView = inflater.inflate(R.layout.fragment_grid, container,
				false);

		// Hiding the gridview and showing loader image before making the http
		// request
		gridView = (GridView) rootView.findViewById(R.id.grid_view);
		gridView.setVisibility(View.GONE);
		pbLoader = (ProgressBar) rootView.findViewById(R.id.pbLoader);
		pbLoader.setVisibility(View.VISIBLE);

		utils = new Utils(getActivity());

		/**
		 * Making volley's json object request to fetch list of photos of an
		 * album
		 * */
		JsonObjectRequest jsonObjReq = new JsonObjectRequest(Method.GET, url,
				null, new Response.Listener<JSONObject>() {

					@Override
					public void onResponse(JSONObject response) {
						Log.d(TAG,
								"List of photos json reponse: "
										+ response.toString());
						try {
							// Parsing the json response
							JSONArray entry = response.getJSONObject(TAG_FEED)
									.getJSONArray(TAG_ENTRY);

							// looping through each photo and adding it to list
							// data set
							for (int i = 0; i < entry.length(); i++) {
								JSONObject photoObj = (JSONObject) entry.get(i);
								JSONArray mediacontentArry = photoObj
										.getJSONObject(TAG_MEDIA_GROUP)
										.getJSONArray(TAG_MEDIA_CONTENT);

								if (mediacontentArry.length() > 0) {
									JSONObject mediaObj = (JSONObject) mediacontentArry
											.get(0);

									String url = mediaObj
											.getString(TAG_IMG_URL);

									String photoJson = photoObj.getJSONObject(
											TAG_ID).getString(TAG_T)
											+ "&imgmax=d";									

									int width = mediaObj.getInt(TAG_IMG_WIDTH);
									int height = mediaObj
											.getInt(TAG_IMG_HEIGHT);

									Wallpaper p = new Wallpaper(photoJson, url, width,
											height);

									// Adding the photo to list data set
									photosList.add(p);

									Log.d(TAG, "Photo: " + url + ", w: "
											+ width + ", h: " + height);
								}
							}

							// Notify list adapter about dataset changes. So
							// that it renders grid again
							adapter.notifyDataSetChanged();

							// Hide the loader, make grid visible
							pbLoader.setVisibility(View.GONE);
							gridView.setVisibility(View.VISIBLE);

						} catch (JSONException e) {
							e.printStackTrace();
							Toast.makeText(getActivity(),
									getString(R.string.msg_unknown_error),
									Toast.LENGTH_LONG).show();
						}

					}
				}, new Response.ErrorListener() {

					@Override
					public void onErrorResponse(VolleyError error) {
						Log.e(TAG, "Error: " + error.getMessage());
						// unable to fetch wallpapers
						// either google username is wrong or
						// devices doesn't have internet connection
						Toast.makeText(getActivity(),
								getString(R.string.msg_wall_fetch_error),
								Toast.LENGTH_LONG).show();

					}
				});

		// Remove the url from cache
		AppController.getInstance().getRequestQueue().getCache().remove(url);

		// Disable the cache for this url, so that it always fetches updated
		// json
		jsonObjReq.setShouldCache(false);

		// Adding request to request queue
		AppController.getInstance().addToRequestQueue(jsonObjReq);

		// Initilizing Grid View
		InitilizeGridLayout();

		// Gridview adapter
		adapter = new GridViewAdapter(getActivity(), photosList, columnWidth);

		// setting grid view adapter
		gridView.setAdapter(adapter);

		// Grid item select listener
		gridView.setOnItemClickListener(new OnItemClickListener() {
			@Override
			public void onItemClick(AdapterView<?> parent, View v,
					int position, long id) {

				// On selecting the grid image, we launch fullscreen activity
				Intent i = new Intent(getActivity(),
						FullScreenViewActivity.class);

				// Passing selected image to fullscreen activity
				Wallpaper photo = photosList.get(position);

				i.putExtra(FullScreenViewActivity.TAG_SEL_IMAGE, photo);
				startActivity(i);
			}
		});

		return rootView;
	}

	/**
	 * Method to calculate the grid dimensions Calculates number columns and
	 * columns width in grid
	 * */
	private void InitilizeGridLayout() {
		Resources r = getResources();
		float padding = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
				AppConst.GRID_PADDING, r.getDisplayMetrics());

		// Column width
		columnWidth = (int) ((utils.getScreenWidth() - ((pref
				.getNoOfGridColumns() + 1) * padding)) / pref
				.getNoOfGridColumns());

		// Setting number of grid columns
		gridView.setNumColumns(pref.getNoOfGridColumns());
		gridView.setColumnWidth(columnWidth);
		gridView.setStretchMode(GridView.NO_STRETCH);
		gridView.setPadding((int) padding, (int) padding, (int) padding,
				(int) padding);

		// Setting horizontal and vertical padding
		gridView.setHorizontalSpacing((int) padding);
		gridView.setVerticalSpacing((int) padding);
	}

}

Now go back to your MainActivity.java, uncomment the GridFragment related code which you commented earlier and run the project. You should able to see the wallpapers in GridView once you selected the category from navigation drawer.

android free wallpapers app grid view

Wallpaper Fullscreen View

We also providing user another option to view selected thumbnail image in fullscreen mode. So to implement this, follow below steps.

27. Create an xml file named activity_fullscreen_image.xml under res ⇒ layout folder. This file contains HorizontalScrollView element to scroll the fullscreen image horizontally. Also it contains two more buttons to provide user option to apply the image as wallpaper and download the wallpaper to galleries.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/black" >

    <ProgressBar
        android:id="@+id/pbLoader"
        style="?android:attr/progressBarStyle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true" >
    </ProgressBar>

    <!-- Scroll view for fullscreen preview -->

    <HorizontalScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scrollbars="none" >

        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="match_parent" >

            <ImageView
                android:id="@+id/imgFullscreen"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:scaleType="fitXY" />
        </LinearLayout>
    </HorizontalScrollView>

    <!-- Set as wallpaper button -->

    <LinearLayout
        android:id="@+id/llSetWallpaper"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentLeft="true"
        android:layout_marginBottom="10dp"
        android:layout_marginLeft="10dp"
        android:background="@drawable/btn_rounded_corner"
        android:gravity="center_vertical"
        android:orientation="horizontal" >

        <ImageView
            android:layout_width="25dp"
            android:layout_height="25dp"
            android:src="@drawable/ico_apply" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:paddingLeft="10dp"
            android:text="@string/set_wallpaper"
            android:textColor="@color/white"
            android:textSize="18dp" />
    </LinearLayout>

    <!-- Download wallpaper button -->

    <LinearLayout
        android:id="@+id/llDownloadWallpaper"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentRight="true"
        android:layout_marginBottom="10dp"
        android:layout_marginRight="10dp"
        android:background="@drawable/btn_rounded_corner"
        android:gravity="center_vertical"
        android:orientation="horizontal" >

        <ImageView
            android:layout_width="25dp"
            android:layout_height="25dp"
            android:src="@drawable/ico_download" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:paddingLeft="10dp"
            android:text="@string/download_wallpaper"
            android:textColor="@color/white"
            android:textSize="18dp" />
    </LinearLayout>

</RelativeLayout>

28. Create a class named FullScreenViewActivity.java under your main package. This class takes care of calculating the image aspect ratio in fullscreen mode. The image width will calculated respective to device height. Below steps will be execute in order show the fullscreen wallpaper.

> User selects the wallpaper from GridView. The selected wallpaper will be passed to fullscreen image activity.
> In fullscreen activity, we make another call to Picasa to get the selected wallpaper’s high resolution version.
> The downloaded wallpaper width will be calculated depending upon device height.
> Then the image will be displayed in ImageView. The HorizontalScrollView make the wallpaper scrollable horizontally.

package info.androidhive.awesomewallpapers;

import info.androidhive.awesomewallpapers.app.AppController;
import info.androidhive.awesomewallpapers.picasa.model.Wallpaper;
import info.androidhive.awesomewallpapers.util.Utils;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Point;
import android.graphics.drawable.BitmapDrawable;
import android.os.Bundle;
import android.util.Log;
import android.view.Display;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.LinearLayout.LayoutParams;
import android.widget.ProgressBar;
import android.widget.Toast;

import com.android.volley.Request.Method;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.ImageLoader;
import com.android.volley.toolbox.ImageLoader.ImageContainer;
import com.android.volley.toolbox.ImageLoader.ImageListener;
import com.android.volley.toolbox.JsonObjectRequest;

public class FullScreenViewActivity extends Activity implements OnClickListener {
	private static final String TAG = FullScreenViewActivity.class
			.getSimpleName();
	public static final String TAG_SEL_IMAGE = "selectedImage";
	private Wallpaper selectedPhoto;
	private ImageView fullImageView;
	private LinearLayout llSetWallpaper, llDownloadWallpaper;
	private Utils utils;
	private ProgressBar pbLoader;

	// Picasa JSON response node keys
	private static final String TAG_ENTRY = "entry",
			TAG_MEDIA_GROUP = "media$group",
			TAG_MEDIA_CONTENT = "media$content", TAG_IMG_URL = "url",
			TAG_IMG_WIDTH = "width", TAG_IMG_HEIGHT = "height";

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_fullscreen_image);

		fullImageView = (ImageView) findViewById(R.id.imgFullscreen);
		llSetWallpaper = (LinearLayout) findViewById(R.id.llSetWallpaper);
		llDownloadWallpaper = (LinearLayout) findViewById(R.id.llDownloadWallpaper);
		pbLoader = (ProgressBar) findViewById(R.id.pbLoader);

		// hide the action bar in fullscreen mode
		getActionBar().hide();

		utils = new Utils(getApplicationContext());

		// layout click listeners
		llSetWallpaper.setOnClickListener(this);
		llDownloadWallpaper.setOnClickListener(this);

		// setting layout buttons alpha/opacity
		llSetWallpaper.getBackground().setAlpha(70);
		llDownloadWallpaper.getBackground().setAlpha(70);

		Intent i = getIntent();
		selectedPhoto = (Wallpaper) i.getSerializableExtra(TAG_SEL_IMAGE);

		// check for selected photo null
		if (selectedPhoto != null) {

			// fetch photo full resolution image by making another json request
			fetchFullResolutionImage();

		} else {
			Toast.makeText(getApplicationContext(),
					getString(R.string.msg_unknown_error), Toast.LENGTH_SHORT)
					.show();
		}
	}

	/**
	 * Fetching image fullresolution json
	 * */
	private void fetchFullResolutionImage() {
		String url = selectedPhoto.getPhotoJson();

		// show loader before making request
		pbLoader.setVisibility(View.VISIBLE);
		llSetWallpaper.setVisibility(View.GONE);
		llDownloadWallpaper.setVisibility(View.GONE);

		// volley's json obj request
		JsonObjectRequest jsonObjReq = new JsonObjectRequest(Method.GET, url,
				null, new Response.Listener<JSONObject>() {

					@Override
					public void onResponse(JSONObject response) {
						Log.d(TAG,
								"Image full resolution json: "
										+ response.toString());
						try {
							// Parsing the json response
							JSONObject entry = response
									.getJSONObject(TAG_ENTRY);

							JSONArray mediacontentArry = entry.getJSONObject(
									TAG_MEDIA_GROUP).getJSONArray(
									TAG_MEDIA_CONTENT);

							JSONObject mediaObj = (JSONObject) mediacontentArry
									.get(0);

							String fullResolutionUrl = mediaObj
									.getString(TAG_IMG_URL);

							// image full resolution widht and height
							final int width = mediaObj.getInt(TAG_IMG_WIDTH);
							final int height = mediaObj.getInt(TAG_IMG_HEIGHT);

							Log.d(TAG, "Full resolution image. url: "
									+ fullResolutionUrl + ", w: " + width
									+ ", h: " + height);

							ImageLoader imageLoader = AppController
									.getInstance().getImageLoader();

							// We download image into ImageView instead of
							// NetworkImageView to have callback methods
							// Currently NetworkImageView doesn't have callback
							// methods

							imageLoader.get(fullResolutionUrl,
									new ImageListener() {

										@Override
										public void onErrorResponse(
												VolleyError arg0) {
											Toast.makeText(
													getApplicationContext(),
													getString(R.string.msg_wall_fetch_error),
													Toast.LENGTH_LONG).show();
										}

										@Override
										public void onResponse(
												ImageContainer response,
												boolean arg1) {
											if (response.getBitmap() != null) {
												// load bitmap into imageview
												fullImageView
														.setImageBitmap(response
																.getBitmap());
												adjustImageAspect(width, height);

												// hide loader and show set &
												// download buttons
												pbLoader.setVisibility(View.GONE);
												llSetWallpaper
														.setVisibility(View.VISIBLE);
												llDownloadWallpaper
														.setVisibility(View.VISIBLE);
											}
										}
									});

						} catch (JSONException e) {
							e.printStackTrace();
							Toast.makeText(getApplicationContext(),
									getString(R.string.msg_unknown_error),
									Toast.LENGTH_LONG).show();
						}

					}
				}, new Response.ErrorListener() {

					@Override
					public void onErrorResponse(VolleyError error) {
						Log.e(TAG, "Error: " + error.getMessage());
						// unable to fetch wallpapers
						// either google username is wrong or
						// devices doesn't have internet connection
						Toast.makeText(getApplicationContext(),
								getString(R.string.msg_wall_fetch_error),
								Toast.LENGTH_LONG).show();

					}
				});

		// Remove the url from cache
		AppController.getInstance().getRequestQueue().getCache().remove(url);

		// Disable the cache for this url, so that it always fetches updated
		// json
		jsonObjReq.setShouldCache(false);

		// Adding request to request queue
		AppController.getInstance().addToRequestQueue(jsonObjReq);
	}

	/**
	 * Adjusting the image aspect ration to scroll horizontally, Image height
	 * will be screen height, width will be calculated respected to height
	 * */
	@SuppressWarnings("deprecation")
	@SuppressLint("NewApi")
	private void adjustImageAspect(int bWidth, int bHeight) {
		LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
				LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);

		if (bWidth == 0 || bHeight == 0)
			return;

		int sHeight = 0;

		if (android.os.Build.VERSION.SDK_INT >= 13) {
			Display display = getWindowManager().getDefaultDisplay();
			Point size = new Point();
			display.getSize(size);
			sHeight = size.y;
		} else {
			Display display = getWindowManager().getDefaultDisplay();
			sHeight = display.getHeight();
		}

		int new_width = (int) Math.floor((double) bWidth * (double) sHeight
				/ (double) bHeight);
		params.width = new_width;
		params.height = sHeight;

		Log.d(TAG, "Fullscreen image new dimensions: w = " + new_width
				+ ", h = " + sHeight);

		fullImageView.setLayoutParams(params);
	}

	/**
	 * View click listener
	 * */
	@Override
	public void onClick(View v) {
		Bitmap bitmap = ((BitmapDrawable) fullImageView.getDrawable())
				.getBitmap();
		switch (v.getId()) {
		// button Download Wallpaper tapped
		case R.id.llDownloadWallpaper:
			utils.saveImageToSDCard(bitmap);
			break;
		// button Set As Wallpaper tapped
		case R.id.llSetWallpaper:
			utils.setAsWallpaper(bitmap);
			break;
		default:
			break;
		}

	}
}

29. Add the FullScreenViewActivity entry in AndroidManifest.xml file between <application> tags.

<application ...>       
        <activity
            android:name="info.androidhive.awesomewallpapers.FullScreenViewActivity"
            android:screenOrientation="portrait" >
        </activity>
        </activity>
</application>

Now run the project and select any image from grid view. You should able see fullscreen image activity launched with wallpaper image preview.

android free wallpapers app grid view

Providing Set as Wallpaper Option

30. To apply the wallpaper to device, add a click listener to set as wallpaper button and call setAsWallpaper() method presented in Utils.java class

Add below line in onCreate() method of FullScreenViewActivity.java

llSetWallpaper.setOnClickListener(this);

Call below method in onClick() method of FullScreenViewActivity.java

	/**
	 * View click listener
	 * */
	@Override
	public void onClick(View v) {
		Bitmap bitmap = ((BitmapDrawable) fullImageView.getDrawable())
				.getBitmap();
		switch (v.getId()) {		
		case R.id.llSetWallpaper:
			utils.setAsWallpaper(bitmap);
			break;
		default:
			break;
		}

	}

Now if you tap the Set button, the wallpaper will be applied to device.

android free wallpapers set as wallpaper

Downloading Wallpaper to Gallery

31. Just like set as wallpaper, to download wallpaper to device gallery directory, add the click listener to download button and call saveImageToSDCard() method presented in Utils.java

Add below line in onCreate() method of FullScreenViewActivity.java

llDownloadWallpaper.setOnClickListener(this);

Add another case statement in onClick() method of FullScreenViewActivity.java

	/**
	 * View click listener
	 * */
	@Override
	public void onClick(View v) {
		Bitmap bitmap = ((BitmapDrawable) fullImageView.getDrawable())
				.getBitmap();
		switch (v.getId()) {
		// button Download Wallpaper tapped
		case R.id.llDownloadWallpaper:
			utils.saveImageToSDCard(bitmap);
			break;
		// button Set As Wallpaper tapped
		case R.id.llSetWallpaper:
			utils.setAsWallpaper(bitmap);
			break;
		default:
			break;
		}

	}

Now if you tap Download Wallpaper button, the wallpaper will be downloaded to your gallery with album named Awesome Wallpapers. If you don’t see the album there, reboot your device. I couldn’t see the album created until I rebooted my device. I am yet to find the issue 🙁

With this we almost the completed the app. But lastly we need to add a Settings screen where user can configure Picasa username, number of grid columns and gallery directory name. This step is not necessary if you are planning to release this app in playstore. It is just for the developers who is reading this.

Adding Settings Screen

32. . Create a layout file named activity_settings.xml under res layout folder. This layout contains a form with few edittext fields and a save button.

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

    <TextView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_marginBottom="8dp"
        android:layout_marginTop="15dp"
        android:text="@string/lbl_google_username"
        android:textColor="@color/settings_label"
        android:textSize="16dp" />

    <EditText
        android:id="@+id/txtGoogleUsername"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_marginBottom="20dp"
        android:background="@drawable/edittext_rounded_corner"
        android:inputType="text"
        android:singleLine="true" />

    <TextView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_marginBottom="8dp"
        android:text="@string/lbl_no_grid_columns"
        android:textColor="@color/settings_label"
        android:textSize="16dp" />

    <EditText
        android:id="@+id/txtNoOfColumns"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_marginBottom="20dp"
        android:background="@drawable/edittext_rounded_corner"
        android:inputType="number"
        android:singleLine="true" />

    <TextView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_marginBottom="8dp"
        android:text="@string/lbl_gallery_name"
        android:textColor="@color/settings_label"
        android:textSize="16dp" />

    <EditText
        android:id="@+id/txtGalleryName"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_marginBottom="25dp"
        android:background="@drawable/edittext_rounded_corner"
        android:singleLine="true" />

    <Button
        android:id="@+id/btnSave"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@drawable/btn_rounded_corner"
        android:paddingLeft="30dp"
        android:paddingRight="30dp"
        android:text="@string/lbl_btn_save"
        android:textColor="@color/white"
        android:textSize="18dp" />

</LinearLayout>

33. . Create a class named SettingsActivity.java and add the below code. This code just validates the data entered by user and overwrites the respective values in Shared Preferences.

package info.androidhive.awesomewallpapers;

import info.androidhive.awesomewallpapers.R;
import info.androidhive.awesomewallpapers.util.PrefManager;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

public class SettingsActivity extends Activity {
	private PrefManager pref;
	private TextView txtGoogleUsername, txtNoOfGridColumns, txtGalleryName;
	private Button btnSave;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_settings);

		txtGoogleUsername = (TextView) findViewById(R.id.txtGoogleUsername);
		txtNoOfGridColumns = (TextView) findViewById(R.id.txtNoOfColumns);
		txtGalleryName = (TextView) findViewById(R.id.txtGalleryName);
		btnSave = (Button) findViewById(R.id.btnSave);

		pref = new PrefManager(getApplicationContext());

		// Display edittext values stored in shared preferences
		// Google username
		txtGoogleUsername.setText(pref.getGoogleUserName());

		// Number of grid columns
		txtNoOfGridColumns.setText(String.valueOf(pref.getNoOfGridColumns()));

		// Gallery name
		txtGalleryName.setText(pref.getGalleryName());

		// Save settings button click listener
		btnSave.setOnClickListener(new View.OnClickListener() {

			@Override
			public void onClick(View v) {

				// Validating the data before saving to shared preferences
				// validate google username
				String googleUsername = txtGoogleUsername.getText().toString()
						.trim();
				if (googleUsername.length() == 0) {
					Toast.makeText(getApplicationContext(),
							getString(R.string.toast_enter_google_username),
							Toast.LENGTH_LONG).show();
					return;
				}

				// validate number of grid columns
				String no_of_columns = txtNoOfGridColumns.getText().toString()
						.trim();
				if (no_of_columns.length() == 0 || !isInteger(no_of_columns)) {
					Toast.makeText(getApplicationContext(),
							getString(R.string.toast_enter_valid_grid_columns),
							Toast.LENGTH_LONG).show();
					return;
				}

				// validate gallery name
				String galleryName = txtGalleryName.getText().toString().trim();
				if (galleryName.length() == 0) {
					Toast.makeText(getApplicationContext(),
							getString(R.string.toast_enter_gallery_name),
							Toast.LENGTH_LONG).show();
					return;
				}

				// Check for setting changes
				if (!googleUsername.equalsIgnoreCase(pref.getGoogleUserName())
						|| !no_of_columns.equalsIgnoreCase(String.valueOf(pref
								.getNoOfGridColumns()))
						|| !galleryName.equalsIgnoreCase(pref.getGalleryName())) {
					// User changed the settings
					// save the changes and launch SplashScreen to initialize
					// the app again
					pref.setGoogleUsername(googleUsername);
					pref.setNoOfGridColumns(Integer.parseInt(no_of_columns));
					pref.setGalleryName(galleryName);

					// start the app from SplashScreen
					Intent i = new Intent(SettingsActivity.this,
							SplashActivity.class);
					// Clear all the previous activities
					i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
							| Intent.FLAG_ACTIVITY_CLEAR_TASK);
					startActivity(i);
				} else {
					// user not modified any values in the form
					// skip saving to shared preferences
					// just go back to previous activity
					onBackPressed();
				}

			}
		});

	}

	public boolean isInteger(String input) {
		try {
			Integer.parseInt(input);
			return true;
		} catch (Exception e) {
			return false;
		}
	}
}

34. Finally add settings activity entry in AndroidManifest.xml

    <application ...>        
        <activity
            android:name="info.androidhive.awesomewallpapers.SettingsActivity"
            android:label="@string/action_settings"
            android:screenOrientation="portrait" >
        </activity>
    </application>

Finally your AndroidManifest.xml file should look like this.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="info.androidhive.awesomewallpapers"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="14"
        android:targetSdkVersion="19" />

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.SET_WALLPAPER" />

    <application
        android:name="info.androidhive.awesomewallpapers.app.AppController"
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/FreeWallTheme" >
        <activity
            android:name="info.androidhive.awesomewallpapers.SplashActivity"
            android:label="@string/app_name"
            android:screenOrientation="portrait" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity
            android:name="info.androidhive.awesomewallpapers.MainActivity"
            android:screenOrientation="portrait" >
        </activity>
        <activity
            android:name="info.androidhive.awesomewallpapers.FullScreenViewActivity"
            android:screenOrientation="portrait" >
        </activity>
        <activity
            android:name="info.androidhive.awesomewallpapers.SettingsActivity"
            android:label="@string/action_settings"
            android:screenOrientation="portrait" >
        </activity>
    </application>

</manifest>

Run the app and launch settings screen by tapping overflow icon on action bar.

Congratulations 🙂 If you are succeeded all the steps until now, you just create a fully fledged wallpapers app which has good potential go into market right away. But before that I would like to address few important points to you.

> This app is doesn’t supports older versions < 4.0. For that you need to use Android Support Library to provide backward compatibility.

> Even though we are using Google+ / Picasa web services to provide wallpapers, in real scenario we should have a server side technology to detect the mobile device and respond the wallpapers depending on mobile configuration like screen dimensions.

If you have any queries or suggestions please leave in comment section below.

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.
  • EhteshamMehmood

    Its Awsome <3 🙂

  • kimcy

    Thank you very much, I used to Picassa AP, I think google support quite bad, several api can’t use. I tried create small application with it
    https://play.google.com/store/apps/details?id=com.kimcy92.mywallpaper

  • Rony Rahmawan

    wrong video demo? 🙂

  • android apk

    He Ravi i want to Add Website Redirection in Dialog Box. When anyone Open the App or Game 1st Open the Website & After the Game Will Start. Only 1st Time Online. I have this Code in smali can you Please give me Complete Code with Website Redirection.

    new-instance v0, Landroid/app/AlertDialog$Builder;

    invoke-direct {v0, p0}, Landroid/app/AlertDialog$Builder;->(Landroid/content/Context;)V

    const-string v1, “”

    invoke-virtual {v0, v1}, Landroid/app/AlertDialog$Builder;->setTitle(Ljava/lang/CharSequence;)Landroid/app/AlertDialog$Builder;

    move-result-object v0

    const-string v1, “”

    invoke-virtual {v0, v1}, Landroid/app/AlertDialog$Builder;->setMessage(Ljava/lang/CharSequence;)Landroid/app/AlertDialog$Builder;

    move-result-object v0

    const-string v1, “”

    const/4 v2, 0x0

    invoke-virtual {v0, v1, v2}, Landroid/app/AlertDialog$Builder;->setPositiveButton(Ljava/lang/CharSequence;Landroid/content/DialogInterface$OnClickListener;)Landroid/app/AlertDialog$Builder;

    move-result-object v0

    invoke-virtual {v0}, Landroid/app/AlertDialog$Builder;->show()Landroid/app/AlertDialog;

  • Yadnyesh

    i am using navigation drawer in my android app..
    Each of fragment contains async task which getting data from internet and displaying in custom list..

    But when i am switching between fragments an async task started loading data again..
    So how to save state of fragment

    • If you use volley all the requests will be singleton. Using request tag you can identify the request. Before make the request check in the request queue using the tag, if request is not present send the request again.

  • Arjun

    There is no “but_rounded_corner” and “list_iterater” in drawable folders and Under which package we need to create a LruBitmapCache and SettingsActivity . Please provide the info

    • It doesn’t matter under which package you create the class. But for organizing the project, we keep them in separate packages.

      Create LruBitmapCache.java under util package. It seems I forgot to add code for but_rounded_corder. For now you can get the code from downloaded project.

      • Arjun

        Ok 🙂

  • Daniel

    How can i remove the horizontal scroll view and fit full image on the screen. even if is scaled so it fits.

    Thanks.

  • Guest

    Hi Ravi nice tutorial.. i have doubt. I saved the wall paper but I couldn’t find the saved picture in awesome wallpaper folder. what may be the issue? Thanks in advance

    • Yeah. I too even found this issue. You can see the downloaded wallpapers once you reboot your mobile. Search for “android refresh gallery album after save”.

  • Sanjay Sinalkar

    Hello Dude, I am getting this Server error

    Error 503 Service Unavailable

    Service Unavailable

    Guru Meditation:

    XID: 1159377834

    Varnish cache server

    May be you have installed more than one caching tool ,,…anyway
    You wrote awesome tutorials! There is one suggestion ,can you please create category-wise and chapter-wise post like Android Beginner to Intermediate in one page and link there it will be easy to learn as reader in flow and reader will continues to next tutorials
    Thanks

  • Brce

    Hi Ravi nice tutorial. If I want to remove particular title in menu items. Is it possible to do in android without deleting album title in picasa?

  • Milind Audichya

    Hello Ravi, Thanx for this great tutorial..
    I have developed an application with the help of the same and deployed it on Google Play Store..
    But its the second time when they removed my application by giving the following reason :

    “REASON FOR REMOVAL: Violation of the intellectual property and impersonation or deceptive behavior provisions of the Content Policy. Please refer to the IP infringement and impersonation policy help article for more information.”

    What can i do for the same ?

    • This is because due to copyright issues. If you are directly using the wallpapers used in this tutorial, it will be copyright issue as they won’t comes under fee license.

      • Milind Audichya

        Thanks for your kind reply.. Kindly suggest what can i do further for the same please if you can

  • Priya kuchan

    Hi ravi please drop sample code for supporting multiple screens in andoird

  • Dear Ravi Sir,

    On Click Recently Added, Volley getting Error: Could not Delete cache entry for key=https://picasaweb.google.com/data/feed/api/user/nilay.scet?albumid/5637447830974140801?alt=json, filename=-1830143455-280059811

    and also give same error in Profile Photos

  • Brce

    Hi Ravi. why it takes more time to display the image though using image loader?

    • I guess because of image size. All the images are of 1 MB approx.

  • Hoangdata

    Thank you for great tutorial. I think this error when “if you tap Download Wallpaper button, the wallpaper will be downloaded to your gallery with album named Awesome Wallpapers. If you don’t see the album there, reboot your device. I couldn’t see the album created until I rebooted my device.”

    I think maybe store image file on media store through this method:

    public static void addImageToGallery(final String filePath, final Context context) {
    ContentValues values = new ContentValues();
    values.put(Images.Media.DATE_TAKEN, System.currentTimeMillis());
    values.put(Images.Media.MIME_TYPE, “image/jpeg”);
    values.put(MediaStore.MediaColumns.DATA, filePath);
    context.getContentResolver().insert(Images.Media.EXTERNAL_CONTENT_URI, values);
    }

    I try this method and solve this issue.

  • allison

    Please help me
    start load 10 picture and i click load then load 10 pic next

  • Constantine

    Hello Ravi, thank you for this awesome tutorial. But unfortunatelly I have a NullPointerException in MainActivity. Debugger indicates that albumsList = AppController.getInstance().getPrefManger().getCategories(); equals null. Please tell me, how do you think, where there may be an error?

    • Hoangdata

      You must place “android:name=.app.AppController” in in AndroidManifest.xml to load app controller before run application

      • Constantine

        Oh, it works! Thank you!

  • Hoangdata

    I want to use Pageradapter to show image through slider. When I click a thumbnail in gridview, so show full image but how to load all image from url just like grid view…

  • Pawan Ratre Gurjar

    Hello Ravi Sir

    I have to show loading image before image comes from Any Url…

    I am using Volley Networkimage…

    If any good method available then plz suggest me…

    Also if image size is not fix i mean image can be a Rectangle or an square SHAPE then how can we make a rounded corner image of a Volley Networkimage

  • meenu

    Hello Ravi Sir,
    How to add different image icon to navigation drawer..??

  • AK

    Hi Ravi nice tutorial.. i have doubt. I saved the wall paper but I couldn’t find the saved picture in Gallery but it’s exist storage/pictures/awesome wallpapers. what may be the issue? Please solve the problem and update the code. Thanks in advance

    • Juned

      same problem with mine

    • Juned

      Did you find out any solution ?

      • Even I got the same problem. The album appeared once the device got restarted.

        • is there any way we can refresh a gallery without rebooting a device?

  • AK

    (1) How to show Navigation Drawer on Starting of Apps and (2)? How to show Navigation Drawer List if we press back button and on press of again back button then Exit.

  • AK

    I Called to the openDrawer method in the main activity:

    @Override

    public boolean onKeyDown(int keyCode, KeyEvent event) {

    switch(keyCode)

    {
    case KeyEvent.KEYCODE_BACK:
    mDrawerLayout.openDrawer(Gravity.LEFT);
    }

    return super.onKeyDown(keyCode, event);
    }
    The fact is that there was a little sliding movement (very quick), and then back to hide. After that i figured out that there was sliding while i held the back button pressed, but if i released it, the side menu went back again to original hided position.

    What am i doing wrong please Help me?? Thanx in advance.

  • AK

    I Called to the openDrawer method in the main activity:

    @Override

    public void onBackPressed() {

    if (!mDrawerLayout.isDrawerOpen(mDrawerList)) {

    mDrawerLayout.openDrawer(mDrawerList);

    }

    // super.onBackPressed();
    }

    From this Method Drawer open Correctly on Back Press but Again on Press of Back Button Activity Not close, and if we use super.onBackPressed(); it close immediately after showing drawer. Please Sir Give Solution …How to show Navigation Drawer List if we press back button and on press of again back button then Exit??. I’m Newbie.

  • fdson

    wallpaper not scrolling in kitkat v4.4.4..please help

  • fdson

    This app is working perfectly on v4.4.2 but after i updated my device to v4.4.4 when i set the wallpaper ,the wallpaper is not scrolling any more ..it is fixed to one screen…please help

  • fdson

    Ravi Sir i need your help really fast ..thanx

  • spitfire10

    Hi Ravi, would like to check with you, if I would like to only display just 1 or 2 albums from the PicasaWeb which code should I make the changes?

    Am just started out to learn the Android prog.

    Appreciated if you could shed me some light on tat..

    Thanks
    Fire

  • fdson

    Ravi Sir can you please help me..can i expect any help from your side????????

  • Nishant Jaisinghani

    Thanx Ravi for this nice tutorial….. because of you i m able to create this app within one day….apart from one error…..whenever i click the image for full screen its giving me this error ” unfortunately awesome wallpapers has stopped ” i checked all files but not able to find the solution or this. kindly help me.

    thank you

    • Check your Eclipse LogCat for crash report.

      • Nishant Jaisinghani

        09-21 15:45:45.950: E/AndroidRuntime(6967): FATAL EXCEPTION: main

        09-21 15:45:45.950: E/AndroidRuntime(6967): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.awesomequotes/com.example.awesomequotes.FullScreenViewActivity}: java.lang.NullPointerException

        09-21 15:45:45.950: E/AndroidRuntime(6967): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2355)

        09-21 15:45:45.950: E/AndroidRuntime(6967): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2391)

        09-21 15:45:45.950: E/AndroidRuntime(6967): at android.app.ActivityThread.access$600(ActivityThread.java:151)

        09-21 15:45:45.950: E/AndroidRuntime(6967): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1335)

        09-21 15:45:45.950: E/AndroidRuntime(6967): at android.os.Handler.dispatchMessage(Handler.java:99)

        09-21 15:45:45.950: E/AndroidRuntime(6967): at android.os.Looper.loop(Looper.java:155)

        09-21 15:45:45.950: E/AndroidRuntime(6967): at android.app.ActivityThread.main(ActivityThread.java:5520)

        09-21 15:45:45.950: E/AndroidRuntime(6967): at java.lang.reflect.Method.invokeNative(Native Method)

        09-21 15:45:45.950: E/AndroidRuntime(6967): at java.lang.reflect.Method.invoke(Method.java:511)

        09-21 15:45:45.950: E/AndroidRuntime(6967): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1029)

        09-21 15:45:45.950: E/AndroidRuntime(6967): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:796)

        09-21 15:45:45.950: E/AndroidRuntime(6967): at dalvik.system.NativeStart.main(Native Method)

        09-21 15:45:45.950: E/AndroidRuntime(6967): Caused by: java.lang.NullPointerException

        09-21 15:45:45.950: E/AndroidRuntime(6967): at com.example.awesomequotes.FullScreenViewActivity.onCreate(FullScreenViewActivity.java:54)

        09-21 15:45:45.950: E/AndroidRuntime(6967): at android.app.Activity.performCreate(Activity.java:5066)

        09-21 15:45:45.950: E/AndroidRuntime(6967): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1101)

        09-21 15:45:45.950: E/AndroidRuntime(6967): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2311)

        09-21 15:45:45.950: E/AndroidRuntime(6967): … 11 more

        my app name is awesomequotes

        • Does your layout file contains the elements whatever I have for FullScreenViewActivity ?

          • Nishant Jaisinghani

            i have double checked FullScreenViewActivity …..not able to find any error!
            any other solution?

    • I was facing a same issue.. I tried with a new eclipse and its solved 🙂

      • Nishant Jaisinghani

        you created the same project in eclipse different version? i will try that….. any other modifications?

        • I have tried with a latest version.. with no changes on a source code

          btw I am facing another problem in a downloading a images..

          once we click on a download .. we can not see a image in a gallery unless we reboot a device.. is there any solution ??

          • Nishant Jaisinghani

            I think maybe store image file on media store through this method: try this

            public static void addImageToGallery(final String filePath, final Context context) {
            ContentValues values = new ContentValues();
            values.put(Images.Media.DATE_TAKEN, System.currentTimeMillis());
            values.put(Images.Media.MIME_TYPE, “image/jpeg”);
            values.put(MediaStore.MediaColumns.DATA, filePath);
            context.getContentResolver().insert(Images.Media.EXTERNAL_CONTENT_URI, values);
            }

            could you pls send me the link to download new eclipse version….i m not able to find it?
            thank u

  • Moktar Hossain

    Thanx Ravi Bhai to give awesome wallpapers app. I create this app one day with your instruction and run rightly without error also try this app my own picasa web album. It’s really excellent app.

    • Hi Moktar, I am glad that you find if very useful 🙂

      • Sahitya Kumar Suman

        @moktar Hossain

        I ran the app and was able to load the pictures in the “Recently Added” tab without any problems. But however when I click other categories I get the toast message “Sorry! Unable to fetch wallpaper(s). Verify app settings or device doesn’t have internet connection” which is being generated from the onErrorResponse() in the GridFragment class,how can I go about this problem my internet connection works just fine.

        I got one answer about this that i should change the username in AppCont …
        which username should i put into it ….. or there is different username for picasa albums available if not then tell me where i can get the username ……

        Thnx in advance

  • Muklas

    is that posible to use google product into our app… if this publish in google play ?
    because they do not allowed to use of any google product in android app ?

  • Nishant Jaisinghani

    Hello everyone, I have created this app. Apart from “Set the wallpaper” & “Download the Image” feature i want to add “share the image to Facebook” feature in the app. Can anyone help me with that?

    Thank you

  • kimcy

    Thank you Ravi very much. I improve your application and add function crop image when set wallpaper , change save image into internal memory(quite bad), because when save into Sdcard gallery not scan image :(. and create selector when press button :).

    • Nishant Jaisinghani

      hello kimcy…..I have downloaded your app “Android HD Wallpapers” from play store.and i like the functions you have added. You also added share the wallpaper to facebook function. I also want to add that function in my app.can you pls help me?

      thank you

      • nature

        Hi Nishant Jaisinghani you can use like this to share image on facebook or whatsapp or anywhere..
        public void shareImage(){
        BitmapDrawable bitmapDrawable = (BitmapDrawable)fullImageView.getDrawable();
        Bitmap bitmap = bitmapDrawable.getBitmap();
        // Save this bitmap to a file.
        File cache = this.getExternalCacheDir();
        Random generator = new Random();
        int n = 10000;
        n = generator.nextInt(n);
        File sharefile = new File(cache, “Wallpaper-” + n + “.jpg”); //give your name and save it.
        try {
        FileOutputStream out = new FileOutputStream(sharefile);

        bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);

        out.flush();

        out.close();

        } catch (IOException e) {

        }

        // Now send it out to share

        Intent share = new Intent(android.content.Intent.ACTION_SEND);

        share.setType(“image/*”);

        share.putExtra(Intent.EXTRA_STREAM, Uri.parse(“file://” + sharefile));

        try {

        this.startActivity(Intent.createChooser(share, “Share photo”));

        } catch (Exception e) {

        }

        }
        return true;
        }

        }

        • Nishant Jaisinghani

          Thanks for your help….i am little bit confused….where should i put up the code you provided on FullScreenViewActivity.java or MainActivity.java…… and i want the share to facebook icon just between the set as wallpaper and download the wallpaper icons during full screen image….could u please provide the full code.Thank You

          • nature

            It’s your requirement how to use ie you want to use in button or in menu..for eg: i am showing it in menu:

            FullScreenViewActivity:

            @Override

            public boolean onCreateOptionsMenu(Menu menu) {

            // Inflate the menu; this adds items to the action bar if it is present.

            getMenuInflater().inflate(R.menu.main_menu, menu);

            return true;

            }

            @Override

            public boolean onOptionsItemSelected(MenuItem item) {

            // Handle presses on the action bar items

            switch (item.getItemId()) {

            case R.id.share:

            BitmapDrawable bitmapDrawable = (BitmapDrawable)fullImageView.getDrawable(); // here fullImageView is object of ImageView

            Bitmap bitmap = bitmapDrawable.getBitmap();

            // Save this bitmap to a file.

            File cache = this.getExternalCacheDir();

            Random generator = new Random();

            int n = 10000;

            n = generator.nextInt(n);

            File sharefile = new File(cache, “Wallpaper-” + n + “.jpg”); //give your name and save it.

            try {

            FileOutputStream out = new FileOutputStream(sharefile);

            bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);

            out.flush();

            out.close();

            } catch (IOException e) {

            }

            // Now send it out to share

            Intent share = new Intent(android.content.Intent.ACTION_SEND);

            share.setType(“image/*”);

            share.putExtra(Intent.EXTRA_STREAM, Uri.parse(“file://” + sharefile));

            try {

            this.startActivity(Intent.createChooser(share, “Share photo”));

            } catch (Exception e) {

            }

            }

            return true;

            }

            }

            main_menu.xml:

            if you want to use that in button, simple just use that code in button click 🙂 still if you have doubt, you can refer this. http://ramkumarhelios.blogspot.in/2014/09/displaying-images-form-list-of-urls-in.html

          • Capkin

            Hi, this is very helpful thanks a lot, can you give me the complet code? and I have same more questions can you help me?

    • i want the playstore link of your app

  • ERKAN BEŞALTI

    Hi Ravi!
    Your tutorials helping us amateurs so much! I need help with something. As you know you can enter titles under each photo in your Picasa album. Can we get and show those titles under the walpapers when in full screen view?

  • Dharun

    Hi Ravi,
    I don’t have error in these code, but unfortunately app has stopped, I check manifest file,,but it’s not.help
    thanks
    Dharun

  • Aldo Cano

    Hi ravi , i want to know how to grab wallpapers from server location and not to use galleries from picasa.

  • nature

    Hi Ravi, how to display like separation of load of images like first 10 and then while scrolling next 10 like that? instead of displaying all at a time? since it takes more time to load.

  • Guest

    where is the btn_rounded_corner

    • Nishant Jaisinghani

      Download The code from this page and you will find it in the folder.

      • ShivamDev

        @Nishant are you talking about res code or project code as I cant find the project code and res folder does not have it

  • Guest

    Hi ravi.
    It works fine but i want to change the URL to my picasa account to see my photos and albums,so where actually i have to change the URL…?
    As you mentioned i have changed the user name but not woking. Do help me please

    • ShivamDev

      change the username in AppConst class

  • Capkin

    10-26 00:28:21.360: D/AndroidRuntime(3295): Shutting down VM

    10-26 00:28:21.360: W/dalvikvm(3295): threadid=1: thread exiting with uncaught exception (group=0x41e322a0)

    10-26 00:28:21.360: E/AndroidRuntime(3295): FATAL EXCEPTION: main

    10-26 00:28:21.360: E/AndroidRuntime(3295): java.lang.RuntimeException: Unable to instantiate application info.androidhive.awesomewallpapers.app.AppController: java.lang.ClassNotFoundException: info.androidhive.awesomewallpapers.app.AppController

    10-26 00:28:21.360: E/AndroidRuntime(3295): at android.app.LoadedApk.makeApplication(LoadedApk.java:501)

    10-26 00:28:21.360: E/AndroidRuntime(3295): at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4170)

    10-26 00:28:21.360: E/AndroidRuntime(3295): at android.app.ActivityThread.access$1400(ActivityThread.java:134)

    10-26 00:28:21.360: E/AndroidRuntime(3295): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1278)

    10-26 00:28:21.360: E/AndroidRuntime(3295): at android.os.Handler.dispatchMessage(Handler.java:99)

    10-26 00:28:21.360: E/AndroidRuntime(3295): at android.os.Looper.loop(Looper.java:137)

    10-26 00:28:21.360: E/AndroidRuntime(3295): at android.app.ActivityThread.main(ActivityThread.java:4867)

    10-26 00:28:21.360: E/AndroidRuntime(3295): at java.lang.reflect.Method.invokeNative(Native Method)

    10-26 00:28:21.360: E/AndroidRuntime(3295): at java.lang.reflect.Method.invoke(Method.java:511)

    10-26 00:28:21.360: E/AndroidRuntime(3295): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1007)

    10-26 00:28:21.360: E/AndroidRuntime(3295): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:774)

    10-26 00:28:21.360: E/AndroidRuntime(3295): at dalvik.system.NativeStart.main(Native Method)

    10-26 00:28:21.360: E/AndroidRuntime(3295): Caused by: java.lang.ClassNotFoundException: info.androidhive.awesomewallpapers.app.AppController

    10-26 00:28:21.360: E/AndroidRuntime(3295): at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:61)

    10-26 00:28:21.360: E/AndroidRuntime(3295): at java.lang.ClassLoader.loadClass(ClassLoader.java:501)

    10-26 00:28:21.360: E/AndroidRuntime(3295): at java.lang.ClassLoader.loadClass(ClassLoader.java:461)

    10-26 00:28:21.360: E/AndroidRuntime(3295): at android.app.Instrumentation.newApplication(Instrumentation.java:982)

    10-26 00:28:21.360: E/AndroidRuntime(3295): at android.app.LoadedApk.makeApplication(LoadedApk.java:496)

    10-26 00:28:21.360: E/AndroidRuntime(3295): … 11 more

    what did I wrong?

  • Nomas

    Hi Ravi! Great tutorial! It works perfect. I am trying to change the code a little bit and instead of using gridview I am trying to use listview in fragments but I get NullPointerException and especially when I am calling adapter.notifyDataSetChanged();

    🙁

    Any ideas why this is happening?

    11-01 14:31:33.666: D/AndroidRuntime(17391): Shutting down VM
    11-01 14:31:33.666: W/dalvikvm(17391): threadid=1: thread exiting with uncaught exception (group=0x41855da0)
    11-01 14:31:33.666: E/AndroidRuntime(17391): FATAL EXCEPTION: main
    11-01 14:31:33.666: E/AndroidRuntime(17391): Process: info.androidhive.awesomewallpapers, PID: 17391
    11-01 14:31:33.666: E/AndroidRuntime(17391): java.lang.NullPointerException
    11-01 14:31:33.666: E/AndroidRuntime(17391): at info.androidhive.awesomewallpapers.MyListFragment$1.onResponse(MyListFragment.java:100)
    11-01 14:31:33.666: E/AndroidRuntime(17391): at info.androidhive.awesomewallpapers.MyListFragment$1.onResponse(MyListFragment.java:1)
    11-01 14:31:33.666: E/AndroidRuntime(17391): at com.android.volley.toolbox.JsonRequest.deliverResponse(JsonRequest.java:65)
    11-01 14:31:33.666: E/AndroidRuntime(17391): at com.android.volley.ExecutorDelivery$ResponseDeliveryRunnable.run(ExecutorDelivery.java:99)
    11-01 14:31:33.666: E/AndroidRuntime(17391): at android.os.Handler.handleCallback(Handler.java:733)
    11-01 14:31:33.666: E/AndroidRuntime(17391): at android.os.Handler.dispatchMessage(Handler.java:95)
    11-01 14:31:33.666: E/AndroidRuntime(17391): at android.os.Looper.loop(Looper.java:136)
    11-01 14:31:33.666: E/AndroidRuntime(17391): at android.app.ActivityThread.main(ActivityThread.java:5586)
    11-01 14:31:33.666: E/AndroidRuntime(17391): at java.lang.reflect.Method.invokeNative(Native Method)
    11-01 14:31:33.666: E/AndroidRuntime(17391): at java.lang.reflect.Method.invoke(Method.java:515)
    11-01 14:31:33.666: E/AndroidRuntime(17391): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1268)
    11-01 14:31:33.666: E/AndroidRuntime(17391): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1084)
    11-01 14:31:33.666: E/AndroidRuntime(17391): at dalvik.system.NativeStart.main(Native Method)
    11-01 14:31:35.016: I/Process(17391): Sending signal. PID: 17391 SIG: 9

  • Husam Malaka

    great tutorial. but how can i swipe left right to the next previous images in my picasa album

  • alya

    i want to crop image before setting wallpaper ..please help

    • r

      hi
      use edmodo crop library

      • alya

        can you give me the code to crop images and set wallpaper

  • Khan

    Source code is not Downloading
    Plz Do something

  • alex

    HI Ravi I had an issue where i couldn’t see the images after i I downloaded unless i restarted my phone or tablet but after looking around I found this:

    // Tell the media scanner about the new file so that it is
    // immediately available to the user.
    MediaScannerConnection.scanFile(_context,
    new String[]{file.toString()}, null,
    new MediaScannerConnection.OnScanCompletedListener() {
    public void onScanCompleted(String path, Uri uri) {
    Log.i(“ExternalStorage”, “Scanned ” + path + “:”);
    Log.i(“ExternalStorage”, “-> uri=” + uri);
    }
    });
    I added to the “saveImageToSDCard(Bitmap bitmap)” method right after the output stream is closed and that resolved the problem.

    • r

      tnx alex i use your code

      • alex

        I have another issue, the app shows nothing in the recently added category when loaded, all the other other categories work but I just have a spinner in the GridFragment when recently added is selected. This is the url for my recently added category: “https://picasaweb.google.com/data/feed/api/user/117701736405365918663?kind=photo&alt=json”

        I get a json output when I paste it in my browser but no pictures are loaded in the app for recently added. I have no idea why. could you help

        • They will load, but it will take sometime due to cache validation.

          • alex

            Is there anyway i could speed the process? like for example only load like the first 20 pictures or any other solution?

          • alex

            Never mind Ravi, I forgot to un-comment some lines of code.

          • Ok.

  • alex

    I also had an issue where the AppController.getInstance() was returning a null value; I am not sure how Extending the Application class works, so I made AppController a Regular class, Add a global context variable and overrode the get instance method.

    public class AppController {

    …..
    private static Context mContext;

    private AppController(Context context){

    mContext = context;

    pref = new PrefManager(context);

    }

    public static synchronized AppController getInstance() {

    return mInstance;

    }

    public static synchronized AppController getInstance(Context context) {

    if (mInstance == null) {

    mInstance = new AppController(context);

    }

    return mInstance;

    }

    …..

    }

    I then Inititialize AppController in SplashActivity right after setContentView.

  • deni777

    How to remove settings screen?

    • Ravi Tamada

      You can hide anything, if you don’t wanna show to users.

      Example: if you wanna hide your Google User Name, you can modify the SettingsActivity file by changing it in this way-

      txtGoogleUsername = (TextView) findViewById(R.id.txtGoogleUsername);

      txtGoogleUsername.setVisibility(View.GONE);

      Hope this helps you 🙂

      • deni777

        Thank you for your answer Ravi.Can you help me with only one thing.On preview wallpapers are with low quality.I upload wallpapers with size 2560×1600 with size 4mb.When i download this wallpaper on my device he is with same size but is compressed to 2mb.I want wallpaper to be in full resolution.Is this possible.Sorry for my English 😀

  • MackAttack

    This is line is giving me a nullpointerexception

    // Picasa request to get list of albums

    String url = AppConst.URL_PICASA_ALBUMS.replace(“_PICASA_USER_”, AppController.getInstance()
    .getPrefManger().getGoogleUserName());

    anyone any ideas??

    • MackAttack

      solved this the other day but cant remember how i solved it.

  • Hey

    Thank you for an awesome tutorial straight forward an easy.

    I am struggling a little with image sizes and was wondering if you could explain how the Image full resolution url is created?

    • Never mind found it 🙂

      If anyone else as problems with image too large edit the following in Gridfragments:
      From:

      ###
      String photoJson = photoObj.getJSONObject(

      TAG_ID).getString(TAG_T)

      + “&imgmax=d”;

      To:

      ###

      String photoJson = photoObj.getJSONObject(

      TAG_ID).getString(TAG_T)

      + “&imgmax=1600”;

      • MackAttack

        IS this for re-sizing on device?

        • No this ony fetches a smaller version of the image from picasa.

          • MackAttack

            Ok thanks! i wonder if its possible to add a function which resizes the full screen pictures relative to the device the app is being run on so that the picture isnt too big for the screen..

          • I think it is I am working on something with pinch zoom I let you know if i get it to work.

          • Phenil Buch

            Hey Michael! Did you get pinch zoom to work? I want it in my app so would be very helpful! 🙂

          • Sorry got stuck in other dev projects, so didn’t look further into it

  • priyank

    Productive tutorial..
    I am struggling with designing Splash screen and wallpaper resource, pls help me with that.

  • Blasta

    This line is giving me a nullpointerexception

    String url = AppConst.URL_PICASA_ALBUMS

  • Mayur Rathod

    I tried this app..Recently added photos are coming properly. if i click on some other group from naviagtion drawer its not fetching the images
    Plzzz help

    • Sahitya Kumar Suman

      Do you find any solution for this ……….. if yes then please share with us

    • Manny264

      change username to number associated with ur profile this can be found in the URL

      • Sahitya Kumar Suman

        can you tell how you get your ulr numbered username ….as i tried this to but not getting result same error

  • MD Danish Ansari

    How we can just crop and set wallpaper…???

  • Mardoqueu Sousa

    I didn’t understand, I tried several times get my own wallpapers from picasa chaging PICASA_USER by the mine, could explain me what should I to do??? I just wanted get my own pictures from picasa…

    • deli

      Try change PICASA_USER from AppConst.java

      • Mardoqueu Sousa

        Thank you ever so much, I don’t know, but when I tried again it worked perfectly! =D

  • Manny264

    I ran the app and was able to load the pictures in the “Recently Added” tab without any problems. But however when I click other categories I get the toast message “Sorry! Unable to fetch wallpaper(s). Verify app settings or device doesn’t have internet connection” which is being generated from the onErrorResponse() in the GridFragment class,how can I go about this problem my internet connection works just fine.

    • Sahitya Kumar Suman

      Do you find any solution for that ………..

      • Manny264

        Yes it seems my username was incorrect somehow what I did was to copy the user number associated with your profile u will see it in the URL cant be hard to figure that out. use that instead of the username

        • Sahitya Kumar Suman

          The digit no. or character user name which one should i use ……. for exmaple username is sahityakumarsuman or number are 123345311223123211 which is m username id or sahityakumarsuman@gmail.com please tell me or you can just send me your details to my mail ………. i will be very much thankfull if you do so

      • Manny264

        so for example this url returns my album names etc in json ryt:https://picasaweb.google.com/data/feed/api/user/107165993798824467749?kind=photo&alt=json . I used the 107165993798824467749 as my username,check it out in my app too which i published: https://play.google.com/store/apps/details?id=com.inc.automata.malawiscenery

        • Sahitya Kumar Suman

          Thank you dear ….. the username is working fine now …….. but again there is one problem left ./… that in all album category app pics are almost same pics … so if you can tell me why is this and also tell me in albumid what you have passed and from where you get your albumid to put into the AppConst class ……… Please look it up

  • Deep

    Hi Ravi, what is the easiest way to implement viewPager for this project? I want to implement swipe to next picture or previous picture

  • Guest

    Hi, i have a issue: D/skia﹕ — SkImageDecoder::Factory returned null
    and photos not display.
    anyone any ideas??

  • deli

    have anybody can add analytics v4 in this app ? how can i add analytics v4 codes in this app

  • how to make a set of wallpapers based HorizontalScrollView image? the middle image is not used as wallpaper

  • youssef abaza

    How do I add a functional Search bar in the navigation drawer that filters the album names?

  • Guest

    I got this error message in logcat:

    End of input at character 0 of

    The app just stopped at Splash Screen since it could not grab the json data. Anyone got the same issue?

    More details about the code is here: http://stackoverflow.com/questions/29350560/error-with-picasa-api-json-request-org-json-jsonexception-end-of-input-at-cha

  • Sahitya Kumar Suman

    @ravi8x:disqus please reply to my question ……… app is working quite good .. but whenever i try to open other category then recently added then it not able to fetch wallpapers so please tell me what to do ……. it says correct your googleuser settings or you have no internet connection but i am fine with my connections ………. what should i do tell me ASAP

  • poptart

    im having three errors one is in the actibity_fullscreen_images

    android:background=”@drawable/btn_rounded_corner”

    then in the fullscreenactivity.java

    @Override

    public void onClick(View v) {

    Bitmap bitmap = ((BitmapDrawable) fullImageView.getDrawable())

    .getBitmap();

    switch (v.getId()) {

    // button Download Wallpaper tapped

    case R.id.llDownloadWallpaper:

    utils.saveImageToSDCard(bitmap);

    break;

    // button Set As Wallpaper tapped

    case R.id.llSetWallpaper:

    utils.setAsWallpaper(bitmap);

    break;

    default:

    break;

    }

    the error is in the r.id.llsetwallpaper
    and the r.id.lldownloadwalpaper

  • poptart

    btn_rounded_corner

    has a error Error: No resource found that matches the given name

  • poptart

    how would i add a swipe refresh layout

  • Panda

    How can I change the pictures?
    I’ve tried in google+ to create Album but the link is not the same
    even my link is not working
    is there another way to create Album?

  • swarathesh addanki

    how to change the wallpapers frequently like muzei

  • Snehasis Shil

    I am having a problem

    String url = AppConst.URL_PICASA_ALBUMS

    .replace(“_PICASA_USER_”, AppController.getInstance()

    .getPrefManger().getGoogleUserName());

  • Masoud MH

    Hi
    Thanks for your great tutorial dear Tamada.
    I have a problem.
    my phone model is Samsung galaxy s4 mini.
    I run your app in my phone and when i click on a photo to see that in full screen view,
    screen has horizentally scroll bar and i don not want that.
    I want photo fit to my screen!!!
    how i edit your code to see photo fit to my screen?
    please help me!!!
    Thank you

  • Ambreen Khan

    Hi ravi

    I want to sort Album list in Drawer menu, Is there a way to do this??

    and secondly I want to exclude some Album from Drawer menu, Is there a way to Exclude them??
    Any help will be highly appreciated .
    Ambreen

  • Michael

    How to implement a PageAdapter for fling ?

  • rezaghasemirad

    hi Ravi Tamada i run my app well but its work in some devices and when i run in some devices not show my images why? pls help me fast .tanks for your
    great tutorial.

  • mukesh datyal

    i have xml file what is the code for that to make a wallpaper app

  • Hey Ravi Bro.
    I want to putup personal album in picasa. Can any person tell mey way for that. actually I’m not developer.

    plz plz any help .

  • Vikrant Bhardwaj

    Got an error what to do with it????

    Error:Execution failed for task ‘:app:transformClassesWithJarMergingForDebug’.

    > com.android.build.api.transform.TransformException: java.util.zip.ZipException: duplicate entry: com/android/volley/AuthFailureError.class

  • Suyash Mishra

    Ravi sir, It is not downloading the image in marshmallow and in other versions also . what should I do so that a pop up comes in marshmallow everytime when someones wants to download it

  • rushita

    hello sir,
    in my app i have created gridview of showing movie posters fetch from thmoviedb.org,
    in settings i have added sort by most popular and sort by highly rated,
    the problem is when i click on highly rated option from settings
    it doesnot change the gridview images.

    can you please tell me what part of this example i can use in my app to change gridview images when user select any option.

    thank you

  • Nihal Singh

    Every time when i download a new image, gallery is not updating until i reboot the device or gallery updates after some time and downloaded image is then showed inside the album. How to refresh the gallery each time when a new image is downloaded.. Plz help

    • Call the below after the image is saved. You need to pass the saved image sdcard path.

      MediaScannerConnection.scanFile(mContext, new String[]{file.getPath()}, null,
      new MediaScannerConnection.OnScanCompletedListener() {
      @Override
      public void onScanCompleted(String path, Uri uri) {
      }
      });

  • nuton

    How can this be integrated with google photos with this app. The url is the main problem not loading as picasa and seem not to work and kind of confusing. Any help I really will appreciate.

    • singh

      also looking for this solution google photos is a headache.

  • Nikhil Singh

    Great tutorial Ravi Tamada bro. Here is something i developed using your tutorial.
    Facebook page: https://www.facebook.com/wallsgroundhd/
    Play Store link: https://play.google.com/store/apps/details?id=com.wallsgroundhd.wallsgroundhd

    I have included many features and redesigned it with material design.
    All credit goes to this tutorial and to you. Thanx a lot..:)

    • App looks cool 🙂

      • Nikhil Singh

        thanx bro 🙂

        • Umair Yasir

          Nikhil Singh can i have your app source code please ?

    • cindydeveloper

      hi Nikhil Singh, how to make private profile photos album?
      pls help me.

    • Reekul Patel

      Hi bro nice app. But in this tutorial Picasa Web album is used and now is depreciated. So which album do you have used?

    • Chihab Chihab

      answer me
      I send you an email
      thank you

    • Fawad khan

      bro picasa albums are dead and google albums are not getting public so where you stored your wallpapers and which api did you used ? please respond

  • Jadu Kh

    Sir, i m geeting JSON NO value for feed error pilz help.. i have been reading ur blog for 3 months and this my first application help sir…

    org.json.JSONException: No value for feed
    10-17 07:24:49.558 22735-22735/com.shyamdev.animewallpaperhd W/System.err: at org.json.JSONObject.get(JSONObject.java:389)
    10-17 07:24:49.558 22735-22735/com.shyamdev.animewallpaperhd W/System.err: at org.json.JSONObject.getJSONObject(JSONObject.java:609)
    10-17 07:24:49.558 22735-22735/com.shyamdev.animewallpaperhd W/System.err: at com.shyamdev.animewallpaperhd.app.SplashActivity$1.onResponse(SplashActivity.java:58)
    10-17 07:24:49.559 22735-22735/com.shyamdev.animewallpaperhd W/System.err: at com.shyamdev.animewallpaperhd.app.SplashActivity$1.onResponse(SplashActivity.java:50)
    10-17 07:24:49.559 22735-22735/com.shyamdev.animewallpaperhd W/System.err: at com.android.volley.toolbox.JsonRequest.deliverResponse(JsonRequest.java:72)
    10-17 07:24:49.559 22735-22735/com.shyamdev.animewallpaperhd W/System.err: at com.android.volley.ExecutorDelivery$ResponseDeliveryRunnable.run(ExecutorDelivery.java:99)
    10-17 07:24:49.559 22735-22735/com.shyamdev.animewallpaperhd W/System.err: at android.os.Handler.handleCallback(Handler.java:739)
    10-17 07:24:49.560 22735-22735/com.shyamdev.animewallpaperhd W/System.err: at android.os.Handler.dispatchMessage(Handler.java:95)
    10-17 07:24:49.561 22735-22735/com.shyamdev.animewallpaperhd W/System.err: at android.os.Looper.loop(Looper.java:135)
    10-17 07:24:49.561 22735-22735/com.shyamdev.animewallpaperhd W/System.err: at android.app.ActivityThread.main(ActivityThread.java:5289)
    10-17 07:24:49.562 22735-22735/com.shyamdev.animewallpaperhd W/System.err: at java.lang.reflect.Method.invoke(Native Method)
    10-17 07:24:49.562 22735-22735/com.shyamdev.animewallpaperhd W/System.err: at java.lang.reflect.Method.invoke(Method.java:372)
    10-17 07:24:49.562 22735-22735/com.shyamdev.animewallpaperhd W/System.err: at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
    10-17 07:24:49.562 22735-22735/com.shyamdev.animewallpaperhd W/System.err: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)

  • Aldy Putra W

    Hi sir,how to change list in drawer to recyclerview? i want to develop this to material design

    Thanks 😀

  • Abdul Rehman

    very very nice article bundle of thanks please update the code with new method thanks

  • Chihab Chihab

    hello!

    Apk runs well but a problem in the menu (Recently Added) always shows nothing
    Why?

    For the other menu it works well. https://uploads.disquscdn.com/images/f486e9b52a5517b178be8c73609fba22c45a36ed3e3dedc2ac10ec68bfc73181.jpg

    thanks https://uploads.disquscdn.com/images/9e1c5570cf8c7b86771e3f60d6df70554cbbb55f6fa44196905d16bef83c1a10.jpg

    thank you

    • Try replacing http with https in image url.

      • Chihab Chihab

        Sorry I do not find!

      • Chihab Chihab
        • Ok. I got it now. Are you seeing any errors in LogCat?

          • Chihab Chihab

            no

          • Chihab Chihab

            All well except (Recently Added)

          • Fawad khan

            bro which api are you using ? because picasa albums are dead now and google albums are not public so where you storing your wallpapers ?

          • Chihab Chihab

            I made a test with your project

            Maybe the problem is that you have not put the picasa user name on the appconst file

          • Yes you have to configure your picasa account correctly in the app.

          • Chihab Chihab

            thanks

          • Chihab Chihab

            Possible to realize the project on android studio?

  • Chihab Chihab

    thank you

  • Chihab Chihab
  • Chihab Chihab

    here I would be very happy if you are going to make us a tutorial with source code of this model app.
    thank you very much https://uploads.disquscdn.com/images/a3ebb7819e0b388a832bde9895f01f23b09b5e249116a92b4a8b34c20358f60e.jpg

  • Aldy Putra W

    Google now retired Picasa Web services,i can’t change album to public and add photo ,so what should i do?