一.Launcher3概述
Launcher顾名思义,就是桌面的意思,也是android系统启动后第一个启动的应用程序,这里以android11为例,和其他应用并无区别,只是增加了对其他app和widget的管理窗口,且可以为用户定制化一些酷炫和常用的显示功能,代码上比其他app在manifest.xml中多添加一个HOME属性,eg:
<category android:name="android.intent.category.HOME" />
二.Launcher3界面显示
Launcher3的主要界面主要结构有如下几个
1.workspace工作区,主要包括SearchBar、CellLayout、PageIndicator、hotseat

2.所有应用列表

3.Widget

4.Wallpapers

三.Launcher3主要源码分析
1.代码结构

2.java源码分析
1). Launcher.java //launcher主要的activity,是launcher第一次启动的activity,显示和启动一些初始化的view
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- Object traceToken = TraceHelper.INSTANCE.beginSection(ON_CREATE_EVT,
- TraceHelper.FLAG_UI_EVENT);
- if (DEBUG_STRICT_MODE) {
- StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
- .detectDiskReads()
- .detectDiskWrites()
- .detectNetwork() // or .detectAll() for all detectable problems
- .penaltyLog()
- .build());
- StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
- .detectLeakedSqlLiteObjects()
- .detectLeakedClosableObjects()
- .penaltyLog()
- .penaltyDeath()
- .build());
- }
-
- super.onCreate(savedInstanceState);
-
- LauncherAppState app = LauncherAppState.getInstance(this);
- mOldConfig = new Configuration(getResources().getConfiguration());
- mModel = app.getModel();
-
- mRotationHelper = new RotationHelper(this);
- InvariantDeviceProfile idp = app.getInvariantDeviceProfile();
- initDeviceProfile(idp);
- idp.addOnChangeListener(this);
- mSharedPrefs = Utilities.getPrefs(this);
- mIconCache = app.getIconCache();
- mAccessibilityDelegate = new LauncherAccessibilityDelegate(this);
-
- mDragController = new DragController(this);
- mAllAppsController = new AllAppsTransitionController(this);
- mStateManager = new StateManager<>(this, NORMAL);
-
- mOnboardingPrefs = createOnboardingPrefs(mSharedPrefs);
-
- mAppWidgetManager = new WidgetManagerHelper(this);
- mAppWidgetHost = new LauncherAppWidgetHost(this,
- appWidgetId -> getWorkspace().removeWidget(appWidgetId));
- mAppWidgetHost.startListening();
-
- inflateRootView(R.layout.launcher);
- setupViews();
- mPopupDataProvider = new PopupDataProvider(this::updateNotificationDots);
- /**
- * Finds all the views we need and configure them properly.
- */
- protected void setupViews() {
- mDragLayer = findViewById(R.id.drag_layer);
- mFocusHandler = mDragLayer.getFocusIndicatorHelper();
- mWorkspace = mDragLayer.findViewById(R.id.workspace);
- mWorkspace.initParentViews(mDragLayer);
- mOverviewPanel = findViewById(R.id.overview_panel);
- mHotseat = findViewById(R.id.hotseat);
- mHotseat.setWorkspace(mWorkspace);
-
- // Setup the drag layer
- mDragLayer.setup(mDragController, mWorkspace);
-
- mWorkspace.setup(mDragController);
- // Until the workspace is bound, ensure that we keep the wallpaper offset locked to the
- // default state, otherwise we will update to the wrong offsets in RTL
- mWorkspace.lockWallpaperToDefaultPage();
- mWorkspace.bindAndInitFirstWorkspaceScreen(null /* recycled qsb */);
- mDragController.addDragListener(mWorkspace);
-
- // Get the search/delete/uninstall bar
- mDropTargetBar = mDragLayer.findViewById(R.id.drop_target_bar);
-
- // Setup Apps
- mAppsView = findViewById(R.id.apps_view);
-
- // Setup Scrim
- mScrimView = findViewById(R.id.scrim_view);
-
- // Setup the drag controller (drop targets have to be added in reverse order in priority)
- mDropTargetBar.setup(mDragController);
-
- mAllAppsController.setupViews(mAppsView, mScrimView);
- }
2). Workspace.java //继承自PagedView,由N个cellLayout组成,从cellLayout更高一级的层面上对事件的处理
- /**
- * Used to inflate the Workspace from XML.
- *
- * @param context The application's context.
- * @param attrs The attributes set containing the Workspace's customization values.
- * @param defStyle Unused.
- */
- public Workspace(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
-
- mLauncher = Launcher.getLauncher(context);
- mStateTransitionAnimation = new WorkspaceStateTransitionAnimation(mLauncher, this);
- mWallpaperManager = WallpaperManager.getInstance(context);
-
- mWallpaperOffset = new WallpaperOffsetInterpolator(this);
-
- setHapticFeedbackEnabled(false);
- initWorkspace();
-
- // Disable multitouch across the workspace/all apps/customize tray
- setMotionEventSplittingEnabled(true);
- setOnTouchListener(new WorkspaceTouchListener(mLauncher, this));
- mStatsLogManager = StatsLogManager.newInstance(context);
- }
3).DeviceProfile.java //icon大小、各个icon间距,布局等计算实体类,可配置各个参数的全局变量
- DeviceProfile(Context context, InvariantDeviceProfile inv, DefaultDisplay.Info info,
- Point minSize, Point maxSize, int width, int height, boolean isLandscape,
- boolean isMultiWindowMode, boolean transposeLayoutWithOrientation,
- Point windowPosition) {
-
- this.inv = inv;
- this.isLandscape = isLandscape;
- this.isMultiWindowMode = isMultiWindowMode;
- windowX = windowPosition.x;
- windowY = windowPosition.y;
-
- // Determine sizes.
- widthPx = width;
- heightPx = height;
- if (isLandscape) {
- availableWidthPx = maxSize.x;
- availableHeightPx = minSize.y;
- } else {
- availableWidthPx = minSize.x;
- availableHeightPx = maxSize.y;
- }
-
- mInfo = info;
-
- // Constants from resources
- float swDPs = Utilities.dpiFromPx(
- Math.min(info.smallestSize.x, info.smallestSize.y), info.metrics);
- isTablet = swDPs >= TABLET_MIN_DPS;
- isLargeTablet = swDPs >= LARGE_TABLET_MIN_DPS;
- isPhone = !isTablet && !isLargeTablet;
- aspectRatio = ((float) Math.max(widthPx, heightPx)) / Math.min(widthPx, heightPx);
- boolean isTallDevice = Float.compare(aspectRatio, TALL_DEVICE_ASPECT_RATIO_THRESHOLD) >= 0;
-
- // Some more constants
- this.transposeLayoutWithOrientation = transposeLayoutWithOrientation;
-
- context = getContext(context, info, isVerticalBarLayout()
- ? Configuration.ORIENTATION_LANDSCAPE
- : Configuration.ORIENTATION_PORTRAIT);
- final Resources res = context.getResources();
-
- edgeMarginPx = res.getDimensionPixelSize(R.dimen.dynamic_grid_edge_margin);
- desiredWorkspaceLeftRightMarginPx = isVerticalBarLayout() ? 0 : edgeMarginPx;
-
- int cellLayoutPaddingLeftRightMultiplier = !isVerticalBarLayout() && isTablet
- ? PORTRAIT_TABLET_LEFT_RIGHT_PADDING_MULTIPLIER : 1;
- int cellLayoutPadding = res.getDimensionPixelSize(R.dimen.dynamic_grid_cell_layout_padding);
- if (isLandscape) {
- cellLayoutPaddingLeftRightPx = 0;
- cellLayoutBottomPaddingPx = cellLayoutPadding;
- } else {
- cellLayoutPaddingLeftRightPx = cellLayoutPaddingLeftRightMultiplier * cellLayoutPadding;
- cellLayoutBottomPaddingPx = 0;
- }
-
- workspacePageIndicatorHeight = res.getDimensionPixelSize(
- R.dimen.workspace_page_indicator_height);
- mWorkspacePageIndicatorOverlapWorkspace =
- res.getDimensionPixelSize(R.dimen.workspace_page_indicator_overlap_workspace);
-
- iconDrawablePaddingOriginalPx =
- res.getDimensionPixelSize(R.dimen.dynamic_grid_icon_drawable_padding);
- dropTargetBarSizePx = res.getDimensionPixelSize(R.dimen.dynamic_grid_drop_target_size);
- workspaceSpringLoadedBottomSpace =
- res.getDimensionPixelSize(R.dimen.dynamic_grid_min_spring_loaded_space);
-
- workspaceCellPaddingXPx = res.getDimensionPixelSize(R.dimen.dynamic_grid_cell_padding_x);
-
- hotseatBarTopPaddingPx =
- res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_top_padding);
- hotseatBarBottomPaddingPx = (isTallDevice ? 0
- : res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_bottom_non_tall_padding))
- + res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_bottom_padding);
- hotseatBarSidePaddingEndPx =
- res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_side_padding);
- // Add a bit of space between nav bar and hotseat in vertical bar layout.
- hotseatBarSidePaddingStartPx = isVerticalBarLayout() ? workspacePageIndicatorHeight : 0;
- hotseatBarSizePx = ResourceUtils.pxFromDp(inv.iconSize, mInfo.metrics)
- + (isVerticalBarLayout()
- ? (hotseatBarSidePaddingStartPx + hotseatBarSidePaddingEndPx)
- : (res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_extra_vertical_size)
- + hotseatBarTopPaddingPx + hotseatBarBottomPaddingPx));
-
- // Calculate all of the remaining variables.
- updateAvailableDimensions(res);
-
- // Now that we have all of the variables calculated, we can tune certain sizes.
- if (!isVerticalBarLayout() && isPhone && isTallDevice) {
- // We increase the hotseat size when there is extra space.
- // ie. For a display with a large aspect ratio, we can keep the icons on the workspace
- // in portrait mode closer together by adding more height to the hotseat.
- // Note: This calculation was created after noticing a pattern in the design spec.
- int extraSpace = getCellSize().y - iconSizePx - iconDrawablePaddingPx * 2
- - workspacePageIndicatorHeight;
- hotseatBarSizePx += extraSpace;
- hotseatBarBottomPaddingPx += extraSpace;
-
- // Recalculate the available dimensions using the new hotseat size.
- updateAvailableDimensions(res);
- }
- updateWorkspacePadding();
-
- // This is done last, after iconSizePx is calculated above.
- mDotRendererWorkSpace = new DotRenderer(iconSizePx, IconShape.getShapePath(),
- IconShape.DEFAULT_PATH_SIZE);
- mDotRendererAllApps = iconSizePx == allAppsIconSizePx ? mDotRendererWorkSpace :
- new DotRenderer(allAppsIconSizePx, IconShape.getShapePath(),
- IconShape.DEFAULT_PATH_SIZE);
- }
4).BubbleTextView.java //继承自TextView,Launcher所有各个icon间距文字显示的父类,包括文字的大小,文字的刷新
- public BubbleTextView(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- mActivity = ActivityContext.lookupContext(context);
-
- TypedArray a = context.obtainStyledAttributes(attrs,
- R.styleable.BubbleTextView, defStyle, 0);
- mLayoutHorizontal = a.getBoolean(R.styleable.BubbleTextView_layoutHorizontal, false);
- DeviceProfile grid = mActivity.getDeviceProfile();
-
- mDisplay = a.getInteger(R.styleable.BubbleTextView_iconDisplay, DISPLAY_WORKSPACE);
- final int defaultIconSize;
- if (mDisplay == DISPLAY_WORKSPACE) {//判断显示是不是在工作区
- setTextSize(TypedValue.COMPLEX_UNIT_PX, grid.iconTextSizePx);
- setCompoundDrawablePadding(grid.iconDrawablePaddingPx);
- defaultIconSize = grid.iconSizePx;
- } else if (mDisplay == DISPLAY_ALL_APPS) {//判断显示是不是在所有应用
- setTextSize(TypedValue.COMPLEX_UNIT_PX, grid.allAppsIconTextSizePx);
- setCompoundDrawablePadding(grid.allAppsIconDrawablePaddingPx);
- defaultIconSize = grid.allAppsIconSizePx;
- } else if (mDisplay == DISPLAY_FOLDER) {//判断显示是不是在文件夹
- setTextSize(TypedValue.COMPLEX_UNIT_PX, grid.folderChildTextSizePx);
- setCompoundDrawablePadding(grid.folderChildDrawablePaddingPx);
- defaultIconSize = grid.folderChildIconSizePx;
- } else {
- // widget_selection or shortcut_popup
- defaultIconSize = grid.iconSizePx;
- }
-
- mCenterVertically = a.getBoolean(R.styleable.BubbleTextView_centerVertically, false);
-
- mIconSize = a.getDimensionPixelSize(R.styleable.BubbleTextView_iconSizeOverride,
- defaultIconSize);
- a.recycle();
-
- mLongPressHelper = new CheckLongPressHelper(this);
-
- mDotParams = new DotRenderer.DrawParams();
-
- setEllipsize(TruncateAt.END);
- setAccessibilityDelegate(mActivity.getAccessibilityDelegate());
- setTextAlpha(1f);
- }
5).CellLayout.java //继承自viewgroup,Launcher布局的计算类,图标的显示边距等,组成workspace的view,既是一个dragSource又是一个dropTarget,可以将它里面的item拖出去,也可以容纳拖动过来的item。在workspace_screen里面定了一些它的view参数
- public CellLayout(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CellLayout, defStyle, 0);
- mContainerType = a.getInteger(R.styleable.CellLayout_containerType, WORKSPACE);
- a.recycle();
-
- // A ViewGroup usually does not draw, but CellLayout needs to draw a rectangle to show
- // the user where a dragged item will land when dropped.
- setWillNotDraw(false);
- setClipToPadding(false);
- mActivity = ActivityContext.lookupContext(context);
-
- DeviceProfile grid = mActivity.getDeviceProfile();
-
- mCellWidth = mCellHeight = -1;
- mFixedCellWidth = mFixedCellHeight = -1;
-
- mCountX = grid.inv.numColumns;
- mCountY = grid.inv.numRows;
- mOccupied = new GridOccupancy(mCountX, mCountY);
- mTmpOccupied = new GridOccupancy(mCountX, mCountY);
-
- mPreviousReorderDirection[0] = INVALID_DIRECTION;
- mPreviousReorderDirection[1] = INVALID_DIRECTION;
-
- mFolderLeaveBehind.mDelegateCellX = -1;
- mFolderLeaveBehind.mDelegateCellY = -1;
-
- setAlwaysDrawnWithCacheEnabled(false);
- final Resources res = getResources();
-
- mBackground = res.getDrawable(R.drawable.bg_celllayout);
- mBackground.setCallback(this);
- mBackground.setAlpha(0);
-
- mReorderPreviewAnimationMagnitude = (REORDER_PREVIEW_MAGNITUDE * grid.iconSizePx);
-
- // Initialize the data structures used for the drag visualization.
- mEaseOutInterpolator = Interpolators.DEACCEL_2_5; // Quint ease out
- mDragCell[0] = mDragCell[1] = -1;
- for (int i = 0; i < mDragOutlines.length; i++) {
- mDragOutlines[i] = new Rect(-1, -1, -1, -1);
- }
- mDragOutlinePaint.setColor(Themes.getAttrColor(context, R.attr.workspaceTextColor));
-
- // When dragging things around the home screens, we show a green outline of
- // where the item will land. The outlines gradually fade out, leaving a trail
- // behind the drag path.
- // Set up all the animations that are used to implement this fading.
- final int duration = res.getInteger(R.integer.config_dragOutlineFadeTime);
- final float fromAlphaValue = 0;
- final float toAlphaValue = (float)res.getInteger(R.integer.config_dragOutlineMaxAlpha);
-
- Arrays.fill(mDragOutlineAlphas, fromAlphaValue);
-
- for (int i = 0; i < mDragOutlineAnims.length; i++) {
- final InterruptibleInOutAnimator anim =
- new InterruptibleInOutAnimator(duration, fromAlphaValue, toAlphaValue);
- anim.getAnimator().setInterpolator(mEaseOutInterpolator);
- final int thisIndex = i;
- anim.getAnimator().addUpdateListener(new AnimatorUpdateListener() {
- public void onAnimationUpdate(ValueAnimator animation) {
- final Bitmap outline = (Bitmap)anim.getTag();
-
- // If an animation is started and then stopped very quickly, we can still
- // get spurious updates we've cleared the tag. Guard against this.
- if (outline == null) {
- if (LOGD) {
- Object val = animation.getAnimatedValue();
- Log.d(TAG, "anim " + thisIndex + " update: " + val +
- ", isStopped " + anim.isStopped());
- }
- // Try to prevent it from continuing to run
- animation.cancel();
- } else {
- mDragOutlineAlphas[thisIndex] = (Float) animation.getAnimatedValue();
- CellLayout.this.invalidate(mDragOutlines[thisIndex]);
- }
- }
- });
- // The animation holds a reference to the drag outline bitmap as long is it's
- // running. This way the bitmap can be GCed when the animations are complete.
- anim.getAnimator().addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- if ((Float) ((ValueAnimator) animation).getAnimatedValue() == 0f) {
- anim.setTag(null);
- }
- }
- });
- mDragOutlineAnims[i] = anim;
- }
-
- mShortcutsAndWidgets = new ShortcutAndWidgetContainer(context, mContainerType);
- mShortcutsAndWidgets.setCellDimensions(mCellWidth, mCellHeight, mCountX, mCountY);
- addView(mShortcutsAndWidgets);
- }
6).FolderGridOrganizer.java //展开文件夹显示的计算逻辑类,文件夹图标呈现是网格状,此类主要给文件夹各应用图标制定显示规则,eg: 3*3 、4*4
- /**
- * Note: must call {@link #setFolderInfo(FolderInfo)} manually for verifier to work.
- */
- public FolderGridOrganizer(InvariantDeviceProfile profile) {
- mMaxCountX = profile.numFolderColumns;
- mMaxCountY = profile.numFolderRows;
- mMaxItemsPerPage = mMaxCountX * mMaxCountY;
- }
-
- /**
- * Updates the organizer with the provided folder info
- */
- public FolderGridOrganizer setFolderInfo(FolderInfo info) {
- return setContentSize(info.contents.size());
- }
7). LoaderTask.java //继承Runnable,加载各个模块Task的显示类,如workspace工作区icon、所有应用icon的初始化工作
- public LoaderTask(LauncherAppState app, AllAppsList bgAllAppsList, BgDataModel dataModel,
- LoaderResults results) {
- mApp = app;
- mBgAllAppsList = bgAllAppsList;
- mBgDataModel = dataModel;
- mResults = results;
-
- mLauncherApps = mApp.getContext().getSystemService(LauncherApps.class);
- mUserManager = mApp.getContext().getSystemService(UserManager.class);
- mUserCache = UserCache.INSTANCE.get(mApp.getContext());
- mSessionHelper = InstallSessionHelper.INSTANCE.get(mApp.getContext());
- mIconCache = mApp.getIconCache();
- }
8).PackageUpdatedTask.java //继承BaseModelUpdateTask,实际也是Runnable,PMS安装应用后更新Launcher图标及逻辑的实现类
- * or when a user availability changes.
- */
- public class PackageUpdatedTask extends BaseModelUpdateTask {
-
- private static final boolean DEBUG = false;
- private static final String TAG = "PackageUpdatedTask";
-
- public static final int OP_NONE = 0;
- public static final int OP_ADD = 1;
- public static final int OP_UPDATE = 2;
- public static final int OP_REMOVE = 3; // uninstalled
- public static final int OP_UNAVAILABLE = 4; // external media unmounted
- public static final int OP_SUSPEND = 5; // package suspended
- public static final int OP_UNSUSPEND = 6; // package unsuspended
- public static final int OP_USER_AVAILABILITY_CHANGE = 7; // user available/unavailable
9). BaseIconFactory.java //Launcher icon的工厂类,控制icon UI展示(eg:图标白边控制)
- protected BaseIconFactory(Context context, int fillResIconDpi, int iconBitmapSize,
- boolean shapeDetection) {
- mContext = context.getApplicationContext();
- mShapeDetection = shapeDetection;
- mFillResIconDpi = fillResIconDpi;
- mIconBitmapSize = iconBitmapSize;
-
- mPm = mContext.getPackageManager();
- mColorExtractor = new ColorExtractor();
-
- mCanvas = new Canvas();
- mCanvas.setDrawFilter(new PaintFlagsDrawFilter(DITHER_FLAG, FILTER_BITMAP_FLAG));
- clear();
- }
10). SecondaryDropTarget.java //继承自ButtonDropTarget,实际也是TextView,长按APP icon的操作类,对icon进行移动、删除、移除、取消、卸载等操作
- public SecondaryDropTarget(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- mCacheExpireAlarm = new Alarm();
- mStatsLogManager = StatsLogManager.newInstance(context);
- }
-
- @Override
- protected void onAttachedToWindow() {
- super.onAttachedToWindow();
- if (mHadPendingAlarm) {
- mCacheExpireAlarm.setAlarm(CACHE_EXPIRE_TIMEOUT);
- mCacheExpireAlarm.setOnAlarmListener(this);
- mHadPendingAlarm = false;
- }
- }
11).PortraitStatesTouchController.java //继承自AbstractStateChangeTouchController,纵向控制抽屉式All应用界面的触摸类,用于处理纵向UI中各种状态转换
- public PortraitStatesTouchController(Launcher l, boolean allowDragToOverview) {
- super(l, SingleAxisSwipeDetector.VERTICAL);
- mOverviewPortraitStateTouchHelper = new PortraitOverviewStateTouchHelper(l);
- mAllowDragToOverview = allowDragToOverview;
- }
-
- @Override
- protected boolean canInterceptTouch(MotionEvent ev) {
- if (mCurrentAnimation != null) {
- if (mFinishFastOnSecondTouch) {
- mCurrentAnimation.getAnimationPlayer().end();
- }
-
- AllAppsTransitionController allAppsController = mLauncher.getAllAppsController();
- if (ev.getY() >= allAppsController.getShiftRange() * allAppsController.getProgress()) {
- // If we are already animating from a previous state, we can intercept as long as
- // the touch is below the current all apps progress (to allow for double swipe).
- return true;
- }
- // Otherwise, make sure everything is settled and don't intercept so they can scroll
- // recents, dismiss a task, etc.
- if (mAtomicAnim != null) {
- mAtomicAnim.end();
- }
- return false;
- }
- if (mLauncher.isInState(ALL_APPS)) {
- // In all-apps only listen if the container cannot scroll itself
- if (!mLauncher.getAppsView().shouldContainerScroll(ev)) {
- return false;
- }
- } else if (mLauncher.isInState(OVERVIEW)) {
- if (!mOverviewPortraitStateTouchHelper.canInterceptTouch(ev)) {
- return false;
- }
- } else {
- // If we are swiping to all apps instead of overview, allow it from anywhere.
- boolean interceptAnywhere = mLauncher.isInState(NORMAL) && !mAllowDragToOverview;
- // For all other states, only listen if the event originated below the hotseat height
- if (!interceptAnywhere && !isTouchOverHotseat(mLauncher, ev)) {
- return false;
- }
- }
- if (getTopOpenViewWithType(mLauncher, TYPE_ACCESSIBLE | TYPE_ALL_APPS_EDU) != null) {
- return false;
- }
- return true;
- }
12).OverviewToAllAppsTouchController.java //继承自PortraitStatesTouchController,横向控制抽屉式All应用界面的触摸控制器
- public OverviewToAllAppsTouchController(Launcher l) {
- super(l, true /* allowDragToOverview */);
- }
-
- @Override
- protected boolean canInterceptTouch(MotionEvent ev) {
- if (mCurrentAnimation != null) {
- // If we are already animating from a previous state, we can intercept.
- return true;
- }
- if (AbstractFloatingView.getTopOpenView(mLauncher) != null) {
- return false;
- }
- if (mLauncher.isInState(ALL_APPS)) {
- // In all-apps only listen if the container cannot scroll itself
- return mLauncher.getAppsView().shouldContainerScroll(ev);
- } else if (mLauncher.isInState(NORMAL)) {
- return (ev.getEdgeFlags() & Utilities.EDGE_NAV_BAR) == 0;
- } else if (mLauncher.isInState(OVERVIEW)) {
- RecentsView rv = mLauncher.getOverviewPanel();
- return ev.getY() > (rv.getBottom() - rv.getPaddingBottom());
- } else {
- return false;
- }
- }
-
- @Override
- protected LauncherState getTargetState(LauncherState fromState, boolean isDragTowardPositive) {
- if (fromState == ALL_APPS && !isDragTowardPositive) {
- // Should swipe down go to OVERVIEW instead?
- return TouchInteractionService.isConnected() ?
- mLauncher.getStateManager().getLastState() : NORMAL;
- } else if (isDragTowardPositive) {
- return ALL_APPS;
- }
- return fromState;
- }
3.部分xml文件解析
1).device_profiles.xml //默认Launcher的网格配置,主要包括一下几点
1'. numRows/numColumns //workspace的行和列
2'.numFolderRows/numFolderColumns //文件夹中配置的行和列
3'.iconImageSize //图标大小
4'.iconTextSize// 图标名称文字大小
5'.numHotseatIcons //hotseat图标的数目
6'.defaultLayoutId //默认选择加载哪个网格xml的配置文件
- <?xml version="1.0" encoding="utf-8"?>
- <!--
- Copyright (C) 2016 The Android Open Source Project
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
- <profiles xmlns:launcher="http://schemas.android.com/apk/res-auto" >
-
- <grid-option
- launcher:name="3_by_3"
- launcher:numRows="3"
- launcher:numColumns="3"
- launcher:numFolderRows="2"
- launcher:numFolderColumns="3"
- launcher:numHotseatIcons="3"
- launcher:dbFile="launcher_3_by_3.db"
- launcher:defaultLayoutId="@xml/default_workspace_3x3" >
-
- <display-option
- launcher:name="Super Short Stubby"
- launcher:minWidthDps="255"
- launcher:minHeightDps="300"
- launcher:iconImageSize="48"
- launcher:iconTextSize="13.0"
- launcher:canBeDefault="true" />
-
- <display-option
- launcher:name="Shorter Stubby"
- launcher:minWidthDps="255"
- launcher:minHeightDps="400"
- launcher:iconImageSize="48"
- launcher:iconTextSize="13.0"
- launcher:canBeDefault="true" />
-
- </grid-option>
-
- <grid-option
- launcher:name="4_by_4"
- launcher:numRows="4"
- launcher:numColumns="4"
- launcher:numFolderRows="3"
- launcher:numFolderColumns="4"
- launcher:numHotseatIcons="4"
- launcher:dbFile="launcher_4_by_4.db"
- launcher:defaultLayoutId="@xml/default_workspace_4x4" >
-
- <display-option
- launcher:name="Short Stubby"
- launcher:minWidthDps="275"
- launcher:minHeightDps="420"
- launcher:iconImageSize="48"
- launcher:iconTextSize="13.0"
- launcher:canBeDefault="true" />
-
- <display-option
- launcher:name="Stubby"
- launcher:minWidthDps="255"
- launcher:minHeightDps="450"
- launcher:iconImageSize="48"
- launcher:iconTextSize="13.0"
- launcher:canBeDefault="true" />
-
- <display-option
- launcher:name="Nexus S"
- launcher:minWidthDps="296"
- launcher:minHeightDps="491.33"
- launcher:iconImageSize="48"
- launcher:iconTextSize="13.0"
- launcher:canBeDefault="true" />
-
- <display-option
- launcher:name="Nexus 4"
- launcher:minWidthDps="359"
- launcher:minHeightDps="567"
- launcher:iconImageSize="54"
- launcher:iconTextSize="13.0"
- launcher:canBeDefault="true" />
-
- <display-option
- launcher:name="Nexus 5"
- launcher:minWidthDps="335"
- launcher:minHeightDps="567"
- launcher:iconImageSize="54"
- launcher:iconTextSize="13.0"
- launcher:canBeDefault="true" />
-
- </grid-option>
-
- <grid-option
- launcher:name="5_by_5"
- launcher:numRows="5"
- launcher:numColumns="5"
- launcher:numFolderRows="4"
- launcher:numFolderColumns="4"
- launcher:numHotseatIcons="5"
- launcher:dbFile="launcher.db"
- launcher:defaultLayoutId="@xml/default_workspace_5x5" >
-
- <display-option
- launcher:name="Large Phone"
- launcher:minWidthDps="406"
- launcher:minHeightDps="694"
- launcher:iconImageSize="56"
- launcher:iconTextSize="14.4"
- launcher:canBeDefault="true" />
-
- <display-option
- launcher:name="Shorter Stubby"
- launcher:minWidthDps="255"
- launcher:minHeightDps="400"
- launcher:iconImageSize="48"
- launcher:iconTextSize="13.0"
- launcher:canBeDefault="true" />
-
- </grid-option>
-
- </profiles>
2).default_workspace_xxx.xml //默认排序各个icon位置的配置文件,包括文件夹默认创建显示及位置

- <favorites xmlns:launcher="http://schemas.android.com/apk/res-auto/com.android.launcher3">
-
- <!-- Hotseat (We use the screen as the position of the item in the hotseat) -->
- <!-- Messaging, [All Apps], Dialer -->
-
- <resolve
- launcher:container="-101"
- launcher:screen="0"
- launcher:x="0"
- launcher:y="0" >
- <favorite launcher:uri="#Intent;action=android.intent.action.MAIN;category=android.intent.category.APP_MESSAGING;end" />
- <favorite launcher:uri="sms:" />
- <favorite launcher:uri="smsto:" />
- <favorite launcher:uri="mms:" />
- <favorite launcher:uri="mmsto:" />
- </resolve>
-
- <!-- All Apps -->
-
- <resolve
- launcher:container="-101"
- launcher:screen="2"
- launcher:x="2"
- launcher:y="0" >
- <favorite launcher:uri="#Intent;action=android.intent.action.DIAL;end" />
- <favorite launcher:uri="tel:123" />
- <favorite launcher:uri="#Intent;action=android.intent.action.CALL_BUTTON;end" />
- </resolve>
-
- <!-- Bottom row -->
- <resolve
- launcher:screen="0"
- launcher:x="0"
- launcher:y="-1" >
- <favorite launcher:uri="#Intent;action=android.intent.action.MAIN;category=android.intent.category.APP_EMAIL;end" />
- <favorite launcher:uri="mailto:" />
- </resolve>
-
- <resolve
- launcher:screen="0"
- launcher:x="1"
- launcher:y="-1" >
- <favorite launcher:uri="#Intent;action=android.intent.action.MAIN;category=android.intent.category.APP_GALLERY;end" />
- <favorite launcher:uri="#Intent;type=images/*;end" />
- </resolve>
-
- <resolve
- launcher:screen="0"
- launcher:x="2"
- launcher:y="-1" >
- <favorite launcher:uri="#Intent;action=android.intent.action.MAIN;category=android.intent.category.APP_MARKET;end" />
- <favorite launcher:uri="market://details?id=com.android.launcher" />
- </resolve>
-
- </favorites>
screen //表示第几屏,eg: 0表示第一屏
x //表示横向的位置,eg: 0表示第一列
y //表示纵向的位置,eg: 0表示第一行

3).folder_shapes.xml //Workspace工作区icon的圆角大小控制配置文件
- <shapes xmlns:launcher="http://schemas.android.com/apk/res-auto" >
-
- <Circle launcher:folderIconRadius="1" />
-
- <!-- Default icon for AOSP -->
- <RoundedSquare launcher:folderIconRadius="0.16" />
-
- <!-- Rounded icon from RRO -->
- <RoundedSquare launcher:folderIconRadius="0.6" />
-
- <!-- Square icon -->
- <RoundedSquare launcher:folderIconRadius="0" />
-
- <TearDrop launcher:folderIconRadius="0.3" />
- <Squircle launcher:folderIconRadius="0.2" />
-
- </shapes>