AOSP6.0.1 launcher3入门篇—解析launcher.java文件

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/a29562268/article/details/82928078

安卓系统是市场占用率最高、用户使用率最多的手机系统。大部分安卓手机厂商在AOSP(Android Open Source Project)的基础上进行二次开发,定制符合自家设备使用的安卓系统。本篇文章记录6.0.1版本launcher3(home程序)的加载过程及launcher.java部分函数分析。

安卓6.0.1版本指定launcher3为默认home程序,作为系统第一个app(由ActivityManagerService的systemReady函数通过Intent(intent.addCategory(Intent.CATEGORY_HOME); 这里注册为Intent.CATEGORY_HOME的Activity)方式打开home程序,这里只是简单介绍不进行详细描述),首先我们看下Launcher3文件夹下的AndroidManifest.xml文件:

  <activity
            android:name="com.android.launcher3.Launcher"
            android:launchMode="singleTask"
            android:clearTaskOnLaunch="true"
            android:stateNotNeeded="true"
            android:theme="@style/Theme"
            android:windowSoftInputMode="adjustPan"
            android:screenOrientation="landscape"
            android:resumeWhilePausing="true"
            android:taskAffinity=""
            android:enabled="true">
            <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>
        在这段描述中找到了<category android:name="android.intent.category.HOME" />,Launcher.java将作为主Activity进行启动。

下面开始分析Launcher.java的加载过程:

找到protected void onCreate(Bundle savedInstanceState)函数:
  程序的设计者考虑到系统启动过程中可能会不止一次启动launcher3程序(比如launcher3意外退出或别的情况导致),采用Builder模式,用一个内部类去实例化一个对象,避免一个类出现过多构造函数。
  
  首先找到if (DEBUG_STRICT_MODE)这条语句,追踪发现DEBUG_STRICT_MODE默认为false,并没有启动严苛模式,继续往下看 
  
  if (mLauncherCallbacks != null) {
            mLauncherCallbacks.preOnCreate();
        }
        如果回调方式已经创建,清空回调信息等待再次创建新的实例(当mLauncherCallbacks的OnCreate执行完成后,后续工作由mLauncherCallbacks进行完成,比如关联所有app程序,所有app的响应事件注册等,后续会专门分析launcher3中比较重要的类),继续往下

super.onCreate(savedInstanceState);
这个是Builder模式构成的重要部分,由父类或超父类(存在超父类的情况下)创建实例,

LauncherAppState.setApplicationContext(getApplicationContext());
        LauncherAppState app = LauncherAppState.getInstance();
 LauncherAppState类获取程序环境上下文进行注册服务,调用DeviceProfile实例加载桌面部件,其中包括Hotseat,workspace等;调用LauncherProvider实例监听provider等;调用LauncherModel启动回调等;调用LauncherAccessibilityDelegate增加动作等。 参考下图:

LauncherAppState调用结构
图1

继续往下分析:
mDragController = new DragController(this);
创建拖动控制器

mInflater = getLayoutInflater();
布局填充(如果桌面上有空余的部分进行填充)

mStateTransitionAnimation = new LauncherStateTransitionAnimation(this);
创建icon的动画效果(比如光标停留在app上icon会发生变化、workspace切换页也会有变化)

mAppWidgetManager = AppWidgetManagerCompat.getInstance(this);
获取app部件管理器实例,当前版本判断标准为API21

mAppWidgetHost = new LauncherAppWidgetHost(this, APPWIDGET_HOST_ID);
mAppWidgetHost.startListening();
在AppWidgetHost.startListening()中,AppWidgetHost通过AppWidgetService把AppWidgetHost,HostId等信息注册到AppWidgetService中,启动服务进行监听

setContentView(R.layout.launcher);
翻译出来的大概意思:从布局资源中设置活动内容。资源将会是
膨胀,将所有顶级视图添加到活动中。
分析结果:从布局资源中设置活动内容,初始化窗口活动空间

setupViews();
进入到SetupViews函数中

mLauncherView = findViewById(R.id.launcher);
这里调用的是packages/apps/Launcher3/res/下的xml,如果你的桌面设置默认是竖屏将会调用layout-port/launcher.xml,如果桌面默认是横屏调用layout-land/launcher.xml,找到“android:id="@+id/launcher"”修改内部参数即可,这种方法适用所有的xml修改

mFocusHandler = (FocusIndicatorView) findViewById(R.id.focus_indicator);
焦点指示器

    mDragLayer = (DragLayer) findViewById(R.id.drag_layer);

拖动层(如果从xml中设置显示=gone,home主界面变为空白)

    mWorkspace = (Workspace) mDragLayer.findViewById(R.id.workspace);

这个可以理解为工作空间,用来放置页视图的cellLayout

    mWorkspace.setPageSwitchListener(this);
    //绑定页转换监听
    mPageIndicators = mDragLayer.findViewById(R.id.page_indicator);

页指示器(页下面的点,切换页面时可以看到变化)

这几个布局加载方式与mLauncherView = findViewById(R.id.launcher);是同一个xml文件,修改方式也是相同

// Setup the hotseat
mHotseat = (Hotseat) findViewById(R.id.hotseat);
if (mHotseat != null) {
mHotseat.setOnLongClickListener(this);
}
加载hotseat(抽屉,中间是allapps按钮,点击allapps按钮进入二级界面)
设置hotseat长按键监听,如果不需要可以注释掉,对于allapps按钮进入的二级界面(cellLayout)没有效果

mOverviewPanel = (ViewGroup) findViewById(R.id.overview_panel);
描述面板(默认隐藏)

mWidgetsButton = findViewById(R.id.widget_button);
小部件按钮(在主界面空闲处长按屏幕进入可以看到)
事件函数不再分析,按中文意思理解即可

View wallpaperButton = findViewById(R.id.wallpaper_button);
壁纸按钮(在主界面空闲处长按屏幕进入可以看到)

View settingsButton = findViewById(R.id.settings_button);
设置主题按钮(在主界面空闲处长按屏幕进入可以看到)

if (mSearchDropTargetBar != null) {
mSearchDropTargetBar.setup(this, dragController);
// 取消上方搜索框
//mSearchDropTargetBar.setQsbSearchBar(getOrCreateQsbBar());
}

继续回到OnCreate()函数:

mDeviceProfile.layout(this);
在DeviceProfile实例中加载workspace,hotseat,pageIndicator,overviewMode,如果你想完成hotseat放置到主屏幕中间位置、隐藏页指示器等,可以通过修改DeviceProflle文件达到效果(后续文章将详细介绍DeviceProfile文件)

Oncreate、SetViews函数修改的位置大概就这些,后面内容可以参考上面的思路继续分析。

如果想隐藏主界面长按键功能,请在public boolean onLongClick(View v) 中注释掉所有内容,增加return true;即可,大部分事件函数可以用中文意思去理解。

猜你喜欢

转载自blog.csdn.net/a29562268/article/details/82928078