Launcher的AndroidManifest.xml文件有很多特殊性,分析一下就会理解整个程序的大概结构。
代码如下:
<manifestxmlns:android="http://schemas.android.com/apk/res/android"
package="net.sunniwell.launcher"
android:versionCode="1"android:versionName="1.0.1">
关于自定义权限,这是很好的例子,其他apk程序要想使用Launcher的功能必须添加这些权限,而这些权限都是在这里声明的。
这个是安装快捷方式的权限定义:
<permission
android:name="com.android.launcher.permission.INSTALL_SHORTCUT"
android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
android:protectionLevel="normal"
android:label="@string/permlab_install_shortcut"
android:description="@string/permdesc_install_shortcut"/>
这个是卸载快捷方式的权限定义:
<permission
android:name="com.android.launcher.permission.UNINSTALL_SHORTCUT"
android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
android:protectionLevel="normal"
android:label="@string/permlab_uninstall_shortcut"
android:description="@string/permdesc_uninstall_shortcut"/>
这个是读取launcher.db内容的权限定义:
<permission
android:name="net.sunniwell.launcher.permission.READ_SETTINGS"
android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
android:protectionLevel="normal"
android:label="@string/permlab_read_settings"
android:description="@string/permdesc_read_settings"/>
这个是修改和删除launcher.db内容的权限定义:
<permission
android:name="net.sunniwell.launcher.permission.WRITE_SETTINGS"
android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
android:protectionLevel="normal"
android:label="@string/permlab_write_settings"
android:description="@string/permdesc_write_settings"/>
这些是Launcher的权限声明,通过这些就能看出launcher的大概功能了:
打电话权限:
<uses-permissionandroid:name="android.permission.CALL_PHONE"/>
使用状态栏权限:
<uses-permissionandroid:name="android.permission.EXPAND_STATUS_BAR"/>
获取当前或最近运行的任务的信息的权限:
<uses-permissionandroid:name="android.permission.GET_TASKS"/>
读取通信录权限:
<uses-permissionandroid:name="android.permission.READ_CONTACTS"/>
设置壁纸权限:
<uses-permissionandroid:name="android.permission.SET_WALLPAPER"/>
允许程序设置壁纸hits的权限:
<uses-permissionandroid:name="android.permission.SET_WALLPAPER_HINTS"/>
使用震动功能权限:
<uses-permissionandroid:name="android.permission.VIBRATE"/>
修改删除launcher.db内容权限:
<uses-permissionandroid:name="android.permission.WRITE_SETTINGS"/>
绑定widget权限:
<uses-permissionandroid:name="android.permission.BIND_APPWIDGET"/>
读取launcher.db内容权限:
<uses-permissionandroid:name="net.sunniwell.launcher.permission.READ_SETTINGS"/>
修改删除launcher.db内容权限:
<uses-permissionandroid:name="net.sunniwell.launcher.permission.WRITE_SETTINGS"/>
读写外部存储设备权限:
<uses-permissionandroid:name="android.permission.WRITE_EXTERNAL_STORAGE">uses-permission>
<application
android:name="LauncherApplication"
activity应该运行的进程的名字:
android:process="android.process.acore"
android:label="@string/application_name"
android:icon="@drawable/swicon">
<activity
android:name="Launcher"
是否
android:launchMode="singleTask"
android:clearTaskOnLaunch="true"
这个activity是否在被杀死或者重启后能恢复原来的状态:
android:stateNotNeeded="true"
android:theme="@style/Theme"
android:screenOrientation="landscape"
android:windowSoftInputMode="stateUnspecified|adjustPan">
<intent-filter>
<actionandroid:name="android.intent.action.MAIN"/>
<categoryandroid:name="android.intent.category.LAUNCHER"/>
桌面应用的标记:
<categoryandroid:name="android.intent.category.HOME"/>
<categoryandroid:name="android.intent.category.DEFAULT"/>
自动化测试工具Monkey的标记,待研究…
<categoryandroid:name="android.intent.category.MONKEY"/>
intent-filter>
activity>
选择壁纸的activity:
<activity
android:name="WallpaperChooser"
android:label="@string/pick_wallpaper"
android:icon="@drawable/ic_launcher_gallery">
设置壁纸的intent-filter:
<intent-filter>
<actionandroid:name="android.intent.action.SET_WALLPAPER"/>
<categoryandroid:name="android.intent.category.DEFAULT"/>
intent-filter>
搜索的activity:
activity>
<meta-data
android:name="android.app.default_searchable"
android:value="*"/>
安装快捷方式的广播接收器:
<receiver
android:name=".InstallShortcutReceiver"
android:permission="com.android.launcher.permission.INSTALL_SHORTCUT">
<intent-filter>
<actionandroid:name="com.android.launcher.action.INSTALL_SHORTCUT"/>
intent-filter>
receiver>
卸载快捷方式的广播接收器:
<receiver
android:name=".UninstallShortcutReceiver"
android:permission="com.android.launcher.permission.UNINSTALL_SHORTCUT">
<intent-filter>
<actionandroid:name="com.android.launcher.action.UNINSTALL_SHORTCUT"/>
intent-filter>
receiver>
声明ContentProvider,用于对launcher.db操作:
<provider
android:name="SWLauncherProvider"
android:authorities="net.sunniwell.launcher.settings"
android:writePermission="net.sunniwell.launcher.permission.WRITE_SETTINGS"
android:readPermission="net.sunniwell.launcher.permission.READ_SETTINGS"/>
application>
<uses-sdkandroid:minSdkVersion="4"/>
manifest>
说明:
1.
标签头部还应声明:
android:sharedUserId="android.uid.shared",作用是获得系统权限,但是这样的程序属性只能在build整个系统时放进去(就是系统软件)才起作用,手动安装是没有权限的。
AddAdapter: 维护了 live fold , widget , shortcut , wallpaper 4 个 ListItem , 长按桌面会显示该列表
AllAppsGridView :显示 APP 的网格
ApplicationInfo :一个可启动的应用
ApplicationsAdapter : gridview 的 adapter
BubbleTextView: 一个定制了的 textview
CellLayout: 屏幕网格化
DeleteZone : UI 的一部分
DragController , dragscroller, dragsource, droptarget: 支持拖拽操作
DragLayer :内部支持拖拽的 viewgroup
FastBitmapDrawable :工具
Folder : Icons 的集合
FolderIcon: 出现在 workspace 的 icon 代表了一个 folder
FolderInfo: ItemInfo 子类
HandleView :一个 imageview 。
InstallShortcutReceiver , UninstallShortcutReceiver :一个 broadcastrecier
ItemInfo: 代表 Launcher 中一个 Item (例如 folder )
Launcher: Launcher 程序的主窗口
LauncherApplication :在 VM 中设置参数
LauncherAppWidgetHost , LauncherAppWidgetHostView ,: Widget 相关
LauncherModel : MVC 中的 M
LauncherProvider :一个 contentprovider ,为 Launcher 存储信息
LauncherSettings: 设置相关的工具
LiveFolder , LiveFolderAdapter , LiveFolderIcon , LiveFolderInfo : livefolder 相关
Search : 搜索
UserFolder , UserFolderInfo :文件夹包含 applications ,shortcuts
Utilities: 小工具
WallpaperChooser :选择 wallpaper 的 activity
Workspace: 屏幕上的一块区域
widget : 代表启动的 widget 实例,例如搜索
总结
1) Launcher中实现了MVC模式(M:launchermode , V:draglayer ,C: launcher),以此为主线,可以得到 Launcher对各个组件管理的细节(如drag的实现)。
六 Launcher 起动过程
Android系统在启动时会安装应用程序,这些应用程序安装好之后,还需要有一个Home应用程序来负责把它们在桌面上展示出来,在Android系统中,这个默认的Home应用程序就是Launcher了,我将详细分析Launcher应用程序的启动过程。
Android系统的Home应用程序Launcher是由ActivityManagerService启动的,而ActivityManagerService和PackageManagerService一样,都是在开机时由SystemServer组件启动的,SystemServer组件首先是启动ePackageManagerServic,由它来负责安装系统的应用程序,系统中的应用程序安装好了以后,SystemServer组件接下来就要通过ActivityManagerService来启动Home应用程序Launcher了,Launcher在启动的时候便会通过PackageManagerServic把系统中已经安装好的应用程序以快捷图标的形式展示在桌面上,这样用户就可以使用这些应用程序了。
下面详细分析每一个步骤。
Step 1. SystemServer.main
这个函数定义在frameworks/base/services/java/com/android/server/SystemServer.java文件中:
view plain copy to clipboard print ?
- public class SystemServer
- {
- ......
-
- native public static void init1(String[] args);
-
- ......
-
- public static void main(String[] args) {
- ......
-
- init1(args);
-
- ......
- }
-
- ......
- }
public class SystemServer { ...... native public static void init1(String[] args); ...... public static void main(String[] args) { ...... init1(args); ...... } ...... } SystemServer组件是由Zygote进程负责启动的,启动的时候就会调用它的main函数,这个函数主要调用了JNI方法init1来做一些系统初始化的工作。
Step 2. SystemServer.init1
这个函数是一个JNI方法,实现在 frameworks/base/services/jni/com_android_server_SystemServer.cpp文件中:
view plain copy to clipboard print ?
- namespace android {
-
- extern "C" int system_init();
-
- static void android_server_SystemServer_init1(JNIEnv* env, jobject clazz)
- {
- system_init();
- }
-
-
-
-
- static JNINativeMethod gMethods[] = {
-
- { "init1", "([Ljava/lang/String;)V", (void*) android_server_SystemServer_init1 },
- };
-
- int register_android_server_SystemServer(JNIEnv* env)
- {
- return jniRegisterNativeMethods(env, "com/android/server/SystemServer",
- gMethods, NELEM(gMethods));
- }
-
- };
namespace android { extern "C" int system_init(); static void android_server_SystemServer_init1(JNIEnv* env, jobject clazz) { system_init(); } /* * JNI registration. */ static JNINativeMethod gMethods[] = { /* name, signature, funcPtr */ { "init1", "([Ljava/lang/String;)V", (void*) android_server_SystemServer_init1 }, }; int register_android_server_SystemServer(JNIEnv* env) { return jniRegisterNativeMethods(env, "com/android/server/SystemServer", gMethods, NELEM(gMethods)); } }; // namespace android 这个函数很简单,只是调用了system_init函数来进一步执行操作。
Step 3. libsystem_server.system_init
函数system_init实现在libsystem_server库中,源代码位于frameworks/base/cmds/system_server/library/system_init.cpp文件中:
view plain copy to clipboard print ?
- extern "C" status_t system_init()
- {
- LOGI("Entered system_init()");
-
- sp proc(ProcessState::self());
-
- sp sm = defaultServiceManager();
- LOGI("ServiceManager: %p\n", sm.get());
-
- sp grim = new GrimReaper();
- sm->asBinder()->linkToDeath(grim, grim.get(), 0);
-
- char propBuf[PROPERTY_VALUE_MAX];
- property_get("system_init.startsurfaceflinger", propBuf, "1");
- if (strcmp(propBuf, "1") == 0) {
-
- SurfaceFlinger::instantiate();
- }
-
-
- SensorService::instantiate();
-
-
-
- if (!proc->supportsProcesses()) {
-
-
- AudioFlinger::instantiate();
-
-
- MediaPlayerService::instantiate();
-
-
- CameraService::instantiate();
-
-
- AudioPolicyService::instantiate();
- }
-
-
-
-
-
-
-
- LOGI("System server: starting Android runtime.\n");
-
- AndroidRuntime* runtime = AndroidRuntime::getRuntime();
-
- LOGI("System server: starting Android services.\n");
- runtime->callStatic("com/android/server/SystemServer", "init2");
-
-
-
-
- if (proc->supportsProcesses()) {
- LOGI("System server: entering thread pool.\n");
- ProcessState::self()->startThreadPool();
- IPCThreadState::self()->joinThreadPool();
- LOGI("System server: exiting thread pool.\n");
- }
-
- return NO_ERROR;
- }
extern "C" status_t system_init() { LOGI("Entered system_init()"); sp
proc(ProcessState::self()); sp sm = defaultServiceManager(); LOGI("ServiceManager: %p\n", sm.get()); sp grim = new GrimReaper(); sm->asBinder()->linkToDeath(grim, grim.get(), 0); char propBuf[PROPERTY_VALUE_MAX]; property_get("system_init.startsurfaceflinger", propBuf, "1"); if (strcmp(propBuf, "1") == 0) { // Start the SurfaceFlinger SurfaceFlinger::instantiate(); } // Start the sensor service SensorService::instantiate(); // On the simulator, audioflinger et al don't get started the // same way as on the device, and we need to start them here if (!proc->supportsProcesses()) { // Start the AudioFlinger AudioFlinger::instantiate(); // Start the media playback service MediaPlayerService::instantiate(); // Start the camera service CameraService::instantiate(); // Start the audio policy service AudioPolicyService::instantiate(); } // And now start the Android runtime. We have to do this bit // of nastiness because the Android runtime initialization requires // some of the core system services to already be started. // All other servers should just start the Android runtime at // the beginning of their processes's main(), before calling // the init function. LOGI("System server: starting Android runtime.\n"); AndroidRuntime* runtime = AndroidRuntime::getRuntime(); LOGI("System server: starting Android services.\n"); runtime->callStatic("com/android/server/SystemServer", "init2"); // If running in our own process, just go into the thread // pool. Otherwise, call the initialization finished // func to let this process continue its initilization. if (proc->supportsProcesses()) { LOGI("System server: entering thread pool.\n"); ProcessState::self()->startThreadPool(); IPCThreadState::self()->joinThreadPool(); LOGI("System server: exiting thread pool.\n"); } return NO_ERROR; } 这个函数首先会初始化SurfaceFlinger、SensorService、AudioFlinger、MediaPlayerService、CameraService和AudioPolicyService这几个服务,然后就通过系统全局唯一的AndroidRuntime实例变量runtime的callStatic来调用SystemServer的init2函数了。关于这个AndroidRuntime实例变量runtime的相关资料,可能参考前面一篇文章
Android应用程序进程启动过程的源代码分析一文。
Step 4. AndroidRuntime.callStatic
这个函数定义在frameworks/base/core/jni/AndroidRuntime.cpp文件中:
view plain copy to clipboard print ?
-
-
-
- status_t AndroidRuntime::callStatic(const char* className, const char* methodName)
- {
- JNIEnv* env;
- jclass clazz;
- jmethodID methodId;
-
- env = getJNIEnv();
- if (env == NULL)
- return UNKNOWN_ERROR;
-
- clazz = findClass(env, className);
- if (clazz == NULL) {
- LOGE("ERROR: could not find class '%s'\n", className);
- return UNKNOWN_ERROR;
- }
- methodId = env->GetStaticMethodID(clazz, methodName, "()V");
- if (methodId == NULL) {
- LOGE("ERROR: could not find method %s.%s\n", className, methodName);
- return UNKNOWN_ERROR;
- }
-
- env->CallStaticVoidMethod(clazz, methodId);
-
- return NO_ERROR;
- }
/* * Call a static Java Programming Language function that takes no arguments and returns void. */ status_t AndroidRuntime::callStatic(const char* className, const char* methodName) { JNIEnv* env; jclass clazz; jmethodID methodId; env = getJNIEnv(); if (env == NULL) return UNKNOWN_ERROR; clazz = findClass(env, className); if (clazz == NULL) { LOGE("ERROR: could not find class '%s'\n", className); return UNKNOWN_ERROR; } methodId = env->GetStaticMethodID(clazz, methodName, "()V"); if (methodId == NULL) { LOGE("ERROR: could not find method %s.%s\n", className, methodName); return UNKNOWN_ERROR; } env->CallStaticVoidMethod(clazz, methodId); return NO_ERROR; } 这个函数调用由参数className指定的java类的静态成员函数,这个静态成员函数是由参数methodName指定的。上面传进来的参数className的值为"com/android/server/SystemServer",而参数methodName的值为"init2",因此,接下来就会调用SystemServer类的init2函数了。
Step 5. SystemServer.init2
这个函数定义在frameworks/base/services/java/com/android/server/SystemServer.java文件中:
view plain copy to clipboard print ?
- public class SystemServer
- {
- ......
-
- public static final void init2() {
- Slog.i(TAG, "Entered the Android system server!");
- Thread thr = new ServerThread();
- thr.setName("android.server.ServerThread");
- thr.start();
- }
- }
public class SystemServer { ...... public static final void init2() { Slog.i(TAG, "Entered the Android system server!"); Thread thr = new ServerThread(); thr.setName("android.server.ServerThread"); thr.start(); } } 这个函数创建了一个ServerThread线程,PackageManagerService服务就是这个线程中启动的了。这里调用了ServerThread实例thr的start函数之后,下面就会执行这个实例的run函数了。
Step 6. ServerThread.run
这个函数定义在frameworks/base/services/java/com/android/server/SystemServer.java文件中:
view plain copy to clipboard print ?
- class ServerThread extends Thread {
- ......
-
- @Override
- public void run() {
- ......
-
- IPackageManager pm = null;
-
- ......
-
-
- try {
- ......
-
- Slog.i(TAG, "Package Manager");
- pm = PackageManagerService.main(context,
- factoryTest != SystemServer.FACTORY_TEST_OFF);
-
- ......
- } catch (RuntimeException e) {
- Slog.e("System", "Failure starting core service", e);
- }
-
- ......
- }
-
- ......
- }
class ServerThread extends Thread { ...... @Override public void run() { ...... IPackageManager pm = null; ...... // Critical services... try { ...... Slog.i(TAG, "Package Manager"); pm = PackageManagerService.main(context, factoryTest != SystemServer.FACTORY_TEST_OFF); ...... } catch (RuntimeException e) { Slog.e("System", "Failure starting core service", e); } ...... } ...... } 这个函数除了启动PackageManagerService服务之外,还启动了其它很多的服务,例如在前面学习Activity和Service的几篇文章中经常看到的ActivityManagerService服务,有兴趣的读者可以自己研究一下。
Step 7. ActivityManagerService.main
这个函数定义在frameworks/base/services/java/com/android/server/am/ActivityManagerServcie.java文件中:
view plain copy to clipboard print ?
- public final class ActivityManagerService extends ActivityManagerNative
- implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
- ......
-
- public static final Context main(int factoryTest) {
- AThread thr = new AThread();
- thr.start();
-
- synchronized (thr) {
- while (thr.mService == null) {
- try {
- thr.wait();
- } catch (InterruptedException e) {
- }
- }
- }
-
- ActivityManagerService m = thr.mService;
- mSelf = m;
- ActivityThread at = ActivityThread.systemMain();
- mSystemThread = at;
- Context context = at.getSystemContext();
- m.mContext = context;
- m.mFactoryTest = factoryTest;
- m.mMainStack = new ActivityStack(m, context, true);
-
- m.mBatteryStatsService.publish(context);
- m.mUsageStatsService.publish(context);
-
- synchronized (thr) {
- thr.mReady = true;
- thr.notifyAll();
- }
-
- m.startRunning(null, null, null, null);
-
- return context;
- }
-
- ......
- }
public final class ActivityManagerService extends ActivityManagerNative implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback { ...... public static final Context main(int factoryTest) { AThread thr = new AThread(); thr.start(); synchronized (thr) { while (thr.mService == null) { try { thr.wait(); } catch (InterruptedException e) { } } } ActivityManagerService m = thr.mService; mSelf = m; ActivityThread at = ActivityThread.systemMain(); mSystemThread = at; Context context = at.getSystemContext(); m.mContext = context; m.mFactoryTest = factoryTest; m.mMainStack = new ActivityStack(m, context, true); m.mBatteryStatsService.publish(context); m.mUsageStatsService.publish(context); synchronized (thr) { thr.mReady = true; thr.notifyAll(); } m.startRunning(null, null, null, null); return context; } ...... } 这个函数首先通过AThread线程对象来内部创建了一个ActivityManagerService实例,然后将这个实例保存其成员变量mService中,接着又把这个ActivityManagerService实例保存在ActivityManagerService类的静态成员变量mSelf中,最后初始化其它成员变量,就结束了。
Step 8. PackageManagerService.main
这个函数定义在frameworks/base/services/java/com/android/server/PackageManagerService.java文件中:
view plain copy to clipboard print ?
- class PackageManagerService extends IPackageManager.Stub {
- ......
-
- public static final IPackageManager main(Context context, boolean factoryTest) {
- PackageManagerService m = new PackageManagerService(context, factoryTest);
- ServiceManager.addService("package", m);
- return m;
- }
-
- ......
- }
class PackageManagerService extends IPackageManager.Stub { ...... public static final IPackageManager main(Context context, boolean factoryTest) { PackageManagerService m = new PackageManagerService(context, factoryTest); ServiceManager.addService("package", m); return m; } ...... } 这个函数创建了一个PackageManagerService服务实例,然后把这个服务添加到ServiceManager中去,ServiceManager是Android系统Binder进程间通信机制的守护进程,负责管理系统中的Binder对象,在创建这个PackageManagerService服务实例时,会在PackageManagerService类的构造函数中开始执行安装应用程序的过程:
view plain copy to clipboard print ?
- class PackageManagerService extends IPackageManager.Stub {
- ......
-
- public PackageManagerService(Context context, boolean factoryTest) {
- ......
-
- synchronized (mInstallLock) {
- synchronized (mPackages) {
- ......
-
- File dataDir = Environment.getDataDirectory();
- mAppDataDir = new File(dataDir, "data");
- mSecureAppDataDir = new File(dataDir, "secure/data");
- mDrmAppPrivateInstallDir = new File(dataDir, "app-private");
-
- ......
-
- mFrameworkDir = new File(Environment.getRootDirectory(), "framework");
- mDalvikCacheDir = new File(dataDir, "dalvik-cache");
-
- ......
-
-
- mFrameworkInstallObserver = new AppDirObserver(
- mFrameworkDir.getPath(), OBSERVER_EVENTS, true);
- mFrameworkInstallObserver.startWatching();
- scanDirLI(mFrameworkDir, PackageParser.PARSE_IS_SYSTEM
- | PackageParser.PARSE_IS_SYSTEM_DIR,
- scanMode | SCAN_NO_DEX, 0);
-
-
- mSystemAppDir = new File(Environment.getRootDirectory(), "app");
- mSystemInstallObserver = new AppDirObserver(
- mSystemAppDir.getPath(), OBSERVER_EVENTS, true);
- mSystemInstallObserver.startWatching();
- scanDirLI(mSystemAppDir, PackageParser.PARSE_IS_SYSTEM
- | PackageParser.PARSE_IS_SYSTEM_DIR, scanMode, 0);
-
-
- mVendorAppDir = new File("/vendor/app");
- mVendorInstallObserver = new AppDirObserver(
- mVendorAppDir.getPath(), OBSERVER_EVENTS, true);
- mVendorInstallObserver.startWatching();
- scanDirLI(mVendorAppDir, PackageParser.PARSE_IS_SYSTEM
- | PackageParser.PARSE_IS_SYSTEM_DIR, scanMode, 0);
-
-
- mAppInstallObserver = new AppDirObserver(
- mAppInstallDir.getPath(), OBSERVER_EVENTS, false);
- mAppInstallObserver.startWatching();
- scanDirLI(mAppInstallDir, 0, scanMode, 0);
-
- mDrmAppInstallObserver = new AppDirObserver(
- mDrmAppPrivateInstallDir.getPath(), OBSERVER_EVENTS, false);
- mDrmAppInstallObserver.startWatching();
- scanDirLI(mDrmAppPrivateInstallDir, PackageParser.PARSE_FORWARD_LOCK,
- scanMode, 0);
-
- ......
- }
- }
- }
-
- ......
- }
class PackageManagerService extends IPackageManager.Stub { ...... public PackageManagerService(Context context, boolean factoryTest) { ...... synchronized (mInstallLock) { synchronized (mPackages) { ...... File dataDir = Environment.getDataDirectory(); mAppDataDir = new File(dataDir, "data"); mSecureAppDataDir = new File(dataDir, "secure/data"); mDrmAppPrivateInstallDir = new File(dataDir, "app-private"); ...... mFrameworkDir = new File(Environment.getRootDirectory(), "framework"); mDalvikCacheDir = new File(dataDir, "dalvik-cache"); ...... // Find base frameworks (resource packages without code). mFrameworkInstallObserver = new AppDirObserver( mFrameworkDir.getPath(), OBSERVER_EVENTS, true); mFrameworkInstallObserver.startWatching(); scanDirLI(mFrameworkDir, PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR, scanMode | SCAN_NO_DEX, 0); // Collect all system packages. mSystemAppDir = new File(Environment.getRootDirectory(), "app"); mSystemInstallObserver = new AppDirObserver( mSystemAppDir.getPath(), OBSERVER_EVENTS, true); mSystemInstallObserver.startWatching(); scanDirLI(mSystemAppDir, PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR, scanMode, 0); // Collect all vendor packages. mVendorAppDir = new File("/vendor/app"); mVendorInstallObserver = new AppDirObserver( mVendorAppDir.getPath(), OBSERVER_EVENTS, true); mVendorInstallObserver.startWatching(); scanDirLI(mVendorAppDir, PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR, scanMode, 0); mAppInstallObserver = new AppDirObserver( mAppInstallDir.getPath(), OBSERVER_EVENTS, false); mAppInstallObserver.startWatching(); scanDirLI(mAppInstallDir, 0, scanMode, 0); mDrmAppInstallObserver = new AppDirObserver( mDrmAppPrivateInstallDir.getPath(), OBSERVER_EVENTS, false); mDrmAppInstallObserver.startWatching(); scanDirLI(mDrmAppPrivateInstallDir, PackageParser.PARSE_FORWARD_LOCK, scanMode, 0); ...... } } } ...... } 这里会调用scanDirLI函数来扫描移动设备上的下面这五个目录中的Apk文件:
/system/framework
/system/app
/vendor/app
/data/app
/data/app-private
Step 9. ActivityManagerService.setSystemProcess
这个函数定义在frameworks/base/services/java/com/android/server/am/ActivityManagerServcie.java文件中:
view plain copy to clipboard print ?
- public final class ActivityManagerService extends ActivityManagerNative
- implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
- ......
-
- public static void setSystemProcess() {
- try {
- ActivityManagerService m = mSelf;
-
- ServiceManager.addService("activity", m);
- ServiceManager.addService("meminfo", new MemBinder(m));
- if (MONITOR_CPU_USAGE) {
- ServiceManager.addService("cpuinfo", new CpuBinder(m));
- }
- ServiceManager.addService("permission", new PermissionController(m));
-
- ApplicationInfo info =
- mSelf.mContext.getPackageManager().getApplicationInfo(
- "android", STOCK_PM_FLAGS);
- mSystemThread.installSystemApplicationInfo(info);
-
- synchronized (mSelf) {
- ProcessRecord app = mSelf.newProcessRecordLocked(
- mSystemThread.getApplicationThread(), info,
- info.processName);
- app.persistent = true;
- app.pid = MY_PID;
- app.maxAdj = SYSTEM_ADJ;
- mSelf.mProcessNames.put(app.processName, app.info.uid, app);
- synchronized (mSelf.mPidsSelfLocked) {
- mSelf.mPidsSelfLocked.put(app.pid, app);
- }
- mSelf.updateLruProcessLocked(app, true, true);
- }
- } catch (PackageManager.NameNotFoundException e) {
- throw new RuntimeException(
- "Unable to find android system package", e);
- }
- }
- ......
- }
public final class ActivityManagerService extends ActivityManagerNative implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback { ...... public static void setSystemProcess() { try { ActivityManagerService m = mSelf; ServiceManager.addService("activity", m); ServiceManager.addService("meminfo", new MemBinder(m)); if (MONITOR_CPU_USAGE) { ServiceManager.addService("cpuinfo", new CpuBinder(m)); } ServiceManager.addService("permission", new PermissionController(m)); ApplicationInfo info = mSelf.mContext.getPackageManager().getApplicationInfo( "android", STOCK_PM_FLAGS); mSystemThread.installSystemApplicationInfo(info); synchronized (mSelf) { ProcessRecord app = mSelf.newProcessRecordLocked( mSystemThread.getApplicationThread(), info, info.processName); app.persistent = true; app.pid = MY_PID; app.maxAdj = SYSTEM_ADJ; mSelf.mProcessNames.put(app.processName, app.info.uid, app); synchronized (mSelf.mPidsSelfLocked) { mSelf.mPidsSelfLocked.put(app.pid, app); } mSelf.updateLruProcessLocked(app, true, true); } } catch (PackageManager.NameNotFoundException e) { throw new RuntimeException( "Unable to find android system package", e); } } ...... } 这个函数首先是将这个ActivityManagerService实例添加到ServiceManager中去托管,这样其它地方就可以通过ServiceManager.getService接口来访问这个全局唯一的ActivityManagerService实例了,接着又通过调用mSystemThread.installSystemApplicationInfo函数来把应用程序框架层下面的android包加载进来 ,这里的mSystemThread是一个ActivityThread类型的实例变量,它是在上面的Step 7中创建的,后面就是一些其它的初始化工作了。
Step 10. ActivityManagerService.systemReady
这个函数是在上面的Step 6中的ServerThread.run函数在将系统中的一系列服务都初始化完毕之后才调用的,它定义在frameworks/base/services/java/com/android/server/am/ActivityManagerServcie.java文件中:
view plain copy to clipboard print ?
- public final class ActivityManagerService extends ActivityManagerNative
- implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
- ......
-
- public void systemReady(final Runnable goingCallback) {
- ......
-
- synchronized (this) {
- ......
-
- mMainStack.resumeTopActivityLocked(null);
- }
- }
-
- ......
- }
public final class ActivityManagerService extends ActivityManagerNative implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback { ...... public void systemReady(final Runnable goingCallback) { ...... synchronized (this) { ...... mMainStack.resumeTopActivityLocked(null); } } ...... } 这个函数的内容比较多,这里省去无关的部分,主要关心启动Home应用程序的逻辑,这里就是通过mMainStack.resumeTopActivityLocked函数来启动Home应用程序的了,这里的mMainStack是一个ActivityStack类型的实例变量。
Step 11. ActivityStack.resumeTopActivityLocked
这个函数定义在frameworks/base/services/java/com/android/server/am/ActivityStack.java文件中:
view plain copy to clipboard print ?
- public class ActivityStack {
- ......
-
- final boolean resumeTopActivityLocked(ActivityRecord prev) {
-
- ActivityRecord next = topRunningActivityLocked(null);
-
- ......
-
- if (next == null) {
-
-
- if (mMainStack) {
- return mService.startHomeActivityLocked();
- }
- }
-
- ......
- }
-
- ......
- }
public class ActivityStack { ...... final boolean resumeTopActivityLocked(ActivityRecord prev) { // Find the first activity that is not finishing. ActivityRecord next = topRunningActivityLocked(null); ...... if (next == null) { // There are no more activities! Let's just start up the // Launcher... if (mMainStack) { return mService.startHomeActivityLocked(); } } ...... } ...... } 这里调用函数topRunningActivityLocked返回的是当前系统Activity堆栈最顶端的Activity,由于此时还没有Activity被启动过,因此,返回值为null,即next变量的值为null,于是就调用mService.startHomeActivityLocked语句,这里的mService就是前面在Step 7中创建的ActivityManagerService实例了。
Step 12. ActivityManagerService.startHomeActivityLocked
这个函数定义在frameworks/base/services/java/com/android/server/am/ActivityManagerServcie.java文件中:
view plain copy to clipboard print ?
- public final class ActivityManagerService extends ActivityManagerNative
- implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
- ......
-
- boolean startHomeActivityLocked() {
- ......
-
- Intent intent = new Intent(
- mTopAction,
- mTopData != null ? Uri.parse(mTopData) : null);
- intent.setComponent(mTopComponent);
- if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
- intent.addCategory(Intent.CATEGORY_HOME);
- }
- ActivityInfo aInfo =
- intent.resolveActivityInfo(mContext.getPackageManager(),
- STOCK_PM_FLAGS);
- if (aInfo != null) {
- intent.setComponent(new ComponentName(
- aInfo.applicationInfo.packageName, aInfo.name));
-
-
- ProcessRecord app = getProcessRecordLocked(aInfo.processName,
- aInfo.applicationInfo.uid);
- if (app == null || app.instrumentationClass == null) {
- intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
- mMainStack.startActivityLocked(null, intent, null, null, 0, aInfo,
- null, null, 0, 0, 0, false, false);
- }
- }
-
- return true;
- }
-
- ......
- }
public final class ActivityManagerService extends ActivityManagerNative implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback { ...... boolean startHomeActivityLocked() { ...... Intent intent = new Intent( mTopAction, mTopData != null ? Uri.parse(mTopData) : null); intent.setComponent(mTopComponent); if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) { intent.addCategory(Intent.CATEGORY_HOME); } ActivityInfo aInfo = intent.resolveActivityInfo(mContext.getPackageManager(), STOCK_PM_FLAGS); if (aInfo != null) { intent.setComponent(new ComponentName( aInfo.applicationInfo.packageName, aInfo.name)); // Don't do this if the home app is currently being // instrumented. ProcessRecord app = getProcessRecordLocked(aInfo.processName, aInfo.applicationInfo.uid); if (app == null || app.instrumentationClass == null) { intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK); mMainStack.startActivityLocked(null, intent, null, null, 0, aInfo, null, null, 0, 0, 0, false, false); } } return true; } ...... } 函数首先创建一个CATEGORY_HOME类型的Intent,然后通过Intent.resolveActivityInfo函数向PackageManagerService查询Category类型为HOME的Activity,这里我们假设只有系统自带的Launcher应用程序注册了HOME类型的Activity(见packages/apps/Launcher2/AndroidManifest.xml文件):
view plain copy to clipboard print ?
- <manifest
- xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.launcher"
- android:sharedUserId="@string/sharedUserId"
- >
-
- ......
-
- <application
- android:name="com.android.launcher2.LauncherApplication"
- android:process="@string/process"
- android:label="@string/application_name"
- android:icon="@drawable/ic_launcher_home">
-
- <activity
- android:name="com.android.launcher2.Launcher"
- android:launchMode="singleTask"
- android:clearTaskOnLaunch="true"
- android:stateNotNeeded="true"
- android:theme="@style/Theme"
- android:screenOrientation="nosensor"
- android:windowSoftInputMode="stateUnspecified|adjustPan">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.HOME" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.MONKEY"/>
- intent-filter>
- activity>
-
- ......
- application>
- manifest>
...... ......
因此,这里就返回com.android.launcher2.Launcher这个Activity了。由于是第一次启动这个Activity,接下来调用函数getProcessRecordLocked返回来的ProcessRecord值为null,于是,就调用mMainStack.startActivityLocked函数启动com.android.launcher2.Launcher这个Activity了,这里的mMainStack是一个ActivityStack类型的成员变量。
Step 13. ActivityStack.startActivityLocked
这个函数定义在frameworks/base/services/java/com/android/server/am/ActivityStack.java文件中
Step 14. Launcher.onCreate
这个函数定义在packages/apps/Launcher2/src/com/android/launcher2/Launcher.java文件中:
view plain copy to clipboard print ?
- public final class Launcher extends Activity
- implements View.OnClickListener, OnLongClickListener, LauncherModel.Callbacks, AllAppsView.Watcher {
- ......
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- ......
-
- if (!mRestoring) {
- mModel.startLoader(this, true);
- }
-
- ......
- }
-
- ......
- }
public final class Launcher extends Activity implements View.OnClickListener, OnLongClickListener, LauncherModel.Callbacks, AllAppsView.Watcher { ...... @Override protected void onCreate(Bundle savedInstanceState) { ...... if (!mRestoring) { mModel.startLoader(this, true); } ...... } ...... } 这里的mModel是一个LauncherModel类型的成员变量,这里通过调用它的startLoader成员函数来执行加应用程序的操作。
Step 15. LauncherModel.startLoader
这个函数定义在packages/apps/Launcher2/src/com/android/launcher2/LauncherModel.java文件中:
view plain copy to clipboard print ?
- public class LauncherModel extends BroadcastReceiver {
- ......
-
- public void startLoader(Context context, boolean isLaunching) {
- ......
-
- synchronized (mLock) {
- ......
-
-
- if (mCallbacks != null && mCallbacks.get() != null) {
-
- LoaderTask oldTask = mLoaderTask;
- if (oldTask != null) {
- if (oldTask.isLaunching()) {
-
- isLaunching = true;
- }
- oldTask.stopLocked();
- }
- mLoaderTask = new LoaderTask(context, isLaunching);
- sWorker.post(mLoaderTask);
- }
- }
- }
-
- ......
- }
public class LauncherModel extends BroadcastReceiver { ...... public void startLoader(Context context, boolean isLaunching) { ...... synchronized (mLock) { ...... // Don't bother to start the thread if we know it's not going to do anything if (mCallbacks != null && mCallbacks.get() != null) { // If there is already one running, tell it to stop. LoaderTask oldTask = mLoaderTask; if (oldTask != null) { if (oldTask.isLaunching()) { // don't downgrade isLaunching if we're already running isLaunching = true; } oldTask.stopLocked(); } mLoaderTask = new LoaderTask(context, isLaunching); sWorker.post(mLoaderTask); } } } ...... } 这里不是直接加载应用程序,而是把加载应用程序的操作作为一个消息来处理。这里的sWorker是一个Handler,通过它的post方式把一个消息放在消息队列中去,然后系统就会调用传进去的参数mLoaderTask的run函数来处理这个消息,这个mLoaderTask是LoaderTask类型的实例,于是,下面就会执行LoaderTask类的run函数了。
Step 16. LoaderTask.run
这个函数定义在packages/apps/Launcher2/src/com/android/launcher2/LauncherModel.java文件中:
view plain copy to clipboard print ?
- public class LauncherModel extends BroadcastReceiver {
- ......
-
- private class LoaderTask implements Runnable {
- ......
-
- public void run() {
- ......
-
- keep_running: {
- ......
-
-
- if (loadWorkspaceFirst) {
- ......
- loadAndBindAllApps();
- } else {
- ......
- }
-
- ......
- }
-
- ......
- }
-
- ......
- }
-
- ......
- }
public class LauncherModel extends BroadcastReceiver { ...... private class LoaderTask implements Runnable { ...... public void run() { ...... keep_running: { ...... // second step if (loadWorkspaceFirst) { ...... loadAndBindAllApps(); } else { ...... } ...... } ...... } ...... } ...... } 这里调用loadAndBindAllApps成员函数来进一步操作。
Step 17. LoaderTask.loadAndBindAllApps
这个函数定义在packages/apps/Launcher2/src/com/android/launcher2/LauncherModel.java文件中:
view plain copy to clipboard print ?
- public class LauncherModel extends BroadcastReceiver {
- ......
-
- private class LoaderTask implements Runnable {
- ......
-
- private void loadAndBindAllApps() {
- ......
-
- if (!mAllAppsLoaded) {
- loadAllAppsByBatch();
- if (mStopped) {
- return;
- }
- mAllAppsLoaded = true;
- } else {
- onlyBindAllApps();
- }
- }
-
-
- ......
- }
-
- ......
- }
public class LauncherModel extends BroadcastReceiver { ...... private class LoaderTask implements Runnable { ...... private void loadAndBindAllApps() { ...... if (!mAllAppsLoaded) { loadAllAppsByBatch(); if (mStopped) { return; } mAllAppsLoaded = true; } else { onlyBindAllApps(); } } ...... } ...... } 由于还没有加载过应用程序,这里的mAllAppsLoaded为false,于是就继续调用loadAllAppsByBatch函数来进一步操作了。
Step 18. LoaderTask.loadAllAppsByBatch
这个函数定义在packages/apps/Launcher2/src/com/android/launcher2/LauncherModel.java文件中:
view plain copy to clipboard print ?
- public class LauncherModel extends BroadcastReceiver {
- ......
-
- private class LoaderTask implements Runnable {
- ......
-
- private void loadAllAppsByBatch() {
- ......
-
- final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
- mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
-
- final PackageManager packageManager = mContext.getPackageManager();
- List apps = null;
-
- int N = Integer.MAX_VALUE;
-
- int startIndex;
- int i=0;
- int batchSize = -1;
- while (i < N && !mStopped) {
- if (i == 0) {
- mAllAppsList.clear();
- ......
- apps = packageManager.queryIntentActivities(mainIntent, 0);
-
- ......
-
- N = apps.size();
-
- ......
-
- if (mBatchSize == 0) {
- batchSize = N;
- } else {
- batchSize = mBatchSize;
- }
-
- ......
-
- Collections.sort(apps,
- new ResolveInfo.DisplayNameComparator(packageManager));
- }
-
- startIndex = i;
- for (int j=0; i
-
- mAllAppsList.add(new ApplicationInfo(apps.get(i), mIconCache));
- i++;
- }
-
- final boolean first = i <= batchSize;
- final Callbacks callbacks = tryGetCallbacks(oldCallbacks);
- final ArrayList added = mAllAppsList.added;
- mAllAppsList.added = new ArrayList();
-
- mHandler.post(new Runnable() {
- public void run() {
- final long t = SystemClock.uptimeMillis();
- if (callbacks != null) {
- if (first) {
- callbacks.bindAllApplications(added);
- } else {
- callbacks.bindAppsAdded(added);
- }
- ......
- } else {
- ......
- }
- }
- });
-
- ......
- }
-
- ......
- }
-
- ......
- }
-
- ......
- }
public class LauncherModel extends BroadcastReceiver { ...... private class LoaderTask implements Runnable { ...... private void loadAllAppsByBatch() { ...... final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null); mainIntent.addCategory(Intent.CATEGORY_LAUNCHER); final PackageManager packageManager = mContext.getPackageManager(); List apps = null; int N = Integer.MAX_VALUE; int startIndex; int i=0; int batchSize = -1; while (i < N && !mStopped) { if (i == 0) { mAllAppsList.clear(); ...... apps = packageManager.queryIntentActivities(mainIntent, 0); ...... N = apps.size(); ...... if (mBatchSize == 0) { batchSize = N; } else { batchSize = mBatchSize; } ...... Collections.sort(apps, new ResolveInfo.DisplayNameComparator(packageManager)); } startIndex = i; for (int j=0; i added = mAllAppsList.added; mAllAppsList.added = new ArrayList(); mHandler.post(new Runnable() { public void run() { final long t = SystemClock.uptimeMillis(); if (callbacks != null) { if (first) { callbacks.bindAllApplications(added); } else { callbacks.bindAppsAdded(added); } ...... } else { ...... } } }); ...... } ...... } ...... } ...... } 函数首先构造一个CATEGORY_LAUNCHER类型的Intent:
view plain copy to clipboard print ?
- final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
- mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null); mainIntent.addCategory(Intent.CATEGORY_LAUNCHER); 接着从mContext变量中获得PackageManagerService的接口:
view plain copy to clipboard print ?
- final PackageManager packageManager = mContext.getPackageManager();
final PackageManager packageManager = mContext.getPackageManager();
下一步就是通过这个PackageManagerService.queryIntentActivities接口来取回所有Action类型为Intent.ACTION_MAIN,并且Category类型为Intent.CATEGORY_LAUNCHER的Activity了。
我们先进入到PackageManagerService.queryIntentActivities函数中看看是如何获得这些Activity的,然后再回到这个函数中来看其余操作。
Step 19. PackageManagerService.queryIntentActivities
这个函数定义在frameworks/base/services/java/com/android/server/PackageManagerService.java文件中:
view plain copy to clipboard print ?
- class PackageManagerService extends IPackageManager.Stub {
- ......
-
- public List queryIntentActivities(Intent intent,
- String resolvedType, int flags) {
- ......
-
- synchronized (mPackages) {
- String pkgName = intent.getPackage();
- if (pkgName == null) {
- return (List)mActivities.queryIntent(intent,
- resolvedType, flags);
- }
-
- ......
- }
-
- ......
- }
-
- ......
- }
class PackageManagerService extends IPackageManager.Stub { ...... public List queryIntentActivities(Intent intent, String resolvedType, int flags) { ...... synchronized (mPackages) { String pkgName = intent.getPackage(); if (pkgName == null) { return (List)mActivities.queryIntent(intent, resolvedType, flags); } ...... } ...... } ...... }
系统在启动PackageManagerService时,会把系统中的应用程序都解析一遍,然后把解析得到的Activity都保存在mActivities变量中,这里通过这个mActivities变量的queryIntent函数返回符合条件intent的Activity,这里要返回的便是Action类型为Intent.ACTION_MAIN,并且Category类型为Intent.CATEGORY_LAUNCHER的Activity了。
回到Step 18中的 LoaderTask.loadAllAppsByBatch函数中,从queryIntentActivities函数调用处返回所要求的Activity后,便调用函数tryGetCallbacks(oldCallbacks)得到一个返CallBack接口,这个接口是由Launcher类实现的,接着调用这个接口的.bindAllApplications函数来进一步操作。注意,这里又是通过消息来处理加载应用程序的操作的。
Step 20. Launcher.bindAllApplications
这个函数定义在packages/apps/Launcher2/src/com/android/launcher2/Launcher.java文件中:
view plain copy to clipboard print ?
- public final class Launcher extends Activity
- implements View.OnClickListener, OnLongClickListener, LauncherModel.Callbacks, AllAppsView.Watcher {
- ......
-
- private AllAppsView mAllAppsGrid;
-
- ......
-
- public void bindAllApplications(ArrayList apps) {
- mAllAppsGrid.setApps(apps);
- }
-
- ......
- }
public final class Launcher extends Activity implements View.OnClickListener, OnLongClickListener, LauncherModel.Callbacks, AllAppsView.Watcher { ...... private AllAppsView mAllAppsGrid; ...... public void bindAllApplications(ArrayList apps) { mAllAppsGrid.setApps(apps); } ...... } 这里的mAllAppsGrid是一个AllAppsView类型的变量,它的实际类型一般就是AllApps2D了。
Step 21. AllApps2D.setApps
这个函数定义在packages/apps/Launcher2/src/com/android/launcher2/AllApps2D.java文件中:
view plain copy to clipboard print ?
- public class AllApps2D
- extends RelativeLayout
- implements AllAppsView,
- AdapterView.OnItemClickListener,
- AdapterView.OnItemLongClickListener,
- View.OnKeyListener,
- DragSource {
-
- ......
-
- public void setApps(ArrayList list) {
- mAllAppsList.clear();
- addApps(list);
- }
-
- public void addApps(ArrayList list) {
- final int N = list.size();
-
- for (int i=0; i
- final ApplicationInfo item = list.get(i);
- int index = Collections.binarySearch(mAllAppsList, item,
- LauncherModel.APP_NAME_COMPARATOR);
- if (index < 0) {
- index = -(index+1);
- }
- mAllAppsList.add(index, item);
- }
- mAppsAdapter.notifyDataSetChanged();
- }
-
- ......
- }
public class AllApps2D extends RelativeLayout implements AllAppsView, AdapterView.OnItemClickListener, AdapterView.OnItemLongClickListener, View.OnKeyListener, DragSource { ...... public void setApps(ArrayList list) { mAllAppsList.clear(); addApps(list); } public void addApps(ArrayList list) { final int N = list.size(); for (int i=0; i
到了这里,系统默认的Home应用程序Launcher就把PackageManagerService中的应用程序加载进来了,当我们在屏幕上点击下面这个图标时,就会把刚才加载好的应用程序以图标的形式展示出来了:
点击这个按钮时,便会响应Launcher.onClick函数:
view plain copy to clipboard print ?
- public final class Launcher extends Activity
- implements View.OnClickListener, OnLongClickListener, LauncherModel.Callbacks, AllAppsView.Watcher {
- ......
-
- public void onClick(View v) {
- Object tag = v.getTag();
- if (tag instanceof ShortcutInfo) {
- ......
- } else if (tag instanceof FolderInfo) {
- ......
- } else if (v == mHandleView) {
- if (isAllAppsVisible()) {
- ......
- } else {
- showAllApps(true);
- }
- }
- }
-
- ......
- }
public final class Launcher extends Activity implements View.OnClickListener, OnLongClickListener, LauncherModel.Callbacks, AllAppsView.Watcher { ...... public void onClick(View v) { Object tag = v.getTag(); if (tag instanceof ShortcutInfo) { ...... } else if (tag instanceof FolderInfo) { ...... } else if (v == mHandleView) { if (isAllAppsVisible()) { ...... } else { showAllApps(true); } } } ...... } 接着就会调用showAllApps函数显示应用程序图标:
view plain copy to clipboard print ?
- public final class Launcher extends Activity
- implements View.OnClickListener, OnLongClickListener, LauncherModel.Callbacks, AllAppsView.Watcher {
- ......
-
- void showAllApps(boolean animated) {
- mAllAppsGrid.zoom(1.0f, animated);
-
- ((View) mAllAppsGrid).setFocusable(true);
- ((View) mAllAppsGrid).requestFocus();
-
-
- mDeleteZone.setVisibility(View.GONE);
- }
-
- ......
- }
public final class Launcher extends Activity implements View.OnClickListener, OnLongClickListener, LauncherModel.Callbacks, AllAppsView.Watcher { ...... void showAllApps(boolean animated) { mAllAppsGrid.zoom(1.0f, animated); ((View) mAllAppsGrid).setFocusable(true); ((View) mAllAppsGrid).requestFocus(); // TODO: fade these two too mDeleteZone.setVisibility(View.GONE); } ...... } 这样我们就可以看到系统中的应用程序了:
当点击上面的这些应用程序图标时,便会响应AllApps2D.onItemClick函数:
view plain copy to clipboard print ?
- public class AllApps2D
- extends RelativeLayout
- implements AllAppsView,
- AdapterView.OnItemClickListener,
- AdapterView.OnItemLongClickListener,
- View.OnKeyListener,
- DragSource {
-
- ......
-
- public void onItemClick(AdapterView parent, View v, int position, long id) {
- ApplicationInfo app = (ApplicationInfo) parent.getItemAtPosition(position);
- mLauncher.startActivitySafely(app.intent, app);
- }
-
-
- ......
- }
public class AllApps2D extends RelativeLayout implements AllAppsView, AdapterView.OnItemClickListener, AdapterView.OnItemLongClickListener, View.OnKeyListener, DragSource { ...... public void onItemClick(AdapterView parent, View v, int position, long id) { ApplicationInfo app = (ApplicationInfo) parent.getItemAtPosition(position); mLauncher.startActivitySafely(app.intent, app); } ...... } 这里的成员变量mLauncher的类型为Launcher,于是就调用Launcher.startActivitySafely函数来启动应用程序了。
七 Launcher widget添加过程
Android中的AppWidget与google widget和中移动的widget并不是一个概念,这里的AppWidget只是把一个进程的控件嵌入到别外一个进程的窗口里的一种方法。View在另外一个进程里显示,但事件的处理方法还是在原来的进程里。这有点像 X Window中的嵌入式窗口。
首先我们需要了解RemoteViews, AppWidgetHost, AppWidgetHostView等概念
RemoteViews:并不是一个真正的View,它没有实现View的接口,而只是一个用于描述View的实体。比如:创建View需要的资源ID和各个控件的事件响应方法。RemoteViews会通过进程间通信机制传递给AppWidgetHost。
AppWidgetHost
AppWidgetHost是真正容纳AppWidget的地方,它的主要功能有两个:
o 监听来自AppWidgetService的事件:
class Callbacks extends IAppWidgetHost.Stub { public void updateAppWidget(int appWidgetId,RemoteViews views) { Message msg = mHandler.obtainMessage(HANDLE_UPDATE); msg.arg1 = appWidgetId;msg.obj = views; msg.sendToTarget(); } public void providerChanged(int appWidgetId,AppWidgetProviderInfo info) { Message msg = mHandler.obtainMessage(HANDLE_PROVIDER_CHANGED);msg.arg1 = appWidgetId; msg.obj = info; msg.sendToTarget(); } }
这是主要处理update和provider_changed两个事件,根据这两个事件更新widget。
class UpdateHandler extends Handler { public UpdateHandler(Looper looper) { super(looper); } public void handleMessage(Message msg) { switch (msg.what) { case HANDLE_UPDATE: {updateAppWidgetView(msg.arg1, (RemoteViews)msg.obj); break; } case HANDLE_PROVIDER_CHANGED: {onProviderChanged(msg.arg1, (AppWidgetProviderInfo)msg.obj); break; } } } }
o 另外一个功能就是创建AppWidgetHostView。前面我们说过RemoteViews不是真正的View,只是View的描述,而AppWidgetHostView才是真正的View。这里先创建AppWidgetHostView,然后通过AppWidgetService查询appWidgetId对应的RemoteViews,最后把RemoteViews传递给AppWidgetHostView去updateAppWidget。
public final AppWidgetHostView createView(Context context, int appWidgetId, AppWidgetProviderInfo appWidget) { AppWidgetHostView view = onCreateView(context, appWidgetId, appWidget);view.setAppWidget(appWidgetId, appWidget); synchronized (mViews) { mViews.put(appWidgetId, view); }RemoteViews views = null; try { views = sService.getAppWidgetViews(appWidgetId); } catch(RemoteException e) { throw new RuntimeException("system server dead?", e); }view.updateAppWidget(views); return view; }
AppWidgetHostView
AppWidgetHostView是真正的View,但它只是一个容器,用来容纳实际的AppWidget的View。这个AppWidget的View是根据RemoteViews的描述来创建。这是在updateAppWidget里做的:
public void updateAppWidget(RemoteViews remoteViews) { ... if (content == null && layoutId ==mLayoutId) { try { remoteViews.reapply(mContext, mView); content = mView; recycled = true; if(LOGD) Log.d(TAG, "was able to recycled existing layout"); } catch (RuntimeException e) { exception= e; } } // Try normal RemoteView inflation if (content == null) { try { content =remoteViews.apply(mContext, this); if (LOGD) Log.d(TAG, "had to inflate new layout"); } catch(RuntimeException e) { exception = e; } } ... if (!recycled) { prepareView(content);addView(content); } if (mView != content) { removeView(mView); mView = content; } ... }
remoteViews.apply创建了实际的View,下面代码可以看出:
public View apply(Context context, ViewGroup parent) { View result = null; Context c =prepareContext(context); Resources r = c.getResources(); LayoutInflater inflater =(LayoutInflater) c .getSystemService(Context.LAYOUT_INFLATER_SERVICE); inflater =inflater.cloneInContext(c); inflater.setFilter(this); result = inflater.inflate(mLayoutId,parent, false); performApply(result); return result; }
Host的实现者
AppWidgetHost和AppWidgetHostView是在框架中定义的两个基类。应用程序可以利用这两个类来实现自己的Host。Launcher是缺省的桌面,它是一个Host的实现者。
LauncherAppWidgetHostView扩展了AppWidgetHostView,实现了对长按事件的处理。
LauncherAppWidgetHost扩展了AppWidgetHost,这里只是重载了onCreateView,创建LauncherAppWidgetHostView的实例。
AppWidgetService
AppWidgetService存在的目的主要是解开AppWidgetProvider和AppWidgetHost之间的耦合。如果AppWidgetProvider和AppWidgetHost的关系固定死了,AppWidget就无法在任意进程里显示了。而有了AppWidgetService,AppWidgetProvider根本不需要知道自己的AppWidget在哪里显示了。
LauncherAppWidgetHostView: 扩展了AppWidgetHostView,实现了对长按事件的处理
LauncherAppWidgetHost: 扩展了AppWidgetHost,这里只是重载了onCreateView,创建LauncherAppWidgetHostView的实例
24
/**
25
* Specific {@link AppWidgetHost} that creates our {@link LauncherAppWidgetHostView}
26
* which correctly captures all long-press events. This ensures that users can
27
* always pick up and move widgets.
28
*/
29
public class LauncherAppWidgetHost extends AppWidgetHost {
30
public LauncherAppWidgetHost(Context context, int hostId) {
31
super(context, hostId);
32
}
33
34
@Override
35
protected AppWidgetHostView onCreateView(Context context, int appWidgetId,
36
AppWidgetProviderInfo appWidget) {
37
return new LauncherAppWidgetHostView(context);
38
}
39
}
首先在Launcher.java中定义了如下两个变量
174
private AppWidgetManager mAppWidgetManager;
175
private LauncherAppWidgetHost mAppWidgetHost;
在onCreate函数中初始化,
224
mAppWidgetManager = AppWidgetManager.getInstance(this);
225
mAppWidgetHost = new LauncherAppWidgetHost(this, APPWIDGET_HOST_ID);
226
mAppWidgetHost.startListening();
上述代码,获取mAppWidgetManager的实例,并创建LauncherAppWidgetHost,以及监听
AppWidgetManager只是应用程序与底层Service之间的一个桥梁,是Android中标准的aidl实现方式
应用程序通过AppWidgetManager调用Service中的方法
frameworks/base /
core
/
java
/
android
/
appwidget
/
AppWidgetManager.java
35
/**
36
* Updates AppWidget state; gets information about installed AppWidget providers and other
37
* AppWidget related state.
38
*/
39
public class AppWidgetManager {
197 static WeakHashMap> sManagerCache = new WeakHashMap();
198
static IAppWidgetService sService;
204
/**
205
* Get the AppWidgetManager instance to use for the supplied {@link android.content.Context
206
* Context} object.
207
*/
208
public static AppWidgetManager getInstance(Context context) {
209
synchronized (sManagerCache) {
210
if (sService == null) {
211
IBinder b = ServiceManager.getService(Context.APPWIDGET_SERVICE);
212
sService = IAppWidgetService.Stub.asInterface(b);
213
}
214
215
WeakReference
ref = sManagerCache.get(context);
216
AppWidgetManager result = null;
217
if (ref != null) {
218
result = ref.get();
219
}
220
if (result == null) {
221
result = new AppWidgetManager(context);
222
sManagerCache.put(context, new WeakReference(result));
223
}
224
return result;
225
}
226
}
227
228
private AppWidgetManager(Context context) {
229
mContext = context;
230
mDisplayMetrics = context.getResources().getDisplayMetrics();
231
}
以上代码是设计模式中标准的单例模式
frameworks/base/ core / java / android / appwidget / AppWidgetHost.java
90
public AppWidgetHost(Context context, int hostId) {
91
mContext = context;
92
mHostId = hostId;
93
mHandler = new UpdateHandler(context.getMainLooper());
94
synchronized (sServiceLock) {
95
if (sService == null) {
96
IBinder b = ServiceManager.getService(Context.APPWIDGET_SERVICE);
97
sService = IAppWidgetService.Stub.asInterface(b);
98
}
99
}
100
}
可以看到AppWidgetHost有自己的HostId,Handler,和sService
93 mHandler = new UpdateHandler(context.getMainLooper());
这是啥用法呢?
参数为Looper,即消息处理放到此Looper的MessageQueue中,有哪些消息呢?
40
static final int HANDLE_UPDATE = 1;
41
static final int HANDLE_PROVIDER_CHANGED = 2;
48
49
class Callbacks extends IAppWidgetHost.Stub {
50
public void updateAppWidget(int appWidgetId, RemoteViews views) {
51
Message msg = mHandler.obtainMessage(HANDLE_UPDATE);
52
msg.arg1 = appWidgetId;
53
msg.obj = views;
54
msg.sendToTarget();
55
}
56
57
public void providerChanged(int appWidgetId, AppWidgetProviderInfo info) {
58
Message msg = mHandler.obtainMessage(HANDLE_PROVIDER_CHANGED);
59
msg.arg1 = appWidgetId;
60
msg.obj = info;
61
msg.sendToTarget();
62
}
63
}
64
65
class UpdateHandler extends Handler {
66
public UpdateHandler(Looper looper) {
67
super(looper);
68
}
69
70
public void handleMessage(Message msg) {
71
switch (msg.what) {
72
case HANDLE_UPDATE: {
73
updateAppWidgetView(msg.arg1, (RemoteViews)msg.obj);
74
break;
75
}
76
case HANDLE_PROVIDER_CHANGED: {
77
onProviderChanged(msg.arg1, (AppWidgetProviderInfo)msg.obj);
78
break;
79
}
80
}
81
}
82
}
通过以上可以看到主要有两中类型的消息,HANDLE_UPDATE和HANDLE_PROVIDER_CHANGED
处理即通过自身定义的方法
231
/**
232
* Called when the AppWidget provider for a AppWidget has been upgraded to a new apk.
233
*/
234
protected void onProviderChanged(int appWidgetId, AppWidgetProviderInfo appWidget) {
235
AppWidgetHostView v;
236
synchronized (mViews) {
237
v = mViews.get(appWidgetId);
238
}
239
if (v != null) {
240
v.updateAppWidget(null, AppWidgetHostView.UPDATE_FLAGS_RESET);
241
}
242
}
243
244
void updateAppWidgetView(int appWidgetId, RemoteViews views) {
245
AppWidgetHostView v;
246
synchronized (mViews) {
247
v = mViews.get(appWidgetId);
248
}
249
if (v != null) {
250
v.updateAppWidget(views, 0);
251
}
252
}
那么此消息是何时由谁发送的呢?
从以上的代码中看到AppWidgetHost定义了内部类Callback,扩展了类IAppWidgetHost.Stub,类Callback中负责发送以上消息
Launcher中会调用本类中的如下方法,
102
/**
103
* Start receiving onAppWidgetChanged calls for your AppWidgets. Call this when your activity
104
* becomes visible, i.e. from onStart() in your Activity.
105
*/
106
public void startListening() {
107
int[] updatedIds;
108
ArrayList updatedViews = new ArrayList();
109
110
try {
111
if (mPackageName == null) {
112
mPackageName = mContext.getPackageName();
113
}
114
updatedIds = sService.startListening(mCallbacks, mPackageName, mHostId, updatedViews);
115
}
116
catch (RemoteException e) {
117
throw new RuntimeException("system server dead?", e);
118
}
119
120
final int N = updatedIds.length;
121
for (int i=0; i
122
updateAppWidgetView(updatedIds[i], updatedViews.get(i));
123
}
124
}
最终调用AppWidgetService中的方法startListening方法,并把mCallbacks传过去,由Service负责发送消息
Launcher中添加Widget
在Launcher中添加widget,有两种途径,通过Menu或者长按桌面的空白区域,都会弹出Dialog,让用户选择添加
如下代码是当用户选择
1999
/**
2000
* Handle the action clicked in the "Add to home" dialog.
2001
*/
2002
public void onClick(DialogInterface dialog, int which) {
2003
Resources res = getResources();
2004
cleanup();
2005
2006
switch (which) {
2007
case AddAdapter.ITEM_SHORTCUT: {
2008
// Insert extra item to handle picking application
2009
pickShortcut();
2010
break;
2011
}
2012
2013
case AddAdapter.ITEM_APPWIDGET: {
2014
int appWidgetId = Launcher.this.mAppWidgetHost.allocateAppWidgetId();
2015
2016
Intent pickIntent = new Intent(AppWidgetManager.ACTION_APPWIDGET_PICK);
2017
pickIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
2018
// start the pick activity
2019
startActivityForResult(pickIntent, REQUEST_PICK_APPWIDGET);
2020
break;
2021
}
当用户在Dialog中选择AddAdapter.ITEM_APPWIDGET时,首先会通过AppWidgethost分配一个appWidgetId,并最终调到AppWidgetService中去
同时发送Intent,其中保存有刚刚分配的appWidgetId,AppWidgetManager.EXTRA_APPWIDGET_ID
139
/**
140
* Get a appWidgetId for a host in the calling process.
141
*
142
* @return a appWidgetId
143
*/
144
public int allocateAppWidgetId() {
145
try {
146
if (mPackageName == null) {
147
mPackageName = mContext.getPackageName();
148
}
149
return sService.allocateAppWidgetId(mPackageName, mHostId);
150
}
151
catch (RemoteException e) {
152
throw new RuntimeException("system server dead?", e);
153
}
154
}
2016
Intent pickIntent = new Intent(AppWidgetManager.ACTION_APPWIDGET_PICK);
2017
pickIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
2018
// start the pick activity
2019
startActivityForResult(pickIntent, REQUEST_PICK_APPWIDGET);
这段代码之后,代码将会怎么执行呢,根据Log信息,可以看到代码将会执行到Setting应用中
packages/apps/Settings/
src
/
com
/
android
/
settings
/
AppWidgetPickActivity.java
此类将会通过AppWidgetService获取到当前系统已经安装的Widget,并显示出来
78
/**
79
* Create list entries for any custom widgets requested through
80
* {@link AppWidgetManager#EXTRA_CUSTOM_INFO}.
81
*/
82
void putCustomAppWidgets(List
items) {
83
final Bundle extras = getIntent().getExtras();
84
85
// get and validate the extras they gave us
86
ArrayList
customInfo = null;
87
ArrayList customExtras = null;
88
try_custom_items: {
89
customInfo = extras.getParcelableArrayList(AppWidgetManager.EXTRA_CUSTOM_INFO);
90
if (customInfo == null || customInfo.size() == 0) {
91
Log.i(TAG, "EXTRA_CUSTOM_INFO not present.");
92
break try_custom_items;
93
}
94
95
int customInfoSize = customInfo.size();
96
for (int i=0; i
97
Parcelable p = customInfo.get(i);
98
if (p == null || !(p instanceof AppWidgetProviderInfo)) {
99
customInfo = null;
100
Log.e(TAG, "error using EXTRA_CUSTOM_INFO index=" + i);
101
break try_custom_items;
102
}
103
}
104
105
customExtras = extras.getParcelableArrayList(AppWidgetManager.EXTRA_CUSTOM_EXTRAS);
106
if (customExtras == null) {
107
customInfo = null;
108
Log.e(TAG, "EXTRA_CUSTOM_INFO without EXTRA_CUSTOM_EXTRAS");
109
break try_custom_items;
110
}
111
112
int customExtrasSize = customExtras.size();
113
if (customInfoSize != customExtrasSize) {
114
Log.e(TAG, "list size mismatch: EXTRA_CUSTOM_INFO: " + customInfoSize
115
+ " EXTRA_CUSTOM_EXTRAS: " + customExtrasSize);
116
break try_custom_items;
117
}
118
119
120
for (int i=0; i
121
Parcelable p = customExtras.get(i);
122
if (p == null || !(p instanceof Bundle)) {
123
customInfo = null;
124
customExtras = null;
125
Log.e(TAG, "error using EXTRA_CUSTOM_EXTRAS index=" + i);
126
break try_custom_items;
127
}
128
}
129
}
130
131
if (LOGD) Log.d(TAG, "Using " + customInfo.size() + " custom items");
132
putAppWidgetItems(customInfo, customExtras, items);
133
}
从上述代码中可以看到,可以放置用户自己定义的伪Widget
关于伪widget,个人有如下想法:
早期Android版本中的Google Search Bar就属于伪Widget,其实就是把widget做到Launcher中,但是用户体验与真widget并没有区别,个人猜想HTC的sense就是这样实现的。
优点:是不需要进程间的通信,效率将会更高,并且也可以规避点Widget开发的种种限制
缺点:导致Launcher代码庞大,不易于维护
用户选择完之后,代码如下
135
/**
136
* {@inheritDoc}
137
*/
138
@Override
139
public void onClick(DialogInterface dialog, int which) {
140
Intent intent = getIntentForPosition(which);
141
142
int result;
143
if (intent.getExtras() != null) {
144
// If there are any extras, it's because this entry is custom.
145
// Don't try to bind it, just pass it back to the app.
146
setResultData(RESULT_OK, intent);
147
} else {
148
try {
149
mAppWidgetManager.bindAppWidgetId(mAppWidgetId, intent.getComponent());
150
result = RESULT_OK;
151
} catch (IllegalArgumentException e) {
152
// This is thrown if they're already bound, or otherwise somehow
153
// bogus. Set the result to canceled, and exit. The app *should*
154
// clean up at this point. We could pass the error along, but
155
// it's not clear that that's useful -- the widget will simply not
156
// appear.
157
result = RESULT_CANCELED;
158
}
159
setResultData(result, null);
160
}
161
finish();
162
}
将会 149
mAppWidgetManager.bindAppWidgetId(mAppWidgetId, intent.getComponent());
如果此次添加的Widget是intent.getComponent()的第一个实例,将会发送如下广播
171
/**
172
* Sent when an instance of an AppWidget is added to a host for the first time.
173
* This broadcast is sent at boot time if there is a AppWidgetHost installed with
174
* an instance for this provider.
175
*
176
* @see AppWidgetProvider#onEnabled AppWidgetProvider.onEnabled(Context context)
177
*/
178 public static final String ACTION_APPWIDGET_ENABLED = "android.appwidget.action.APPWIDGET_ENABLED";
紧接着会发送UPDATE广播
135
/**
136
* Sent when it is time to update your AppWidget.
137
*
138
*
This may be sent in response to a new instance for this AppWidget provider having
139
* been instantiated, the requested {@link AppWidgetProviderInfo#updatePeriodMillis update interval}
140
* having lapsed, or the system booting.
141
*
143
* The intent will contain the following extras:
144
*
145
*
146
*
{@link #EXTRA_APPWIDGET_IDS} |
147
*
The appWidgetIds to update. This may be all of the AppWidgets created for this
148
* provider, or just a subset. The system tries to send updates for as few AppWidget
149
* instances as possible. |
150
*
151
*
152
*
153 * @see AppWidgetProvider#onUpdate AppWidgetProvider.onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds)
154
*/
155 public static final String ACTION_APPWIDGET_UPDATE = "android.appwidget.action.APPWIDGET_UPDATE";
待用户选择完要添加的widget之后,将会回到Launcher.java中的函数onActivityResult中
538
case REQUEST_PICK_APPWIDGET:
539
addAppWidget(data);
540
break;
上述addAppWidget中做了哪些事情呢?
1174
void addAppWidget(Intent data) {
1175
// TODO: catch bad widget exception when sent
1176
int appWidgetId = data.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1);
1177
AppWidgetProviderInfo appWidget = mAppWidgetManager.getAppWidgetInfo(appWidgetId);
1178
1179
if (appWidget.configure != null) {
1180
// Launch over to configure widget, if needed
1181
Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_CONFIGURE);
1182
intent.setComponent(appWidget.configure);
1183
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
1184
1185
startActivityForResultSafely(intent, REQUEST_CREATE_APPWIDGET);
1186
} else {
1187
// Otherwise just add it
1188
onActivityResult(REQUEST_CREATE_APPWIDGET, Activity.RESULT_OK, data);
1189
}
1190
}
首先获取appWidgetId,再通过AppWidgetManager获取AppWidgetProviderInfo,最后判断此Widget是否存在ConfigActivity,如果存在则启动ConfigActivity,否则直接调用函数onActivityResult
541
case REQUEST_CREATE_APPWIDGET:
542
completeAddAppWidget(data, mAddItemCellInfo);
543
break;
通过函数completeAddAppWidget把此widget的信息插入到数据库中,并添加到桌面上
873
/**
874
* Add a widget to the workspace.
875
*
876
* @param data The intent describing the appWidgetId.
877
* @param cellInfo The position on screen where to create the widget.
878
*/
879
private void completeAddAppWidget(Intent data, CellLayout.CellInfo cellInfo) {
880
Bundle extras = data.getExtras();
881
int appWidgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, -1);
882
883
if (LOGD) Log.d(TAG, "dumping extras content=" + extras.toString());
884
885
AppWidgetProviderInfo appWidgetInfo = mAppWidgetManager.getAppWidgetInfo(appWidgetId);
886
887
// Calculate the grid spans needed to fit this widget
888
CellLayout layout = (CellLayout) mWorkspace.getChildAt(cellInfo.screen);
889
int[] spans = layout.rectToCell(appWidgetInfo.minWidth, appWidgetInfo.minHeight);
890
891
// Try finding open space on Launcher screen
892
final int[] xy = mCellCoordinates;
893
if (!findSlot(cellInfo, xy, spans[0], spans[1])) {
894
if (appWidgetId != -1) mAppWidgetHost.deleteAppWidgetId(appWidgetId);
895
return;
896
}
897
898
// Build Launcher-specific widget info and save to database
899
LauncherAppWidgetInfo launcherInfo = new LauncherAppWidgetInfo(appWidgetId);
900
launcherInfo.spanX = spans[0];
901
launcherInfo.spanY = spans[1];
902
903
LauncherModel.addItemToDatabase(this, launcherInfo,
904
LauncherSettings.Favorites.CONTAINER_DESKTOP,
905
mWorkspace.getCurrentScreen(), xy[0], xy[1], false);
906
907
if (!mRestoring) {
908
mDesktopItems.add(launcherInfo);
909
910
// Perform actual inflation because we're live
911
launcherInfo.hostView = mAppWidgetHost.createView(this, appWidgetId, appWidgetInfo);
912
913
launcherInfo.hostView.setAppWidget(appWidgetId, appWidgetInfo);
914
launcherInfo.hostView.setTag(launcherInfo);
915
916
mWorkspace.addInCurrentScreen(launcherInfo.hostView, xy[0], xy[1],
917
launcherInfo.spanX, launcherInfo.spanY, isWorkspaceLocked());
918
}
919
}
Launcher中删除widget
长按一个widget,并拖入到DeleteZone中可实现删除
具体代码在DeleteZone中
92
public void onDrop(DragSource source, int x, int y, int xOffset, int yOffset,
93
DragView dragView, Object dragInfo) {
94
final ItemInfo item = (ItemInfo) dragInfo;
95
96
if (item.container == -1) return;
97
98
if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {
99
if (item instanceof LauncherAppWidgetInfo) {
100
mLauncher.removeAppWidget((LauncherAppWidgetInfo) item);
101
}
102
} else {
103
if (source instanceof UserFolder) {
104
final UserFolder userFolder = (UserFolder) source;
105
final UserFolderInfo userFolderInfo = (UserFolderInfo) userFolder.getInfo();
106
// Item must be a ShortcutInfo otherwise it couldn't have been in the folder
107
// in the first place.
108
userFolderInfo.remove((ShortcutInfo)item);
109
}
110
}
111
if (item instanceof UserFolderInfo) {
112
final UserFolderInfo userFolderInfo = (UserFolderInfo)item;
113
LauncherModel.deleteUserFolderContentsFromDatabase(mLauncher, userFolderInfo);
114
mLauncher.removeFolder(userFolderInfo);
115
} else if (item instanceof LauncherAppWidgetInfo) {
116
final LauncherAppWidgetInfo launcherAppWidgetInfo = (LauncherAppWidgetInfo) item;
117
final LauncherAppWidgetHost appWidgetHost = mLauncher.getAppWidgetHost();
118
if (appWidgetHost != null) {
119
appWidgetHost.deleteAppWidgetId(launcherAppWidgetInfo.appWidgetId);
120
}
121
}
122
LauncherModel.deleteItemFromDatabase(mLauncher, item);
123
}
删除时,判断删除的类型是否是AppWidget,如果是的话,要通过AppWidgetHost,删除AppWidetId,并最终从数据库中删除。
八 Launcher celllayout介绍
(1) 大家都知道workspace是有celllayout组成
Celllayout被划分为了4行4列的表格,用Boolean类型的mOccupied二维数组来标记每个cell是否被占用。在attrs.xml中定义了shortAxisCells和longAxisCells分别存储x轴和y轴方向的cell个数。在Celllayout构造函数中初始化。
(2) 内部类CellInfo为静态类,实现了ContextMenu.ContextMenuInfo接口,其对象用于存储cell的基本信息
VacantCell类用于存储空闲的cell,用到了同步机制用于管理对空闲位置的操作。所有的空cell都存储在vacantCells中。
cellX和cellY用于记录cell的位置,起始位0。如:(0,0) (0,1),每一页从新开始编号。
clearVacantCells作用是将Vacant清空:具体是释放每个cell,将list清空。
findVacantCellsFromOccupied从存放cell的数值中找到空闲的cell。在Launcher.Java中的restoreState方法中调用。
(3) mPortrait用于标记是横屏还是竖屏,FALSE表示竖屏,默认为FALSE。
(4)修改CellLayout页面上cell的布局:
CellLayout页面上默认的cell为4X4=16个,可以通过修改配置文件来达到修改目的。
在CellLayout.Java类的CellLayout(Context context, AttributeSet attrs, int defStyle)构造方法中用变量mShortAxisCells和mLongAxisCells存储行和列。
其值是在自定义配置文件attrs.xml中定义的,并在workspace_screen.xml中赋初值的,初值都为4,即4行、4列。可以在workspace_screen.xml修改对应的值。
注意:CellLayout构造方法中从attrs.xml中获取定义是这样的:mShortAxisCells = a.getInt(R.styleable.CellLayout_shortAxisCells, 4);当workspace_screen.xml中没有给定义的变量赋值时,上面的4就起作用。
(5)Launcher(主屏/待机) App的BUG: 没有初始化定义CellLayout中屏幕方向的布尔值参数:
- Launcher App:\cupcake\packages\apps\Launcher
待机画面分为多层,桌面Desktop Items在\res\layout-*\workspace_screen.xml中置:
-
- ... ...
- launcher:shortAxisCells="4"
- launcher:longAxisCells="4"
- ... ...
- />
以上表示4行4列.
再看看com.android.launcher.CellLayout ,其中有定义屏幕方向的参数:
- private boolean mPortrait;
但是一直没有初始化,也就是mPortrait=false,桌面的单元格设置一直是以非竖屏(横屏)的设置定义进行初始化。
再来看看横屏和竖屏情况下的初始化不同之处,就可以看出BUG了:
- boolean[][] mOccupied;//二元单元格布尔值数组
- if (mPortrait) {
- mOccupied = new boolean[mShortAxisCells][mLongAxisCells];
- } else {
- mOccupied = new boolean[mLongAxisCells][mShortAxisCells];
- }
如果我们满屏显示桌面(横向和纵向的单元格数不一致),而不是默认的只显示4行4列,则mShortAxisCells = 4, mLongAxisCells = 5,数组应该初始化是:new boolean[4][5],但是实际是按照非竖屏处理,初始化成了new boolean[5][4],会产生数组越界异常。
可以在构造函数中,添加通过屏幕方向初始化mPortrait,代码如下:
- public CellLayout(Context context, AttributeSet attrs, int defStyle)
- {
- super(context, attrs, defStyle);
- mPortrait = this.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT;// 新增代码
- ... ...
好了就写这些,太累了,以后再补上其他跟Launcher有关的