//
//src\com\example\android\home\ApplicationInfo.java
/*
* 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.content.ComponentName;
import android.content.Intent;
import android.graphics.drawable.Drawable;
/**
* Represents a launchable application. An application is made of a name (or title), an intent
* and an icon.
*/
class ApplicationInfo {
/**
* The application name.
*/
CharSequence title;
/**
* The intent used to start the application.
*/
Intent intent;
/**
* The application icon.
*/
Drawable icon;
/**
* When set to true, indicates that the icon has been resized.
*/
boolean filtered;
/**
* Creates the application intent based on a component name and various launch flags.
*
* @param className the class name of the component representing the intent
* @param launchFlags the launch flags
*/
final void setActivity(ComponentName className, int launchFlags) {
intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
intent.setComponent(className);
intent.setFlags(launchFlags);
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof ApplicationInfo)) {
return false;
}
ApplicationInfo that = (ApplicationInfo) o;
return title.equals(that.title) &&
intent.getComponent().getClassName().equals(
that.intent.getComponent().getClassName());
}
@Override
public int hashCode() {
int result;
result = (title != null ? title.hashCode() : 0);
final String name = intent.getComponent().getClassName();
result = 31 * result + (name != null ? name.hashCode() : 0);
return result;
}
}
//src\com\example\android\home\ApplicationsStackLayout.java
/*
* 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.content.Context;
import android.content.Intent;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.view.LayoutInflater;
import android.widget.TextView;
import java.util.List;
/**
* The ApplicationsStackLayout is a specialized layout used for the purpose of the home screen
* only. This layout stacks various icons in three distinct areas: the recents, the favorites
* (or faves) and the button.
*
* This layout supports two different orientations: vertical and horizontal. When horizontal,
* the areas are laid out this way:
*
* [RECENTS][FAVES][BUTTON]
*
* When vertical, the layout is the following:
*
* [RECENTS]
* [FAVES]
* [BUTTON]
*
* The layout operates from the "bottom up" (or from right to left.) This means that the button
* area will first be laid out, then the faves area, then the recents. When there are too many
* favorites, the recents area is not displayed.
*
* The following attributes can be set in XML:
*
* orientation: horizontal or vertical
* marginLeft: the left margin of each element in the stack
* marginTop: the top margin of each element in the stack
* marginRight: the right margin of each element in the stack
* marginBottom: the bottom margin of each element in the stack
*/
public class ApplicationsStackLayout extends ViewGroup implements View.OnClickListener {
public static final int HORIZONTAL = 0;
public static final int VERTICAL = 1;
private View mButton;
private LayoutInflater mInflater;
private int mFavoritesEnd;
private int mFavoritesStart;
private List mFavorites;
private List mRecents;
private int mOrientation = VERTICAL;
private int mMarginLeft;
private int mMarginTop;
private int mMarginRight;
private int mMarginBottom;
private Rect mDrawRect = new Rect();
private Drawable mBackground;
private int mIconSize;
public ApplicationsStackLayout(Context context) {
super(context);
initLayout();
}
public ApplicationsStackLayout(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray a =
context.obtainStyledAttributes(attrs, R.styleable.ApplicationsStackLayout);
mOrientation = a.getInt(R.styleable.ApplicationsStackLayout_stackOrientation, VERTICAL);
mMarginLeft = a.getDimensionPixelSize(R.styleable.ApplicationsStackLayout_marginLeft, 0);
mMarginTop = a.getDimensionPixelSize(R.styleable.ApplicationsStackLayout_marginTop, 0);
mMarginRight = a.getDimensionPixelSize(R.styleable.ApplicationsStackLayout_marginRight, 0);
mMarginBottom = a.getDimensionPixelSize(R.styleable.ApplicationsStackLayout_marginBottom, 0);
a.recycle();
mIconSize = 42; //(int) getResources().getDimension(android.R.dimen.app_icon_size);
initLayout();
}
private void initLayout() {
mInflater = LayoutInflater.from(getContext());
mButton = mInflater.inflate(R.layout.all_applications_button, this, false);
addView(mButton);
mBackground = getBackground();
setBackgroundDrawable(null);
setWillNotDraw(false);
}
/**
* Return the current orientation, either VERTICAL (default) or HORIZONTAL.
*
* @return the stack orientation
*/
public int getOrientation() {
return mOrientation;
}
@Override
protected void onDraw(Canvas canvas) {
final Drawable background = mBackground;
final int right = getWidth();
final int bottom = getHeight();
// Draw behind recents
if (mOrientation == VERTICAL) {
mDrawRect.set(0, 0, right, mFavoritesStart);
} else {
mDrawRect.set(0, 0, mFavoritesStart, bottom);
}
background.setBounds(mDrawRect);
background.draw(canvas);
// Draw behind favorites
if (mFavoritesStart > -1) {
if (mOrientation == VERTICAL) {
mDrawRect.set(0, mFavoritesStart, right, mFavoritesEnd);
} else {
mDrawRect.set(mFavoritesStart, 0, mFavoritesEnd, bottom);
}
background.setBounds(mDrawRect);
background.draw(canvas);
}
super.onDraw(canvas);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
final int heightSize = MeasureSpec.getSize(heightMeasureSpec);
if (widthMode != MeasureSpec.EXACTLY || heightMode != MeasureSpec.EXACTLY) {
throw new IllegalStateException("ApplicationsStackLayout can only be used with "
+ "measure spec mode=EXACTLY");
}
setMeasuredDimension(widthSize, heightSize);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
removeAllApplications();
LayoutParams layoutParams = mButton.getLayoutParams();
final int widthSpec = MeasureSpec.makeMeasureSpec(layoutParams.width, MeasureSpec.EXACTLY);
final int heightSpec = MeasureSpec.makeMeasureSpec(layoutParams.height, MeasureSpec.EXACTLY);
mButton.measure(widthSpec, heightSpec);
if (mOrientation == VERTICAL) {
layoutVertical();
} else {
layoutHorizontal();
}
}
private void layoutVertical() {
int childLeft = 0;
int childTop = getHeight();
int childWidth = mButton.getMeasuredWidth();
int childHeight = mButton.getMeasuredHeight();
childTop -= childHeight + mMarginBottom;
mButton.layout(childLeft, childTop, childLeft + childWidth, childTop + childHeight);
childTop -= mMarginTop;
mFavoritesEnd = childTop - mMarginBottom;
int oldChildTop = childTop;
childTop = stackApplications(mFavorites, childLeft, childTop);
if (childTop != oldChildTop) {
mFavoritesStart = childTop + mMarginTop;
} else {
mFavoritesStart = -1;
}
stackApplications(mRecents, childLeft, childTop);
}
private void layoutHorizontal() {
int childLeft = getWidth();
int childTop = 0;
int childWidth = mButton.getMeasuredWidth();
int childHeight = mButton.getMeasuredHeight();
childLeft -= childWidth;
mButton.layout(childLeft, childTop, childLeft + childWidth, childTop + childHeight);
childLeft -= mMarginLeft;
mFavoritesEnd = childLeft - mMarginRight;
int oldChildLeft = childLeft;
childLeft = stackApplications(mFavorites, childLeft, childTop);
if (childLeft != oldChildLeft) {
mFavoritesStart = childLeft + mMarginLeft;
} else {
mFavoritesStart = -1;
}
stackApplications(mRecents, childLeft, childTop);
}
private int stackApplications(List applications, int childLeft, int childTop) {
LayoutParams layoutParams;
int widthSpec;
int heightSpec;
int childWidth;
int childHeight;
final boolean isVertical = mOrientation == VERTICAL;
final int count = applications.size();
for (int i = count - 1; i >= 0; i--) {
final ApplicationInfo info = applications.get(i);
final View view = createApplicationIcon(mInflater, this, info);
layoutParams = view.getLayoutParams();
widthSpec = MeasureSpec.makeMeasureSpec(layoutParams.width, MeasureSpec.EXACTLY);
heightSpec = MeasureSpec.makeMeasureSpec(layoutParams.height, MeasureSpec.EXACTLY);
view.measure(widthSpec, heightSpec);
childWidth = view.getMeasuredWidth();
childHeight = view.getMeasuredHeight();
if (isVertical) {
childTop -= childHeight + mMarginBottom;
if (childTop < 0) {
childTop += childHeight + mMarginBottom;
break;
}
} else {
childLeft -= childWidth + mMarginRight;
if (childLeft < 0) {
childLeft += childWidth + mMarginRight;
break;
}
}
addViewInLayout(view, -1, layoutParams);
view.layout(childLeft, childTop, childLeft + childWidth, childTop + childHeight);
if (isVertical) {
childTop -= mMarginTop;
} else {
childLeft -= mMarginLeft;
}
}
return isVertical ? childTop : childLeft;
}
private void removeAllApplications() {
final int count = getChildCount();
for (int i = count - 1; i >= 0; i--) {
final View view = getChildAt(i);
if (view != mButton) {
removeViewAt(i);
}
}
}
private View createApplicationIcon(LayoutInflater inflater,
ViewGroup group, ApplicationInfo info) {
TextView textView = (TextView) inflater.inflate(R.layout.favorite, group, false);
info.icon.setBounds(0, 0, mIconSize, mIconSize);
textView.setCompoundDrawables(null, info.icon, null, null);
textView.setText(info.title);
textView.setTag(info.intent);
textView.setOnClickListener(this);
return textView;
}
/**
* Sets the list of favorites.
*
* @param applications the applications to put in the favorites area
*/
public void setFavorites(List applications) {
mFavorites = applications;
requestLayout();
}
/**
* Sets the list of recents.
*
* @param applications the applications to put in the recents area
*/
public void setRecents(List applications) {
mRecents = applications;
requestLayout();
}
public void onClick(View v) {
getContext().startActivity((Intent) v.getTag());
}
}
//src\com\example\android\home\Home.java
/*
* 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.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.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.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.TextView;
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 mApplications;
private static LinkedList mFavorites;
private final BroadcastReceiver mWallpaperReceiver = new WallpaperIntentReceiver();
private final BroadcastReceiver mApplicationsReceiver = new ApplicationsIntentReceiver();
private 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;
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setDefaultKeyMode(DEFAULT_KEYS_SEARCH_LOCAL);
setContentView(R.layout.home);
registerIntentReceivers();
setDefaultWallpaper();
loadApplications(true);
bindApplications();
bindFavorites(true);
bindRecents();
bindButtons();
mGridEntry = AnimationUtils.loadAnimation(this, R.anim.grid_entry);
mGridExit = AnimationUtils.loadAnimation(this, R.anim.grid_exit);
}
@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) {
mGrid = (GridView) findViewById(R.id.all_apps);
}
mGrid.setAdapter(new ApplicationsAdapter(this, 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();
} 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 recentTasks = tasksManager.getRecentTasks(
MAX_RECENT_TASKS, 0);
final int count = recentTasks.size();
final ArrayList recents = new ArrayList();
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;
}
}
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_DOWN) {
switch (event.getKeyCode()) {
case KeyEvent.KEYCODE_BACK:
mBackDown = true;
return true;
case KeyEvent.KEYCODE_HOME:
mHomeDown = true;
return true;
}
} else if (event.getAction() == KeyEvent.ACTION_UP) {
switch (event.getKeyCode()) {
case KeyEvent.KEYCODE_BACK:
if (!event.isCanceled()) {
// Do BACK behavior.
}
mBackDown = true;
return true;
case KeyEvent.KEYCODE_HOME:
if (!event.isCanceled()) {
// Do HOME behavior.
}
mHomeDown = true;
return true;
}
}
return super.dispatchKeyEvent(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 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(count);
}
mApplications.clear();
for (int i = 0; i < count; i++) {
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);
application.icon = info.activityInfo.loadIcon(manager);
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.
*/
private class ApplicationsAdapter extends ArrayAdapter {
private Rect mOldBounds = new Rect();
public ApplicationsAdapter(Context context, ArrayList 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);
final int iconWidth = icon.getIntrinsicWidth();
final int iconHeight = icon.getIntrinsicHeight();
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.
*/
private class ApplicationLauncher implements AdapterView.OnItemClickListener {
public void onItemClick(AdapterView parent, View v, int position, long id) {
ApplicationInfo app = (ApplicationInfo) parent.getItemAtPosition(position);
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();
}
}
}
//src\com\example\android\home\Wallpaper.java
/*
* Copyright (C) 2006 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.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.Gallery;
import android.widget.ImageView;
import android.widget.Gallery.LayoutParams;
import java.io.IOException;
import java.io.InputStream;
/**
* Wallpaper picker for the Home application. User can choose from
* a gallery of stock photos.
*/
public class Wallpaper extends Activity implements
AdapterView.OnItemSelectedListener, AdapterView.OnItemClickListener {
private static final String LOG_TAG = "Home";
private static final Integer[] THUMB_IDS = {
R.drawable.bg_android_icon,
R.drawable.bg_sunrise_icon,
R.drawable.bg_sunset_icon,
};
private static final Integer[] IMAGE_IDS = {
R.drawable.bg_android,
R.drawable.bg_sunrise,
R.drawable.bg_sunset,
};
private Gallery mGallery;
private boolean mIsWallpaperSet;
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.wallpaper);
mGallery = (Gallery) findViewById(R.id.gallery);
mGallery.setAdapter(new ImageAdapter(this));
mGallery.setOnItemSelectedListener(this);
mGallery.setOnItemClickListener(this);
}
@Override
protected void onResume() {
super.onResume();
mIsWallpaperSet = false;
}
public void onItemSelected(AdapterView parent, View v, int position, long id) {
getWindow().setBackgroundDrawableResource(IMAGE_IDS[position]);
}
public void onItemClick(AdapterView parent, View v, int position, long id) {
selectWallpaper(position);
}
/*
* When using touch if you tap an image it triggers both the onItemClick and
* the onTouchEvent causing the wallpaper to be set twice. Synchronize this
* method and ensure we only set the wallpaper once.
*/
private synchronized void selectWallpaper(int position) {
if (mIsWallpaperSet) {
return;
}
mIsWallpaperSet = true;
try {
InputStream stream = getResources().openRawResource(IMAGE_IDS[position]);
setWallpaper(stream);
setResult(RESULT_OK);
finish();
} catch (IOException e) {
Log.e(LOG_TAG, "Failed to set wallpaper " + e);
}
}
public void onNothingSelected(AdapterView parent) {
}
@Override
public boolean onTouchEvent(MotionEvent event) {
selectWallpaper(mGallery.getSelectedItemPosition());
return true;
}
public class ImageAdapter extends BaseAdapter {
private Context mContext;
public ImageAdapter(Context c) {
mContext = c;
}
public int getCount() {
return THUMB_IDS.length;
}
public Object getItem(int position) {
return position;
}
public long getItemId(int position) {
return position;
}
public View getView(final int position, View convertView, ViewGroup parent) {
ImageView i = new ImageView(mContext);
i.setImageResource(THUMB_IDS[position]);
i.setAdjustViewBounds(true);
i.setLayoutParams(new Gallery.LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
i.setBackgroundResource(android.R.drawable.picture_frame);
return i;
}
}
}
//
//res\anim\fade_in.xml
android:interpolator="@android:anim/accelerate_interpolator"
android:fromAlpha="0.0" android:toAlpha="1.0" android:duration="50" />
//res\anim\fade_out.xml
android:interpolator="@android:anim/accelerate_interpolator"
android:fromAlpha="1.0" android:toAlpha="0.0" android:duration="50" />
//res\anim\grid_entry.xml
android:interpolator="@android:anim/decelerate_interpolator">
android:fromYScale="0.9" android:toYScale="1.0"
android:pivotX="100%" android:pivotY="100%" android:duration="200" />
//res\anim\grid_exit.xml
android:interpolator="@android:anim/accelerate_interpolator"
android:fromAlpha="1.0" android:toAlpha="0.0" android:duration="200" />
//res\anim\hide_applications.xml
android:rowDelay="25%"
android:directionPriority="column"
android:animation="@anim/fade_out" />
//res\anim\show_applications.xml
android:rowDelay="25%"
android:directionPriority="column"
android:direction="right_to_left|bottom_to_top"
android:animation="@anim/fade_in" />
//
//res\color\bright_text_dark_focused.xml
//
//res\layout\all_applications_button.xml
android:id="@+id/show_all_apps"
android:layout_width="78dip"
android:layout_height="65dip"
android:orientation="vertical"
android:gravity="center_vertical"
android:clickable="true"
android:focusable="true"
android:background="@drawable/all_applications_button_background">
android:id="@+id/show_all_apps_check"
android:focusable="false"
android:clickable="false"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/all_applications_background"
android:button="@drawable/all_applications"
android:text="@string/show_all_apps"
android:textSize="12dip"
android:maxLines="1"
android:duplicateParentState="true"
android:textColor="@color/bright_text_dark_focused"
android:gravity="center_horizontal" />
//res\layout\application.xml
android:id="@+id/label"
android:layout_width="78dip"
android:layout_height="65dip"
android:paddingTop="4dip"
android:textSize="12dip"
android:singleLine="true"
android:ellipsize="end"
android:textColor="@color/bright_text_dark_focused"
android:gravity="center_horizontal|center_vertical" />
//res\layout\favorite.xml
android:layout_width="78dip"
android:layout_height="65dip"
android:paddingTop="3dip"
android:paddingBottom="3dip"
android:clickable="true"
android:focusable="true"
android:background="@drawable/favorite_background"
android:textSize="12dip"
android:maxLines="1"
android:ellipsize="end"
android:textColor="@color/bright_text_dark_focused"
android:gravity="center_horizontal|bottom" />
//res\layout\wallpaper.xml
android:layout_width="match_parent"
android:layout_height="match_parent">
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="5dip"
android:background="#70000000"
android:text="@string/wallpaper_instructions"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
/>
android:background="#70000000"
android:layout_width="match_parent"
android:layout_height="60dip"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:gravity="center_vertical"
android:spacing="16dp"
/>
//
//res\layout-land\home.xml
xmlns:home="http://schemas.android.com/apk/res/com.example.android.home"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
android:background="@drawable/application_background"
android:persistentDrawingCache="animation|scrolling"
android:alwaysDrawnWithCache="true"
android:scrollbars="none"
android:drawSelectorOnTop="false"
android:listSelector="@drawable/grid_selector"
android:numColumns="auto_fit"
android:columnWidth="78dp"
android:stretchMode="spacingWidth"
android:layout_weight="1.0"
android:layout_height="0dip"
android:layout_width="match_parent"
android:stackFromBottom="true"
android:visibility="invisible" />
home:stackOrientation="horizontal"
home:marginLeft="1dip"
home:marginRight="1dip"
android:layout_marginTop="0dip"
android:layout_width="match_parent"
android:layout_height="65dip"
android:background="@drawable/application_background" />
//
//res\layout-port\home.xml
xmlns:home="http://schemas.android.com/apk/res/com.example.android.home"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
android:background="@drawable/application_background"
android:persistentDrawingCache="animation|scrolling"
android:alwaysDrawnWithCache="true"
android:scrollbars="none"
android:drawSelectorOnTop="false"
android:listSelector="@drawable/grid_selector"
android:numColumns="auto_fit"
android:columnWidth="78dp"
android:stretchMode="spacingWidth"
android:layout_weight="1.0"
android:layout_height="0dip"
android:layout_width="match_parent"
android:stackFromBottom="true"
android:visibility="invisible" />
home:stackOrientation="horizontal"
home:marginLeft="1dip"
home:marginRight="1dip"
android:layout_marginTop="0dip"
android:layout_width="match_parent"
android:layout_height="65dip"
android:background="@drawable/application_background" />
//
//res\values\attrs.xml
//res\values\strings.xml
Home Sample
All
Wallpaper
Search
Settings
Tap picture to set portrait wallpaper
//res\values\styles.xml
//
//res\values-cs\strings.xml
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
"Dom"
"Ve"
"Tapeta"
"Hledat"
"Klepnutm na obrzek nastavte tapetu portrtu"
//
//res\values-land\strings.xml
Tap image to set landscape wallpaper