您的位置:首页 > 移动开发 > Android开发

手把手教你定制android桌面

2012-08-03 14:57 375 查看
launcher,也就是android的桌面应用程序。下图是android2.3的launcher应用程序:

接下来我们要开发一个自己的launcher,使其替代系统的默认launcher。

怎样使我们的应用程序成为一个launcher?

下面我们就新建一个叫做MyHome的工程,具体步骤略。创建完工程后整个目录结构如下图:

现在我们的AndroidManifest.xml文件这样的:

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

<manifest xmlns:android="http://schemas.android.com/apk/res/android"

package="org.bangchui.myhome"

android:versionCode="1"

android:versionName="1.0">

<applicationandroid:icon="@drawable/icon"android:label="@string/app_name">

<activityandroid:name=".MyHome"

android:label="@string/app_name">

<intent-filter>

<actionandroid:name="android.intent.action.MAIN" />

<categoryandroid:name="android.intent.category.LAUNCHER" />

</intent-filter>

</activity>

</application>

</manifest>

请注意<intent-filter>

</intent-filter>里面的内容。

下面我们在其中添加上以下两行:

?

1

2

<category android:name="android.intent.category.HOME" />

<category android:name="android.intent.category.DEFAULT" />

此时AndroidManifest.xml文件是这样:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

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

<manifest xmlns:android="http://schemas.android.com/apk/res/android"

package="org.bangchui.myhome"

android:versionCode="1"

android:versionName="1.0">

<application android:icon="@drawable/icon" android:label="@string/app_name">

<activity android:name=".MyHome"

android:label="@string/app_name">

<intent-filter>

<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />

<category android:name="android.intent.category.HOME" />

<category android:name="android.intent.category.DEFAULT" />

</intent-filter>

</activity>

</application>

</manifest>

此时运行程序,我们看不到任何特别之处。当按下home键时(模拟器上按下home会调出桌面应用),程序如图:

我们看到了,我们开发的Myhome跟Launcher出现在了一起。

重启模拟器,我们看到我们自己的程序已经可以作为home来运行了。

ok。 第一步完成了:把我们的应用程序作为home。

总结一下:要把我们的应用程序作为home,只需要在AndroidManifest.xml中添加:

<category android:name="android.intent.category.HOME" />

<category android:name="android.intent.category.DEFAULT"/>

android手把手教你开发launcher (二)

第二课:列出安装的应用程序

预备知识: GridView的使用 \ 改写BaseAdapter



列出已经安装的应用程序是作为launcher比不可少的功能。下面我们就讲解怎样将应用程序列出来。程序运行后的样子如下:

一. 修改main.xml,在其中添加一个GridView用来显示应用程序列表。

修改后如下:

?

1

2

3

4

5

6

7

8

9

10

11

12

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

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

android:orientation="vertical" android:layout_width="fill_parent"

android:layout_height="fill_parent">

<GridView android:layout_width="match_parent"

android:id="@+id/apps_list"

android:numColumns="4"

android:layout_height="wrap_content">

</GridView>

</LinearLayout>

二 . 通过PackageManager的api 查询已经安装的apk

我们写一个叫做loadApps的方法将活得的应用程序列表放到private List<ResolveInfo> mApps; 中,如下:

?

1

2

3

4

5

6

private void loadApps() {

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

mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);

mApps = getPackageManager().queryIntentActivities(mainIntent, 0);

}



三. 实现用于显示Gridview的Adapter,使其显示获得的应用程序列表

直接上代码:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

public class AppsAdapter extends BaseAdapter {

public AppsAdapter() {

}

public View getView(int position, View convertView, ViewGroup parent) {

ImageView i;

if (convertView == null) {

i = new ImageView(MyHome.this);

i.setScaleType(ImageView.ScaleType.FIT_CENTER);

i.setLayoutParams(new GridView.LayoutParams(50, 50));

} else {

i = (ImageView) convertView;

}

ResolveInfo info = mApps.get(position);

i.setImageDrawable(info.activityInfo.loadIcon(getPackageManager()));

return i;

}

public final int getCount() {

return mApps.size();

}

public final Object getItem(int position) {

return mApps.get(position);

}

public final long getItemId(int position) {

return position;

}

}

最后整个Activity的代码如下

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

package org.bangchui.myhome;

import java.util.List;

import android.app.Activity;

import android.content.Intent;

import android.content.pm.ResolveInfo;

import android.os.Bundle;

import android.view.View;

import android.view.ViewGroup;

import android.widget.BaseAdapter;

import android.widget.GridView;

import android.widget.ImageView;

public class MyHome extends Activity {

GridView mGrid;

/** Called when the activity is first created. */

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

loadApps();

setContentView(R.layout.main);

mGrid = (GridView) findViewById(R.id.apps_list);

mGrid.setAdapter(new AppsAdapter());

}

private List<ResolveInfo> mApps;

private void loadApps() {

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

mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);

mApps = getPackageManager().queryIntentActivities(mainIntent, 0);

}

public class AppsAdapter extends BaseAdapter {

public AppsAdapter() {

}

public View getView(int position, View convertView, ViewGroup parent) {

ImageView i;

if (convertView == null) {

i = new ImageView(MyHome.this);

i.setScaleType(ImageView.ScaleType.FIT_CENTER);

i.setLayoutParams(new GridView.LayoutParams(50, 50));

} else {

i = (ImageView) convertView;

}

ResolveInfo info = mApps.get(position);

i.setImageDrawable(info.activityInfo.loadIcon(getPackageManager()));

return i;

}

public final int getCount() {

return mApps.size();

}

public final Object getItem(int position) {

return mApps.get(position);

}

public final long getItemId(int position) {

return position;

}

}

}

第三课 启动安装的应用程序

1. 监听GridView的onItemClick事件

设置一个监听器是为了当gridView的某项被点击时,会有一个回调函数通知我们。

我们调用mGrid.setOnItemClickListener(listener); 设置一个监听器

mGrid.setOnItemClickListener(listener)中的listener是一个接口,其类型为:android.widget.AdapterView.OnItemClickListener,如下图所示:

下面我们new一个android.widget.AdapterView.OnItemClickListener类型的对象作为参数。我们直接使用eclipde的自动补全功能来完成OnItemClickListener的定义:

?

1

2

3

4

5

private OnItemClickListener listener = new OnItemClickListener() {

@Override

public void onItemClick(AdapterView<?> parent, View view, int position,long id) {

}

};

接口OnItemClickListener 中有一个方法叫做onItemClick,我们实现它即可。下面我对onItemClick的几个参数略作说明:

parent 略

view 被点击的view

position 被点击项的位置

id 被点击项的id

2.启动被点击应用的activity

一般来讲,我们根据position即可知道被点击的项目是哪一项了。现在我们根据被点击的项目,取出对应的应用程序数据(主要是其中的主activity),然后启动activity。用下面代码实现:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

@Override

public void onItemClick(AdapterView<?> parent, View view, int position,long id) {

ResolveInfo info = mApps.get(position);

//该应用的包名

String pkg = info.activityInfo.packageName;

//应用的主activity类

String cls = info.activityInfo.name;

ComponentName componet = new ComponentName(pkg, cls);

Intent i = new Intent();

i.setComponent(componet);

startActivity(i);

}

例如,我们点击计算器时,启动了计算器,如下图:

现在整个类代码如下:

复制代码

package org.bangchui.myhome;

import java.util.List;

import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.ResolveInfo;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.AdapterView.OnItemClickListener;

public class MyHome extends Activity {
private List<ResolveInfo> mApps;
GridView mGrid;
private OnItemClickListener listener = new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position,long id) {

ResolveInfo info = mApps.get(position);

//该应用的包名
String pkg = info.activityInfo.packageName;
//应用的主activity类
String cls = info.activityInfo.name;

ComponentName componet = new ComponentName(pkg, cls);

Intent i = new Intent();
i.setComponent(componet);
startActivity(i);
}

};

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

loadApps();
setContentView(R.layout.main);
mGrid = (GridView) findViewById(R.id.apps_list);
mGrid.setAdapter(new AppsAdapter());

mGrid.setOnItemClickListener(listener);
}

private void loadApps() {
Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);

mApps = getPackageManager().queryIntentActivities(mainIntent, 0);
}

public class AppsAdapter extends BaseAdapter {
public AppsAdapter() {
}

public View getView(int position, View convertView, ViewGroup parent) {

ImageView i;

if (convertView == null) {
i = new ImageView(MyHome.this);
i.setScaleType(ImageView.ScaleType.FIT_CENTER);
i.setLayoutParams(new GridView.LayoutParams(50, 50));
} else {
i = (ImageView) convertView;
}

ResolveInfo info = mApps.get(position);
i.setImageDrawable(info.activityInfo.loadIcon(getPackageManager()));

return i;
}

public final int getCount() {
return mApps.size();
}

public final Object getItem(int position) {
return mApps.get(position);
}

public final long getItemId(int position) {
return position;
}
}
}

我们在前面的课程中已经列出了安装的应用程序,并且点击后可以启动应用程序了!

下面我们来研究如何显示widget。

源代码: 附件出售:TestWidget.7z

我们要达到这样的效果:点击“add widget” 后弹出widget列表,之后选择一个widget后显示在界面上,如下:

第四课:显示widget

1. 获取widget信息



获取widget其实非常简单,我们只需要发送一个请求到系统,系统就会打开widget的列表,然后我们选择一个即可。代码如下:

?

1

2

3

4

5

6

7

void addWidget() {

int appWidgetId = mAppWidgetHost.allocateAppWidgetId();

Intent pickIntent = new Intent(AppWidgetManager.ACTION_APPWIDGET_PICK);

pickIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);

// start the pick activity

startActivityForResult(pickIntent, REQUEST_PICK_APPWIDGET);

}

2. 添加widget的view到layout中

当选择一个widget后会通过onActivityResult 通知到activity,widget的信息被包含在 Intent data中,详情看代码注释

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

@Override

protected void onActivityResult(int requestCode, int resultCode, Intent data) {

// The pattern used here is that a user PICKs a specific application,

// which, depending on the target, might need to CREATE the actual

// target.

// For example, the user would PICK_SHORTCUT for "Music playlist", and

// we

// launch over to the Music app to actually CREATE_SHORTCUT.

if (resultCode == RESULT_OK) {

switch (requestCode) {

case REQUEST_PICK_APPWIDGET:

addAppWidget(data);

break;

case REQUEST_CREATE_APPWIDGET:

completeAddAppWidget(data);

break;

}

}

}

void addAppWidget(Intent data) {

// TODO: catch bad widget exception when sent

int appWidgetId = data.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,

-1);

AppWidgetProviderInfo appWidget = mAppWidgetManager

.getAppWidgetInfo(appWidgetId);

//widget 包含设置信息不为空,则启动widget的设置界面

if (appWidget.configure != null) {

// Launch over to configure widget, if needed

Intent intent = new Intent(

AppWidgetManager.ACTION_APPWIDGET_CONFIGURE);

intent.setComponent(appWidget.configure);

intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);

startActivityForResultSafely(intent, REQUEST_CREATE_APPWIDGET);

} else {

// widget 包含设置信息为空,直接添加widget到layout中

// Otherwise just add it

onActivityResult(REQUEST_CREATE_APPWIDGET, Activity.RESULT_OK, data);

}

}

void startActivityForResultSafely(Intent intent, int requestCode) {

try {

startActivityForResult(intent, requestCode);

} catch (ActivityNotFoundException e) {

Toast.makeText(this, "activity_not_found", Toast.LENGTH_SHORT)

.show();

} catch (SecurityException e) {

Toast.makeText(this, "activity_not_found", Toast.LENGTH_SHORT)

.show();

}

}

/**

* 添加widget信息到layout中

* @param data 包含了widget的信息

*/

private void completeAddAppWidget(Intent data) {

Bundle extras = data.getExtras();

int appWidgetId = extras

.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, -1);

Log.d(TAG, "dumping extras content=" + extras.toString());

AppWidgetProviderInfo appWidgetInfo = mAppWidgetManager

.getAppWidgetInfo(appWidgetId);

// Perform actual inflation because we're live

synchronized (mLock) {

//获取显示widget的view

mHostView = mAppWidgetHost.createView(this, appWidgetId,

appWidgetInfo);

mHostView.setAppWidget(appWidgetId, appWidgetInfo);

//将获取的view添加早layout中

LayoutParams lp = new LinearLayout.LayoutParams(

appWidgetInfo.minWidth, appWidgetInfo.minHeight);

mainLayout.addView(mHostView, lp);

mHostView.requestLayout();

}

}

显示壁纸也是launcher必不可少的功能,下面我们看看如何让我们开发的launcher来显示壁纸。

新建一个叫做ShowWallpaper的工程,具体步骤略。

一. 显示壁纸

要在我们的activity里显示一个壁纸非常简单(包括动态壁纸也如此),我们只需要定义一个theme使其继承自android:Theme.Wallpaper,然后在activity中使用这个theme就ok了。

在res/valuse下面增加一个xml文件,其名称为styles.xml ,内容如下:

?

1

2

3

4

5

6

<resources>

<style name="Theme" parent="android:Theme.Wallpaper">

<!-- windowNoTitle设置为true,去掉标题栏 -->

<item name="android:windowNoTitle">true</item>

</style>

</resources>

此时整个工程的结果如下:

下面在AndroidManifest.xml中使用这个theme,如下图所示:

xml代码如下

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

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

<manifest xmlns:android="http://schemas.android.com/apk/res/android"

package="com.test"

android:versionCode="1"

android:versionName="1.0">

<application android:icon="@drawable/icon" android:label="@string/app_name">

<activity android:name=".ShowWallpaper"

android:theme="@style/Theme"

android:label="@string/app_name">

<intent-filter>

<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />

</intent-filter>

</activity>

</application>

</manifest>

好了,运行程序,可以看到壁纸的显示效果了:(显示的是预设置的动态壁纸:星系)

设置壁纸

用代码设置壁纸也是非常地简单的事,我们只需要向系统发送一个“设置请求”就足够了,其它的事情系统处理。

用下面代码表示:

?

1

2

3

4

5

6

7

public void onSetWallpaper(View view) {

//生成一个设置壁纸的请求

final Intent pickWallpaper = new Intent(Intent.ACTION_SET_WALLPAPER);

Intent chooser = Intent.createChooser(pickWallpaper,"chooser_wallpaper");

//发送设置壁纸的请求

startActivity(chooser);

}

为了调用上面这段代码,我们在xml中添加一个button,并设置回调函数,如下图:

最后运行代码,步骤如下图所示:

设置壁纸后:
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: