launcher in android

http://blog.csdn.net/liangshengyang/article/details/5905351

Laucher的UI组成

UI组件属性在layout-port/launcher.xml中定义,主要有Workspace和SlidingDrawer两大部分组成,盛放这两者的容器就是DragLayer。

  1. <com.android.launcher.DragLayer  
  2.     xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     xmlns:launcher="http://schemas.android.com/apk/res/com.android.launcher"  
  4.   
  5.     android:id="@+id/drag_layer"  
  6.     android:layout_width="fill_parent"  
  7.     android:layout_height="fill_parent">  
  8.   
  9.     <!-- The workspace contains 3 screens of cells -->  
  10.     <com.android.launcher.Workspace  
  11.         android:id="@+id/workspace"  
  12.         android:layout_width="fill_parent"  
  13.         android:layout_height="fill_parent"  
  14.   
  15.         launcher:defaultScreen="1">  
  16.   
  17.         <include android:id="@+id/cell1" layout="@layout/workspace_screen" />  
  18.         <include android:id="@+id/cell2" layout="@layout/workspace_screen" />  
  19.         <include android:id="@+id/cell3" layout="@layout/workspace_screen" />  
  20.   
  21.     </com.android.launcher.Workspace>  
  22.   
  23.     <SlidingDrawer  
  24.         android:id="@+id/drawer"  
  25.         android:layout_width="fill_parent"  
  26.         android:layout_height="fill_parent"  
  27.   
  28.         android:topOffset="5dip"  
  29.         android:bottomOffset="7dip"  
  30.         android:handle="@+id/all_apps"  
  31.         android:content="@+id/content">  
  32.   
  33.         <com.android.launcher.HandleView  
  34.             android:id="@id/all_apps"  
  35.             android:layout_width="fill_parent"  
  36.             android:layout_height="56dip"  
  37.   
  38.             android:background="@drawable/handle"  
  39.   
  40.             android:focusable="true"  
  41.             android:clickable="true"  
  42.   
  43.             android:scaleType="center"  
  44.             android:src="@drawable/handle_icon"  
  45.   
  46.             launcher:direction="horizontal" />  
  47.   
  48.         <com.android.launcher.AllAppsGridView  
  49.             android:id="@id/content"  
  50.             android:layout_width="fill_parent"  
  51.             android:layout_height="fill_parent"  
  52.   
  53.             launcher:texture="@drawable/pattern_carbon_fiber_dark"  
  54.   
  55.             android:scrollbarStyle="outsideInset"  
  56.             android:drawSelectorOnTop="false"  
  57.             android:listSelector="@drawable/grid_selector"  
  58.   
  59.             android:nextFocusLeft="@id/content"  
  60.             android:nextFocusDown="@id/content"  
  61.             android:nextFocusUp="@id/all_apps"  
  62.             android:nextFocusRight="@id/content"  
  63.   
  64.             android:verticalSpacing="10dip"  
  65.             android:numColumns="4" />  
  66.   
  67.     </SlidingDrawer>  
  68.   
  69.     <com.android.launcher.DeleteZone  
  70.         android:id="@+id/delete_zone"  
  71.         android:layout_width="wrap_content"  
  72.         android:layout_height="49dip"  
  73.   
  74.         android:scaleType="center"  
  75.         android:src="@drawable/ic_delete"  
  76.         android:background="@drawable/delete_zone_selector"  
  77.   
  78.         android:layout_gravity="bottom|center_horizontal"  
  79.         android:visibility="invisible"  
  80.           
  81.         launcher:direction="horizontal" />  
  82.   
  83. </com.android.launcher.DragLayer>  

 

Workspace就是启动后进入的桌面,可以左右滑动得到3个(默认值)画面,它可以有背景图片作为墙纸。

 

 

 

 

SlidingDrawer包括HandleView和AllAppsGridView两部分。在屏幕为竖直时(Portait),在layout-port/launcher.xml文件里定义的高度56dip,宽度则充满充满整个屏幕,其背景图片在文件drawable/handle.xml中指定,见上面的layout文件中的定义。文件drawable/handle.xml:

  1. <selector xmlns:android="http://schemas.android.com/apk/res/android">  
  2.     <item android:state_window_focused="false" android:state_enabled="true" android:drawable="@drawable/tray_handle_normal" />  
  3.     <item android:state_pressed="true" android:drawable="@drawable/tray_handle_pressed" />  
  4.     <item android:state_focused="true" android:state_enabled="true" android:drawable="@drawable/tray_handle_selected" />  
  5.     <item android:state_enabled="true" android:drawable="@drawable/tray_handle_normal" />  
  6.     <item android:state_focused="true" android:drawable="@drawable/tray_handle_selected" />  
  7. </selector>  

对于竖直方式来说则是诸如图片res/drawable-port/tray_handle_normal.png。前景图标源则是在

drawable/handle_icon.xml(见上面的layout文件),该文件为内容为:

  1. <transition xmlns:android="http://schemas.android.com/apk/res/android">  
  2.     <item android:drawable="@drawable/ic_tray_expand"  />  
  3.     <item android:drawable="@drawable/ic_tray_collapse"  />  
  4. </transition>  

点击或滑动HandleView中的按钮图标,则可显示AllAppsGridView,它包含了系统中的应用程序。再点击或滑动按钮,则隐藏AllAppsGridView。

在Launcher的onCreate函数中会调用setupViews来初始化各个View类,初始化布局则是由上面的layout文件中定义。setupViews函数代码如下:

  1. /** 
  2.      * Finds all the views we need and configure them properly. 
  3.      */  
  4.     private void setupViews() {  
  5.         mDragLayer = (DragLayer) findViewById(R.id.drag_layer);  
  6.         final DragLayer dragLayer = mDragLayer;  
  7.   
  8.         mWorkspace = (Workspace) dragLayer.findViewById(R.id.workspace);  
  9.         final Workspace workspace = mWorkspace;  
  10.   
  11.         mDrawer = (SlidingDrawer) dragLayer.findViewById(R.id.drawer);  
  12.         final SlidingDrawer drawer = mDrawer;  
  13.   
  14.         mAllAppsGrid = (AllAppsGridView) drawer.getContent();  
  15.         final AllAppsGridView grid = mAllAppsGrid;  
  16.   
  17.         final DeleteZone deleteZone = (DeleteZone) dragLayer.findViewById(R.id.delete_zone);  
  18.   
  19.         mHandleView = (HandleView) drawer.findViewById(R.id.all_apps);  
  20.         mHandleView.setLauncher(this);  
  21.         mHandleIcon = (TransitionDrawable) mHandleView.getDrawable();  
  22.         mHandleIcon.setCrossFadeEnabled(true);  
  23.   
  24.         drawer.lock();  
  25.         final DrawerManager drawerManager = new DrawerManager();  
  26.         drawer.setOnDrawerOpenListener(drawerManager);  
  27.         drawer.setOnDrawerCloseListener(drawerManager);  
  28.         drawer.setOnDrawerScrollListener(drawerManager);  
  29.   
  30.         grid.setTextFilterEnabled(false);  
  31.         grid.setDragger(dragLayer);  
  32.         grid.setLauncher(this);  
  33.   
  34.         workspace.setOnLongClickListener(this);  
  35.         workspace.setDragger(dragLayer);  
  36.         workspace.setLauncher(this);  
  37.         loadWallpaper();  
  38.   
  39.         deleteZone.setLauncher(this);  
  40.         deleteZone.setDragController(dragLayer);  
  41.         deleteZone.setHandle(mHandleView);  
  42.   
  43.         dragLayer.setIgnoredDropTarget(grid);  
  44.         dragLayer.setDragScoller(workspace);  
  45.         dragLayer.setDragListener(deleteZone);  
  46.     }  

其中DeleteZone用于:当长按workspace中的图标时会进入拖拽功能,可以将它们托到HandleView中,将它们从workspace中删除。

App的装载

在onCreate函数中,有如下这2行代码,用于装载应用程序信息,

  1. if (!mRestoring) {  
  2.             startLoaders();  
  3.         }  

 

startLoaders会调用LauncherModel的loadApplications函数:

  1. private void startLoaders() {  
  2.     boolean loadApplications = sModel.loadApplications(true, this, mLocaleChanged);  
  3.     sModel.loadUserItems(!mLocaleChanged, this, mLocaleChanged, loadApplications);  
  4.   
  5.     mRestoring = false;  
  6. }  

第一行装载应用程序包,第二行的函数装载workspace中用户自定义添加到ShortCut,LiveFolder,WidgetApp等。

在loadApplications中,需要注意2个地方,一是创建ApplicationsAdapter,它将应用程序数组列表ArrayList<ApplicationInfo> mApplications和View关联起来。二是继续调用函数startApplicationsLoaderLocked:

  1. /** 
  2.      * Loads the list of installed applications in mApplications. 
  3.      * 
  4.      * @return true if the applications loader must be started 
  5.      *         (see startApplicationsLoader()), false otherwise. 
  6.      */  
  7.     synchronized boolean loadApplications(boolean isLaunching, Launcher launcher,  
  8.             boolean localeChanged) {  
  9.   
  10.         if (DEBUG_LOADERS) d(LOG_TAG, "load applications");  
  11.   
  12.         if (isLaunching && mApplicationsLoaded && !localeChanged) {  
  13.             mApplicationsAdapter = new ApplicationsAdapter(launcher, mApplications);  
  14.             if (DEBUG_LOADERS) d(LOG_TAG, "  --> applications loaded, return");  
  15.             return false;  
  16.         }  
  17.   
  18.         stopAndWaitForApplicationsLoader();  
  19.   
  20.         if (localeChanged) {  
  21.             dropApplicationCache();  
  22.         }  
  23.   
  24.         if (mApplicationsAdapter == null || isLaunching || localeChanged) {  
  25.             mApplications = new ArrayList<ApplicationInfo>(DEFAULT_APPLICATIONS_NUMBER);  
  26.             mApplicationsAdapter = new ApplicationsAdapter(launcher, mApplications);  
  27.         }  
  28.   
  29.         mApplicationsLoaded = false;  
  30.   
  31.         if (!isLaunching) {  
  32.             startApplicationsLoaderLocked(launcher, false);  
  33.             return false;  
  34.         }  
  35.   
  36.         return true;  
  37.     }  

再来看看startApplicationsLoaderLocked,它实际上启动一个线程去装载应用程序信息:

  1. private void startApplicationsLoaderLocked(Launcher launcher, boolean isLaunching) {  
  2.      if (DEBUG_LOADERS) d(LOG_TAG, "  --> starting applications loader");  
  3.   
  4.      stopAndWaitForApplicationsLoader();  
  5.   
  6.      mApplicationsLoader = new ApplicationsLoader(launcher, isLaunching);  
  7.      mApplicationsLoaderThread = new Thread(mApplicationsLoader, "Applications Loader");  
  8.      mApplicationsLoaderThread.start();  
  9.  }  

它创建一个线程执行体Runnable对象mApplicationsLoader,然后在调用mApplicationsLoaderThread.start()时会执行ApplicationsLoader. run():

  1. public void run() {  
  2.             if (DEBUG_LOADERS) d(LOG_TAG, "  ----> running applications loader (" + mId + ")");  
  3.   
  4.             // Elevate priority when Home launches for the first time to avoid  
  5.             // starving at boot time. Staring at a blank home is not cool.  
  6.             android.os.Process.setThreadPriority(mIsLaunching ? Process.THREAD_PRIORITY_DEFAULT :  
  7.                     Process.THREAD_PRIORITY_BACKGROUND);  
  8.   
  9.             final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);  
  10.             mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);  
  11.   
  12.             final Launcher launcher = mLauncher.get();  
  13.             final PackageManager manager = launcher.getPackageManager();  
  14.             final List<ResolveInfo> apps = manager.queryIntentActivities(mainIntent, 0);  
  15.   
  16.             if (apps != null && !mStopped) {  
  17.                 final int count = apps.size();  
  18.                 // Can be set to null on the UI thread by the unbind() method  
  19.                 // Do not access without checking for null first  
  20.                 final ApplicationsAdapter applicationList = mApplicationsAdapter;  
  21.   
  22.                 ChangeNotifier action = new ChangeNotifier(applicationList, true);  
  23.                 final HashMap<ComponentName, ApplicationInfo> appInfoCache = mAppInfoCache;  
  24.   
  25.                 for (int i = 0; i < count && !mStopped; i++) {  
  26.                     ResolveInfo info = apps.get(i);  
  27.                     ApplicationInfo application =  
  28.                         makeAndCacheApplicationInfo(manager, appInfoCache, info, launcher);  
  29.   
  30.                     if (action.add(application) && !mStopped) {  
  31.                         launcher.runOnUiThread(action);  
  32.                         action = new ChangeNotifier(applicationList, false);  
  33.                     }  
  34.                 }  
  35.   
  36.                 launcher.runOnUiThread(action);  
  37.             }  
  38.   
  39.             if (!mStopped) {  
  40.                 mApplicationsLoaded = true;  
  41.             } else {  
  42.                 if (DEBUG_LOADERS) d(LOG_TAG, "  ----> applications loader stopped (" + mId + ")");                                  
  43.             }  
  44.             mRunning = false;  
  45.         }  
  46.     }  

在该线程中,它使用PackageManager获取安装的应用程序。

 

在装载完workspace和AllGridView中的各项后,onDesktopItemsLoaded将被调用,它会绑定桌面的Shortcut及appWidgets:

  1. void onDesktopItemsLoaded(ArrayList<ItemInfo> shortcuts,  
  2.           ArrayList<LauncherAppWidgetInfo> appWidgets) {  
  3.       if (mDestroyed) {  
  4.           if (LauncherModel.DEBUG_LOADERS) {  
  5.               d(LauncherModel.LOG_TAG, "  ------> destroyed, ignoring desktop items");  
  6.           }  
  7.           return;  
  8.       }  
  9.       bindDesktopItems(shortcuts, appWidgets);  
  10.   }  

 

绑定过程

绑定过程包括ApplicationAdapter(即ArrayAapter的子类)与AllGridView的绑定,实现数据到View的显示。

  1. private void bindDesktopItems(ArrayList<ItemInfo> shortcuts,  
  2.         ArrayList<LauncherAppWidgetInfo> appWidgets) {  
  3.   
  4.     final ApplicationsAdapter drawerAdapter = sModel.getApplicationsAdapter();  
  5.     if (shortcuts == null || appWidgets == null || drawerAdapter == null) {  
  6.         if (LauncherModel.DEBUG_LOADERS) d(LauncherModel.LOG_TAG, "  ------> a source is null");              
  7.         return;  
  8.     }  
  9.   
  10.   
  11.   
  12.  mBinder = new DesktopBinder(this, shortcuts, appWidgets, drawerAdapter);  
  13.     mBinder.startBindingItems();  
  14. }  

 

DesktopBinder的构造函数如下,指定了Adapter,实现了数据到view的绑定:

  1.         DesktopBinder(Launcher launcher, ArrayList<ItemInfo> shortcuts,  
  2.                 ArrayList<LauncherAppWidgetInfo> appWidgets,  
  3.                 ApplicationsAdapter drawerAdapter) {  
  4.   
  5.             mLauncher = new   
  6. WeakReference<Launcher>(launcher);  
  7.             mShortcuts = shortcuts;  
  8.             mDrawerAdapter = drawerAdapter;  
  9. ...  

在函数bindDrawer 中为view指定了adapter:

 

  1. private void bindDrawer(Launcher.DesktopBinder binder,  
  2.         ApplicationsAdapter drawerAdapter) {  
  3.     mAllAppsGrid.setAdapter(drawerAdapter);  
  4.     binder.startBindingAppWidgetsWhenIdle();  
  5. }  

 

其它

LauncherModel提供了添加/删除/更新应用程序包的功能 。

Launcher还提供了对ShortCut 、AppWidget、LiveFolder和搜索框等的管理功能,墙纸管理功能。默认的墙纸也是存放在该程序包的资源中。

posted @ 2012-12-24 16:39  GreyWolf  阅读(249)  评论(0编辑  收藏  举报