com.example.android.home.Home.java Source code

Java tutorial

Introduction

Here is the source code for com.example.android.home.Home.java

Source

/*
 * Copyright (C) 2007 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.example.android.home;

import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.SearchManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PaintFlagsDrawFilter;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.ColorFilter;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.PaintDrawable;
import android.os.Bundle;
import android.os.Environment;
import android.support.v4.view.ViewPager;
import android.util.Log;
import android.util.Xml;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.animation.LayoutAnimationController;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;
import android.widget.GridView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;

import java.io.IOException;
import java.io.FileReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

public class Home extends Activity {
    /**
     * Tag used for logging errors.
     */
    private static final String LOG_TAG = "Home";

    /**
     * Keys during freeze/thaw.
     */
    private static final String KEY_SAVE_GRID_OPENED = "grid.opened";

    private static final String DEFAULT_FAVORITES_PATH = "etc/favorites.xml";

    private static final String TAG_FAVORITES = "favorites";
    private static final String TAG_FAVORITE = "favorite";
    private static final String TAG_PACKAGE = "package";
    private static final String TAG_CLASS = "class";

    // Identifiers for option menu items
    private static final int MENU_WALLPAPER_SETTINGS = Menu.FIRST + 1;
    private static final int MENU_SEARCH = MENU_WALLPAPER_SETTINGS + 1;
    private static final int MENU_SETTINGS = MENU_SEARCH + 1;

    /**
     * Maximum number of recent tasks to query.
     */
    private static final int MAX_RECENT_TASKS = 20;

    private static boolean mWallpaperChecked;
    private static ArrayList<ApplicationInfo> mApplications;
    //private static LinkedList<ApplicationInfo> mFavorites;

    private final BroadcastReceiver mWallpaperReceiver = new WallpaperIntentReceiver();
    private final BroadcastReceiver mApplicationsReceiver = new ApplicationsIntentReceiver();

    private GridView mGrid;
    //static GridView mGrid;

    private LayoutAnimationController mShowLayoutAnimation;
    private LayoutAnimationController mHideLayoutAnimation;

    private boolean mBlockAnimation;

    private boolean mHomeDown;
    private boolean mBackDown;

    //private View mShowApplications;
    private CheckBox mShowApplicationsCheck;

    //private ApplicationsStackLayout mApplicationsStack;

    private Animation mGridEntry;
    private Animation mGridExit;

    private ViewPager myPager;

    @Override
    public void onCreate(Bundle icicle) {
        super.onCreate(icicle);

        setDefaultKeyMode(DEFAULT_KEYS_SEARCH_LOCAL);

        setContentView(R.layout.home);
        //setContentView(R.layout.home_main_panel);

        registerIntentReceivers();

        //setDefaultWallpaper();
        getWindow().setBackgroundDrawableResource(R.drawable.bg_android);

        loadApplications(true);

        bindApplications();
        //bindFavorites(true);
        //bindRecents();
        //bindButtons();

        mGridEntry = AnimationUtils.loadAnimation(this, R.anim.grid_entry);
        mGridExit = AnimationUtils.loadAnimation(this, R.anim.grid_exit);

        // Set up page adapter
        HomePagerAdapter adapter = new HomePagerAdapter(getApplicationContext(),
                new ApplicationsAdapter(this, mApplications));
        myPager = (ViewPager) findViewById(R.id.three_panel_pager);
        myPager.setAdapter(adapter);
        myPager.setCurrentItem(HomePagerAdapter.SCREEN_CENTER);
    }

    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);

        // Close the menu
        if (Intent.ACTION_MAIN.equals(intent.getAction())) {
            getWindow().closeAllPanels();
        }
    }

    @Override
    public void onDestroy() {
        super.onDestroy();

        // Remove the callback for the cached drawables or we leak
        // the previous Home screen on orientation change
        final int count = mApplications.size();
        for (int i = 0; i < count; i++) {
            mApplications.get(i).icon.setCallback(null);
        }

        unregisterReceiver(mWallpaperReceiver);
        unregisterReceiver(mApplicationsReceiver);
    }

    @Override
    protected void onResume() {
        super.onResume();
        //bindRecents();
    }

    @Override
    protected void onRestoreInstanceState(Bundle state) {
        super.onRestoreInstanceState(state);
        final boolean opened = state.getBoolean(KEY_SAVE_GRID_OPENED, false);
        if (opened) {
            showApplications(false);
        }
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putBoolean(KEY_SAVE_GRID_OPENED, mGrid.getVisibility() == View.VISIBLE);
    }

    /**
     * Registers various intent receivers. The current implementation registers
     * only a wallpaper intent receiver to let other applications change the
     * wallpaper.
     */
    private void registerIntentReceivers() {
        IntentFilter filter = new IntentFilter(Intent.ACTION_WALLPAPER_CHANGED);
        registerReceiver(mWallpaperReceiver, filter);

        filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
        filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
        filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
        filter.addDataScheme("package");
        registerReceiver(mApplicationsReceiver, filter);
    }

    /**
     * Creates a new appplications adapter for the grid view and registers it.
     */
    private void bindApplications() {
        if (mGrid == null) {

            //final LayoutInflater layoutInflater = getLayoutInflater();
            //View mainPanel = layoutInflater.inflate(R.layout.home_main_panel, null);

            //mGrid = (GridView) mainPanel.findViewById(R.id.all_apps);
            mGrid = new GridView(this);

            //mGrid = (GridView) findViewById(R.id.all_apps);
        }
        //mGrid.setAdapter(new ApplicationsAdapter(this, mApplications));
        //mGrid.setAdapter(new ApplicationsAdapter(mGrid.getContext(), mApplications));
        mGrid.setSelection(0);

        //        if (mApplicationsStack == null) {
        //            mApplicationsStack = (ApplicationsStackLayout) findViewById(R.id.faves_and_recents);
        //        }
    }

    //    /**
    //     * Binds actions to the various buttons.
    //     */
    //    private void bindButtons() {
    ////        mShowApplications = findViewById(R.id.show_all_apps);
    ////        mShowApplications.setOnClickListener(new ShowApplications());
    ////        mShowApplicationsCheck = (CheckBox) findViewById(R.id.show_all_apps_check);
    //
    //        mGrid.setOnItemClickListener(new ApplicationLauncher());
    //    }

    /**
     * When no wallpaper was manually set, a default wallpaper is used instead.
     */
    /*
    private void setDefaultWallpaper() {
    if (!mWallpaperChecked) {
        Drawable wallpaper = peekWallpaper();
        if (wallpaper == null) {
            try {
                clearWallpaper();
            } catch (IOException e) {
                Log.e(LOG_TAG, "Failed to clear wallpaper " + e);
            }
        } else {
            getWindow().setBackgroundDrawable(new ClippedDrawable(wallpaper));
        }
        mWallpaperChecked = true;
    }
    }
    */
    /**
     * Refreshes the favorite applications stacked over the all apps button.
     * The number of favorites depends on the user.
     */

    /*
    private void bindFavorites(boolean isLaunching) {
    if (!isLaunching || mFavorites == null) {
        
        if (mFavorites == null) {
            mFavorites = new LinkedList<ApplicationInfo>();
        } else {
            mFavorites.clear();
        }
        //mApplicationsStack.setFavorites(mFavorites);            
            
        FileReader favReader;
        
        // Environment.getRootDirectory() is a fancy way of saying ANDROID_ROOT or "/system".
        final File favFile = new File(Environment.getRootDirectory(), DEFAULT_FAVORITES_PATH);
        try {
            favReader = new FileReader(favFile);
        } catch (FileNotFoundException e) {
            Log.e(LOG_TAG, "Couldn't find or open favorites file " + favFile);
            return;
        }
        
        final Intent intent = new Intent(Intent.ACTION_MAIN, null);
        intent.addCategory(Intent.CATEGORY_LAUNCHER);
        
        final PackageManager packageManager = getPackageManager();
        
        try {
            final XmlPullParser parser = Xml.newPullParser();
            parser.setInput(favReader);
        
            beginDocument(parser, TAG_FAVORITES);
        
            ApplicationInfo info;
        
            while (true) {
                nextElement(parser);
        
                String name = parser.getName();
                if (!TAG_FAVORITE.equals(name)) {
                    break;
                }
        
                final String favoritePackage = parser.getAttributeValue(null, TAG_PACKAGE);
                final String favoriteClass = parser.getAttributeValue(null, TAG_CLASS);
        
                final ComponentName cn = new ComponentName(favoritePackage, favoriteClass);
                intent.setComponent(cn);
                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        
                info = getApplicationInfo(packageManager, intent);
                if (info != null) {
                    info.intent = intent;
                    mFavorites.addFirst(info);
                }
            }
        } catch (XmlPullParserException e) {
            Log.w(LOG_TAG, "Got exception parsing favorites.", e);
        } catch (IOException e) {
            Log.w(LOG_TAG, "Got exception parsing favorites.", e);
        }
    }
        
    //mApplicationsStack.setFavorites(mFavorites);
    }
        
    private static void beginDocument(XmlPullParser parser, String firstElementName)
        throws XmlPullParserException, IOException {
        
    int type;
    while ((type = parser.next()) != XmlPullParser.START_TAG &&
            type != XmlPullParser.END_DOCUMENT) {
        // Empty
    }
        
    if (type != XmlPullParser.START_TAG) {
        throw new XmlPullParserException("No start tag found");
    }
        
    if (!parser.getName().equals(firstElementName)) {
        throw new XmlPullParserException("Unexpected start tag: found " + parser.getName() +
                ", expected " + firstElementName);
    }
    }
        
    private static void nextElement(XmlPullParser parser) throws XmlPullParserException, IOException {
    int type;
    while ((type = parser.next()) != XmlPullParser.START_TAG &&
            type != XmlPullParser.END_DOCUMENT) {
        // Empty
    }
    }
    */
    /**
     * Refreshes the recently launched applications stacked over the favorites. The number
     * of recents depends on how many favorites are present.
     */
    /*
    private void bindRecents() {
    final PackageManager manager = getPackageManager();
    final ActivityManager tasksManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
    final List<ActivityManager.RecentTaskInfo> recentTasks = tasksManager.getRecentTasks(
            MAX_RECENT_TASKS, 0);
        
    final int count = recentTasks.size();
    final ArrayList<ApplicationInfo> recents = new ArrayList<ApplicationInfo>();
        
    for (int i = count - 1; i >= 0; i--) {
        final Intent intent = recentTasks.get(i).baseIntent;
        
        if (Intent.ACTION_MAIN.equals(intent.getAction()) &&
                !intent.hasCategory(Intent.CATEGORY_HOME)) {
        
            ApplicationInfo info = getApplicationInfo(manager, intent);
            if (info != null) {
                info.intent = intent;
    //                    if (!mFavorites.contains(info)) {
    //                        recents.add(info);
    //                    }
            }
        }
    }
        
    //mApplicationsStack.setRecents(recents);
    }
    */
    private static ApplicationInfo getApplicationInfo(PackageManager manager, Intent intent) {
        final ResolveInfo resolveInfo = manager.resolveActivity(intent, 0);

        if (resolveInfo == null) {
            return null;
        }

        final ApplicationInfo info = new ApplicationInfo();
        final ActivityInfo activityInfo = resolveInfo.activityInfo;
        info.icon = activityInfo.loadIcon(manager);
        if (info.title == null || info.title.length() == 0) {
            info.title = activityInfo.loadLabel(manager);
        }
        if (info.title == null) {
            info.title = "";
        }
        return info;
    }

    @Override
    public void onWindowFocusChanged(boolean hasFocus) {
        super.onWindowFocusChanged(hasFocus);
        if (!hasFocus) {
            mBackDown = mHomeDown = false;
        }
    }

    @SuppressLint({ "NewApi", "NewApi" })
    @Override
    public boolean dispatchKeyEvent(KeyEvent event) {
        Toast.makeText(getApplicationContext(), "dispatchKeyEvent", Toast.LENGTH_SHORT).show();

        if (event.getAction() == KeyEvent.ACTION_DOWN) {
            switch (event.getKeyCode()) {
            case KeyEvent.KEYCODE_BACK:
                mBackDown = true;
                Toast.makeText(getApplicationContext(), "BACK 1", Toast.LENGTH_SHORT).show();
                myPager.setCurrentItem(HomePagerAdapter.SCREEN_CENTER);
                return true;
            case KeyEvent.KEYCODE_HOME:
                mHomeDown = true;
                //myPager.setCurrentItem(HomePagerAdapter.SCREEN_CENTER); 
                //myPager.invalidate();
                Toast.makeText(getApplicationContext(), "HOME", Toast.LENGTH_SHORT).show();
                Log.e("PUSH", "Home 2");
                return true;
            }
        } else if (event.getAction() == KeyEvent.ACTION_UP) {
            switch (event.getKeyCode()) {
            case KeyEvent.KEYCODE_BACK:
                if (!event.isCanceled()) {
                    // Do BACK behavior.
                    Toast.makeText(getApplicationContext(), "BACK 2", Toast.LENGTH_SHORT).show();
                }
                mBackDown = true;
                return true;
            case KeyEvent.KEYCODE_HOME:
                Toast.makeText(getApplicationContext(), "HOME", Toast.LENGTH_SHORT).show();
                Log.e("PUSH", "Home 2");
                if (!event.isCanceled()) {
                    // Do HOME behavior.
                    //myPager.setCurrentItem(HomePagerAdapter.SCREEN_CENTER); 
                    Toast.makeText(getApplicationContext(), "HOME", Toast.LENGTH_SHORT).show();
                    Log.e("PUSH", "Home 2");
                }
                mHomeDown = true;
                return true;
            }
        }

        return super.dispatchKeyEvent(event);
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        Toast.makeText(this, "onKeyDown", Toast.LENGTH_LONG).show();
        if ((keyCode == KeyEvent.KEYCODE_HOME)) {
            Toast.makeText(this, "You pressed the home button!", Toast.LENGTH_LONG).show();
            return true;
        }
        return super.onKeyDown(keyCode, event);
    }

    /*
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
    super.onCreateOptionsMenu(menu);
        
    menu.add(0, MENU_WALLPAPER_SETTINGS, 0, R.string.menu_wallpaper)
             .setIcon(android.R.drawable.ic_menu_gallery)
             .setAlphabeticShortcut('W');
    menu.add(0, MENU_SEARCH, 0, R.string.menu_search)
            .setIcon(android.R.drawable.ic_search_category_default)
            .setAlphabeticShortcut(SearchManager.MENU_KEY);
    menu.add(0, MENU_SETTINGS, 0, R.string.menu_settings)
            .setIcon(android.R.drawable.ic_menu_preferences)
            .setIntent(new Intent(android.provider.Settings.ACTION_SETTINGS));
        
    return true;
    }
        
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case MENU_WALLPAPER_SETTINGS:
            startWallpaper();
            return true;
        case MENU_SEARCH:
            onSearchRequested();
            return true;
    }
        
    return super.onOptionsItemSelected(item);
    }
        
    private void startWallpaper() {
    final Intent pickWallpaper = new Intent(Intent.ACTION_SET_WALLPAPER);
    startActivity(Intent.createChooser(pickWallpaper, getString(R.string.menu_wallpaper)));
    }
    */
    /**
     * Loads the list of installed applications in mApplications.
     */
    private void loadApplications(boolean isLaunching) {
        if (isLaunching && mApplications != null) {
            return;
        }

        PackageManager manager = getPackageManager();

        Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
        mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);

        final List<ResolveInfo> apps = manager.queryIntentActivities(mainIntent, 0);
        Collections.sort(apps, new ResolveInfo.DisplayNameComparator(manager));

        if (apps != null) {
            final int count = apps.size();

            if (mApplications == null) {
                mApplications = new ArrayList<ApplicationInfo>(count);
            }
            mApplications.clear();

            for (int i = 0; i < count; i++) {
                //for (int i = 0; i < 6; i++) {            // show only 6 apps
                ApplicationInfo application = new ApplicationInfo();
                ResolveInfo info = apps.get(i);

                application.title = info.loadLabel(manager);
                application.setActivity(
                        new ComponentName(info.activityInfo.applicationInfo.packageName, info.activityInfo.name),
                        Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);

                Log.v("Home APP", "package neme= " + info.activityInfo.applicationInfo.packageName);
                Log.v("Home APP", "neme= " + info.activityInfo.name);
                Log.v("Home APP", "title= " + application.title);

                application.icon = info.activityInfo.loadIcon(manager);

                // TODO
                // Replace Icons
                //if((application.title+"").equals("Calculator")) application.icon = getResources().getDrawable(R.drawable.ic_launcher_home_big);

                // Add Application
                if ((application.title + "").equals("Browser"))
                    mApplications.add(application);
                if ((application.title + "").equals("Phone"))
                    mApplications.add(application);
                if ((application.title + "").equals("People"))
                    mApplications.add(application);
                if ((application.title + "").equals("Messaging"))
                    mApplications.add(application);
                if ((application.title + "").equals("Settings"))
                    mApplications.add(application);

            }

            // Took from http://hi-android.info/src/index.html
            // ********************* ADD Call Log
            ApplicationInfo application = new ApplicationInfo();
            application.title = "Call Log";
            application.icon = getResources().getDrawable(R.drawable.ic_launcher_home);
            application.setActivity(
                    new ComponentName("com.android.contacts", "com.android.contacts.RecentCallsListActivity"),
                    Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
            mApplications.add(application);
        }
    }

    /**
     * Shows all of the applications by playing an animation on the grid.
     */
    private void showApplications(boolean animate) {
        if (mBlockAnimation) {
            return;
        }
        mBlockAnimation = true;

        mShowApplicationsCheck.toggle();

        if (mShowLayoutAnimation == null) {
            mShowLayoutAnimation = AnimationUtils.loadLayoutAnimation(this, R.anim.show_applications);
        }

        // This enables a layout animation; if you uncomment this code, you need to
        // comment the line mGrid.startAnimation() below
        //        mGrid.setLayoutAnimationListener(new ShowGrid());
        //        mGrid.setLayoutAnimation(mShowLayoutAnimation);
        //        mGrid.startLayoutAnimation();

        if (animate) {
            mGridEntry.setAnimationListener(new ShowGrid());
            mGrid.startAnimation(mGridEntry);
        }

        mGrid.setVisibility(View.VISIBLE);

        if (!animate) {
            mBlockAnimation = false;
        }

        // ViewDebug.startHierarchyTracing("Home", mGrid);
    }

    /**
     * Hides all of the applications by playing an animation on the grid.
     */
    private void hideApplications() {
        if (mBlockAnimation) {
            return;
        }
        mBlockAnimation = true;

        mShowApplicationsCheck.toggle();

        if (mHideLayoutAnimation == null) {
            mHideLayoutAnimation = AnimationUtils.loadLayoutAnimation(this, R.anim.hide_applications);
        }

        mGridExit.setAnimationListener(new HideGrid());
        mGrid.startAnimation(mGridExit);
        mGrid.setVisibility(View.INVISIBLE);
        //        mShowApplications.requestFocus();

        // This enables a layout animation; if you uncomment this code, you need to
        // comment the line mGrid.startAnimation() above
        //        mGrid.setLayoutAnimationListener(new HideGrid());
        //        mGrid.setLayoutAnimation(mHideLayoutAnimation);
        //        mGrid.startLayoutAnimation();
    }

    /**
     * Receives intents from other applications to change the wallpaper.
     */
    private class WallpaperIntentReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            getWindow().setBackgroundDrawable(new ClippedDrawable(getWallpaper()));
        }
    }

    /**
     * Receives notifications when applications are added/removed.
     */
    private class ApplicationsIntentReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            loadApplications(false);
            bindApplications();
            //bindRecents();
            //bindFavorites(false);
        }
    }

    /**
     * GridView adapter to show the list of all installed applications.
     */
    class ApplicationsAdapter extends ArrayAdapter<ApplicationInfo> {
        private Rect mOldBounds = new Rect();

        public ApplicationsAdapter(Context context, ArrayList<ApplicationInfo> apps) {
            super(context, 0, apps);
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            final ApplicationInfo info = mApplications.get(position);

            if (convertView == null) {
                final LayoutInflater inflater = getLayoutInflater();
                convertView = inflater.inflate(R.layout.application, parent, false);
            }

            Drawable icon = info.icon;

            if (!info.filtered) {
                //final Resources resources = getContext().getResources();
                //                int width = 42;//(int) resources.getDimension(android.R.dimen.app_icon_size);
                //                int height = 42;//(int) resources.getDimension(android.R.dimen.app_icon_size);
                // TODO
                int width = 92;//(int) resources.getDimension(android.R.dimen.app_icon_size);
                int height = 92;//(int) resources.getDimension(android.R.dimen.app_icon_size);               

                //                final int iconWidth = icon.getIntrinsicWidth();
                //                final int iconHeight = icon.getIntrinsicHeight();

                final int iconWidth = 95;
                final int iconHeight = 95;

                if (icon instanceof PaintDrawable) {
                    PaintDrawable painter = (PaintDrawable) icon;
                    painter.setIntrinsicWidth(width);
                    painter.setIntrinsicHeight(height);
                }

                if (width > 0 && height > 0 && (width < iconWidth || height < iconHeight)) {
                    final float ratio = (float) iconWidth / iconHeight;

                    if (iconWidth > iconHeight) {
                        height = (int) (width / ratio);
                    } else if (iconHeight > iconWidth) {
                        width = (int) (height * ratio);
                    }

                    final Bitmap.Config c = icon.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888
                            : Bitmap.Config.RGB_565;
                    final Bitmap thumb = Bitmap.createBitmap(width, height, c);
                    final Canvas canvas = new Canvas(thumb);
                    canvas.setDrawFilter(new PaintFlagsDrawFilter(Paint.DITHER_FLAG, 0));
                    // Copy the old bounds to restore them later
                    // If we were to do oldBounds = icon.getBounds(),
                    // the call to setBounds() that follows would
                    // change the same instance and we would lose the
                    // old bounds
                    mOldBounds.set(icon.getBounds());
                    icon.setBounds(0, 0, width, height);
                    icon.draw(canvas);
                    icon.setBounds(mOldBounds);
                    icon = info.icon = new BitmapDrawable(thumb);
                    info.filtered = true;
                }
            }

            final TextView textView = (TextView) convertView.findViewById(R.id.label);
            textView.setCompoundDrawablesWithIntrinsicBounds(null, icon, null, null);
            textView.setText(info.title);

            return convertView;
        }
    }

    /**
     * Shows and hides the applications grid view.
     */
    private class ShowApplications implements View.OnClickListener {
        public void onClick(View v) {
            if (mGrid.getVisibility() != View.VISIBLE) {
                showApplications(true);
            } else {
                hideApplications();
            }
        }
    }

    /**
     * Hides the applications grid when the layout animation is over.
     */
    private class HideGrid implements Animation.AnimationListener {
        public void onAnimationStart(Animation animation) {
        }

        public void onAnimationEnd(Animation animation) {
            mBlockAnimation = false;
        }

        public void onAnimationRepeat(Animation animation) {
        }
    }

    /**
     * Shows the applications grid when the layout animation is over.
     */
    private class ShowGrid implements Animation.AnimationListener {
        public void onAnimationStart(Animation animation) {
        }

        public void onAnimationEnd(Animation animation) {
            mBlockAnimation = false;
            // ViewDebug.stopHierarchyTracing();
        }

        public void onAnimationRepeat(Animation animation) {
        }
    }

    /**
     * Starts the selected activity/application in the grid view.
     */
    class ApplicationLauncher implements AdapterView.OnItemClickListener {
        public void onItemClick(AdapterView parent, View v, int position, long id) {
            ApplicationInfo app = (ApplicationInfo) parent.getItemAtPosition(position);
            Log.e("ApplicationLauncher", app.intent + "");
            startActivity(app.intent);
        }
    }

    /**
     * When a drawable is attached to a View, the View gives the Drawable its dimensions
     * by calling Drawable.setBounds(). In this application, the View that draws the
     * wallpaper has the same size as the screen. However, the wallpaper might be larger
     * that the screen which means it will be automatically stretched. Because stretching
     * a bitmap while drawing it is very expensive, we use a ClippedDrawable instead.
     * This drawable simply draws another wallpaper but makes sure it is not stretched
     * by always giving it its intrinsic dimensions. If the wallpaper is larger than the
     * screen, it will simply get clipped but it won't impact performance.
     */
    private class ClippedDrawable extends Drawable {
        private final Drawable mWallpaper;

        public ClippedDrawable(Drawable wallpaper) {
            mWallpaper = wallpaper;
        }

        @Override
        public void setBounds(int left, int top, int right, int bottom) {
            super.setBounds(left, top, right, bottom);
            // Ensure the wallpaper is as large as it really is, to avoid stretching it
            // at drawing time
            mWallpaper.setBounds(left, top, left + mWallpaper.getIntrinsicWidth(),
                    top + mWallpaper.getIntrinsicHeight());
        }

        public void draw(Canvas canvas) {
            mWallpaper.draw(canvas);
        }

        public void setAlpha(int alpha) {
            mWallpaper.setAlpha(alpha);
        }

        public void setColorFilter(ColorFilter cf) {
            mWallpaper.setColorFilter(cf);
        }

        public int getOpacity() {
            return mWallpaper.getOpacity();
        }
    }
}