Launcher中显示的App,Shortcut,Folder,Widget都是数据模型
继承关系图:
看一下ItemInfo.java
重要属性:X、Y坐标,占用位置(用于Widget),标题等
重要方法:初始构造,数据库存储,bitmap在db的读和存
class ItemInfo {
static final int NO_ID = -1;
//数据库中的Id
long id = NO_ID;
//Item类型,app,shortcut,folder,appwidget
int itemType;
//用来区分item在workspace还是在dock,还是在文件夹中
long container = NO_ID;
//在第几个屏幕上
int screen = -1;
//横坐标
int cellX = -1;
//从坐标
int cellY = -1;
//横向占用位置
int spanX = 1;
//纵向占用位置
int spanY = 1;
/**
* Indicates the minimum X cell span.
*/
int minSpanX = 1;
/**
* Indicates the minimum Y cell span.
*/
int minSpanY = 1;
//是否需要更新
boolean requiresDbUpdate = false;
//标题文本
CharSequence title;
//拖拽位置
int[] dropPos = null;
ItemInfo() {
}
ItemInfo(ItemInfo info) {
id = info.id;
cellX = info.cellX;
cellY = info.cellY;
spanX = info.spanX;
spanY = info.spanY;
screen = info.screen;
itemType = info.itemType;
container = info.container;
// tempdebug:
LauncherModel.checkItemInfo(this);
}
/** Returns the package name that the intent will resolve to, or an empty string if
* none exists. */
static String getPackageName(Intent intent) {
if (intent != null) {
String packageName = intent.getPackage();
if (packageName == null && intent.getComponent() != null) {
packageName = intent.getComponent().getPackageName();
}
if (packageName != null) {
return packageName;
}
}
return "";
}
/**
* Write the fields of this item to the DB
*
* @param values
*/
void onAddToDatabase(ContentValues values) {
values.put(LauncherSettings.BaseLauncherColumns.ITEM_TYPE, itemType);
values.put(LauncherSettings.Favorites.CONTAINER, container);
values.put(LauncherSettings.Favorites.SCREEN, screen);
values.put(LauncherSettings.Favorites.CELLX, cellX);
values.put(LauncherSettings.Favorites.CELLY, cellY);
values.put(LauncherSettings.Favorites.SPANX, spanX);
values.put(LauncherSettings.Favorites.SPANY, spanY);
}
void updateValuesWithCoordinates(ContentValues values, int cellX, int cellY) {
values.put(LauncherSettings.Favorites.CELLX, cellX);
values.put(LauncherSettings.Favorites.CELLY, cellY);
}
static byte[] flattenBitmap(Bitmap bitmap) {
// Try go guesstimate how much space the icon will take when serialized
// to avoid unnecessary allocations/copies during the write.
int size = bitmap.getWidth() * bitmap.getHeight() * 4;
ByteArrayOutputStream out = new ByteArrayOutputStream(size);
try {
bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
out.flush();
out.close();
return out.toByteArray();
} catch (IOException e) {
Log.w("Favorite", "Could not write icon");
return null;
}
}
static void writeBitmap(ContentValues values, Bitmap bitmap) {
if (bitmap != null) {
byte[] data = flattenBitmap(bitmap);
values.put(LauncherSettings.Favorites.ICON, data);
}
}
/**
* It is very important that sub-classes implement this if they contain any references
* to the activity (anything in the view hierarchy etc.). If not, leaks can result since
* ItemInfo objects persist across rotation and can hence leak by holding stale references
* to the old view hierarchy / activity.
*/
void unbind() {
}
@Override
public String toString() {
return "Item(id=" + this.id + " type=" + this.itemType + " container=" + this.container
+ " screen=" + screen + " cellX=" + cellX + " cellY=" + cellY + " spanX=" + spanX
+ " spanY=" + spanY + " dropPos=" + dropPos + ")";
}
ApplicationInfo.java
继承ItemInfo.java 增加了Intent属性,ComponentName,PackageName,StartActivity等属性和方法。
class ApplicationInfo extends ItemInfo {
private static final String TAG = "Launcher2.ApplicationInfo";
/**
* The intent used to start the application.
*/
Intent intent;
/**
* A bitmap version of the application icon.
*/
Bitmap iconBitmap;
/**
* The time at which the app was first installed.
*/
long firstInstallTime;
ComponentName componentName;
static final int DOWNLOADED_FLAG = 1;
static final int UPDATED_SYSTEM_APP_FLAG = 2;
int flags = 0;
ApplicationInfo() {
itemType = LauncherSettings.BaseLauncherColumns.ITEM_TYPE_SHORTCUT;
}
/**
* Must not hold the Context.
*/
public ApplicationInfo(PackageManager pm, ResolveInfo info, IconCache iconCache,
HashMap<Object, CharSequence> labelCache) {
final String packageName = info.activityInfo.applicationInfo.packageName;
this.componentName = new ComponentName(packageName, info.activityInfo.name);
this.container = ItemInfo.NO_ID;
this.setActivity(componentName,
Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
try {
int appFlags = pm.getApplicationInfo(packageName, 0).flags;
if ((appFlags & android.content.pm.ApplicationInfo.FLAG_SYSTEM) == 0) {
flags |= DOWNLOADED_FLAG;
if ((appFlags & android.content.pm.ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) {
flags |= UPDATED_SYSTEM_APP_FLAG;
}
}
firstInstallTime = pm.getPackageInfo(packageName, 0).firstInstallTime;
} catch (NameNotFoundException e) {
Log.d(TAG, "PackageManager.getApplicationInfo failed for " + packageName);
}
iconCache.getTitleAndIcon(this, info, labelCache);
}
public ApplicationInfo(ApplicationInfo info) {
super(info);
componentName = info.componentName;
title = info.title.toString();
intent = new Intent(info.intent);
flags = info.flags;
firstInstallTime = info.firstInstallTime;
}
/** Returns the package name that the shortcut's intent will resolve to, or an empty string if
* none exists. */
String getPackageName() {
return super.getPackageName(intent);
}
/**
* Creates the application intent based on a component name and various launch flags.
* Sets {@link #itemType} to {@link LauncherSettings.BaseLauncherColumns#ITEM_TYPE_APPLICATION}.
*
* @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);
itemType = LauncherSettings.BaseLauncherColumns.ITEM_TYPE_APPLICATION;
}
@Override
public String toString() {
return "ApplicationInfo(title=" + title.toString() + ")";
}
public static void dumpApplicationInfoList(String tag, String label,
ArrayList<ApplicationInfo> list) {
Log.d(tag, label + " size=" + list.size());
for (ApplicationInfo info: list) {
Log.d(tag, " title=\"" + info.title + "\" iconBitmap="
+ info.iconBitmap + " firstInstallTime="
+ info.firstInstallTime);
}
}
public ShortcutInfo makeShortcut() {
return new ShortcutInfo(this);
}
}
剩下的都是类似的,继承ItemInfo,再根据具体的需求添加属性和方法。
FolderInfo.item
class FolderInfo extends ItemInfo {
/**
* Whether this folder has been opened
*/
boolean opened;
/**
* The apps and shortcuts
*/
ArrayList<ShortcutInfo> contents = new ArrayList<ShortcutInfo>();
ArrayList<FolderListener> listeners = new ArrayList<FolderListener>();
FolderInfo() {
itemType = LauncherSettings.Favorites.ITEM_TYPE_FOLDER;
}
/**
* Add an app or shortcut
*
* @param item
*/
public void add(ShortcutInfo item) {
contents.add(item);
for (int i = 0; i < listeners.size(); i++) {
listeners.get(i).onAdd(item);
}
itemsChanged();
}
/**
* Remove an app or shortcut. Does not change the DB.
*
* @param item
*/
public void remove(ShortcutInfo item) {
contents.remove(item);
for (int i = 0; i < listeners.size(); i++) {
listeners.get(i).onRemove(item);
}
itemsChanged();
}
public void setTitle(CharSequence title) {
this.title = title;
for (int i = 0; i < listeners.size(); i++) {
listeners.get(i).onTitleChanged(title);
}
}
@Override
void onAddToDatabase(ContentValues values) {
super.onAddToDatabase(values);
values.put(LauncherSettings.Favorites.TITLE, title.toString());
}
void addListener(FolderListener listener) {
listeners.add(listener);
}
void removeListener(FolderListener listener) {
if (listeners.contains(listener)) {
listeners.remove(listener);
}
}
void itemsChanged() {
for (int i = 0; i < listeners.size(); i++) {
listeners.get(i).onItemsChanged();
}
}
@Override
void unbind() {
super.unbind();
listeners.clear();
}
interface FolderListener {
public void onAdd(ShortcutInfo item);
public void onRemove(ShortcutInfo item);
public void onTitleChanged(CharSequence title);
public void onItemsChanged();
}
}
LauncherAppWidgetInfo.java
class LauncherAppWidgetInfo extends ItemInfo {
/**
* Indicates that the widget hasn't been instantiated yet.
*/
static final int NO_ID = -1;
/**
* Identifier for this widget when talking with
* {@link android.appwidget.AppWidgetManager} for updates.
*/
int appWidgetId = NO_ID;
ComponentName providerName;
// TODO: Are these necessary here?
int minWidth = -1;
int minHeight = -1;
private boolean mHasNotifiedInitialWidgetSizeChanged;
/**
* View that holds this widget after it's been created. This view isn't created
* until Launcher knows it's needed.
*/
AppWidgetHostView hostView = null;
LauncherAppWidgetInfo(int appWidgetId, ComponentName providerName) {
itemType = LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET;
this.appWidgetId = appWidgetId;
this.providerName = providerName;
// Since the widget isn't instantiated yet, we don't know these values. Set them to -1
// to indicate that they should be calculated based on the layout and minWidth/minHeight
spanX = -1;
spanY = -1;
}
@Override
void onAddToDatabase(ContentValues values) {
super.onAddToDatabase(values);
values.put(LauncherSettings.Favorites.APPWIDGET_ID, appWidgetId);
}
/**
* When we bind the widget, we should notify the widget that the size has changed if we have not
* done so already (only really for default workspace widgets).
*/
void onBindAppWidget(Launcher launcher) {
if (!mHasNotifiedInitialWidgetSizeChanged) {
notifyWidgetSizeChanged(launcher);
}
}
/**
* Trigger an update callback to the widget to notify it that its size has changed.
*/
void notifyWidgetSizeChanged(Launcher launcher) {
AppWidgetResizeFrame.updateWidgetSizeRanges(hostView, launcher, spanX, spanY);
mHasNotifiedInitialWidgetSizeChanged = true;
}
@Override
public String toString() {
return "AppWidget(id=" + Integer.toString(appWidgetId) + ")";
}
@Override
void unbind() {
super.unbind();
hostView = null;
}
}
PendingAddInfo,PendingAddShortcutInfo,PendingAddWidgetInfo
class PendingAddItemInfo extends ItemInfo {
/**
* The component that will be created.
*/
ComponentName componentName;
}
class PendingAddShortcutInfo extends PendingAddItemInfo {
ActivityInfo shortcutActivityInfo;
public PendingAddShortcutInfo(ActivityInfo activityInfo) {
shortcutActivityInfo = activityInfo;
}
@Override
public String toString() {
return "Shortcut: " + shortcutActivityInfo.packageName;
}
}
class PendingAddWidgetInfo extends PendingAddItemInfo {
int minWidth;
int minHeight;
int minResizeWidth;
int minResizeHeight;
int previewImage;
int icon;
AppWidgetProviderInfo info;
AppWidgetHostView boundWidget;
Bundle bindOptions = null;
// Any configuration data that we want to pass to a configuration activity when
// starting up a widget
String mimeType;
Parcelable configurationData;
public PendingAddWidgetInfo(AppWidgetProviderInfo i, String dataMimeType, Parcelable data) {
itemType = LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET;
this.info = i;
componentName = i.provider;
minWidth = i.minWidth;
minHeight = i.minHeight;
minResizeWidth = i.minResizeWidth;
minResizeHeight = i.minResizeHeight;
previewImage = i.previewImage;
icon = i.icon;
if (dataMimeType != null && data != null) {
mimeType = dataMimeType;
configurationData = data;
}
}
// Copy constructor
public PendingAddWidgetInfo(PendingAddWidgetInfo copy) {
minWidth = copy.minWidth;
minHeight = copy.minHeight;
minResizeWidth = copy.minResizeWidth;
minResizeHeight = copy.minResizeHeight;
previewImage = copy.previewImage;
icon = copy.icon;
info = copy.info;
boundWidget = copy.boundWidget;
mimeType = copy.mimeType;
configurationData = copy.configurationData;
componentName = copy.componentName;
itemType = copy.itemType;
spanX = copy.spanX;
spanY = copy.spanY;
minSpanX = copy.minSpanX;
minSpanY = copy.minSpanY;
bindOptions = copy.bindOptions == null ? null : (Bundle) copy.bindOptions.clone();
}
@Override
public String toString() {
return "Widget: " + componentName.toShortString();
}
}