Android Launcher3简介

article/2025/11/7 3:17:48

一.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

  @Overrideprotected 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 layermDragLayer.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 RTLmWorkspace.lockWallpaperToDefaultPage();mWorkspace.bindAndInitFirstWorkspaceScreen(null /* recycled qsb */);mDragController.addDragListener(mWorkspace);// Get the search/delete/uninstall barmDropTargetBar = mDragLayer.findViewById(R.id.drop_target_bar);// Setup AppsmAppsView = findViewById(R.id.apps_view);// Setup ScrimmScrimView = 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 traysetMotionEventSplittingEnabled(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 resourcesfloat 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 constantsthis.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_popupdefaultIconSize = 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 outmDragCell[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 runanimation.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() {@Overridepublic 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; // uninstalledpublic static final int OP_UNAVAILABLE = 4; // external media unmountedpublic static final int OP_SUSPEND = 5; // package suspendedpublic static final int OP_UNSUSPEND = 6; // package unsuspendedpublic 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);}@Overrideprotected 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;}@Overrideprotected 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 itselfif (!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 heightif (!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 */);}@Overrideprotected 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 itselfreturn 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;}}@Overrideprotected 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 ProjectLicensed 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 athttp://www.apache.org/licenses/LICENSE-2.0Unless required by applicable law or agreed to in writing, softwaredistributed 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 andlimitations under the License.
--><profiles xmlns:launcher="http://schemas.android.com/apk/res-auto" ><grid-optionlauncher: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-optionlauncher:name="Super Short Stubby"launcher:minWidthDps="255"launcher:minHeightDps="300"launcher:iconImageSize="48"launcher:iconTextSize="13.0"launcher:canBeDefault="true" /><display-optionlauncher:name="Shorter Stubby"launcher:minWidthDps="255"launcher:minHeightDps="400"launcher:iconImageSize="48"launcher:iconTextSize="13.0"launcher:canBeDefault="true" /></grid-option><grid-optionlauncher: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-optionlauncher:name="Short Stubby"launcher:minWidthDps="275"launcher:minHeightDps="420"launcher:iconImageSize="48"launcher:iconTextSize="13.0"launcher:canBeDefault="true" /><display-optionlauncher:name="Stubby"launcher:minWidthDps="255"launcher:minHeightDps="450"launcher:iconImageSize="48"launcher:iconTextSize="13.0"launcher:canBeDefault="true" /><display-optionlauncher:name="Nexus S"launcher:minWidthDps="296"launcher:minHeightDps="491.33"launcher:iconImageSize="48"launcher:iconTextSize="13.0"launcher:canBeDefault="true" /><display-optionlauncher:name="Nexus 4"launcher:minWidthDps="359"launcher:minHeightDps="567"launcher:iconImageSize="54"launcher:iconTextSize="13.0"launcher:canBeDefault="true" /><display-optionlauncher:name="Nexus 5"launcher:minWidthDps="335"launcher:minHeightDps="567"launcher:iconImageSize="54"launcher:iconTextSize="13.0"launcher:canBeDefault="true" /></grid-option><grid-optionlauncher: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-optionlauncher:name="Large Phone"launcher:minWidthDps="406"launcher:minHeightDps="694"launcher:iconImageSize="56"launcher:iconTextSize="14.4"launcher:canBeDefault="true" /><display-optionlauncher: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 --><resolvelauncher: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 --><resolvelauncher: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 --><resolvelauncher: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><resolvelauncher: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><resolvelauncher: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>


http://chatgpt.dhexx.cn/article/428s7wVU.shtml

相关文章

详细理解准确率、精准率、召回率,F1值等评价指标的含义

转载文章 原博客地址&#xff1a;详解准确率、精确率、召回率、F1值等评价指标的含义 机器学习问题之中&#xff0c;通常需要建立模型来解决具体问题&#xff0c;但对于模型的好坏&#xff0c;也就是模型的泛化能力&#xff0c;如何进行评估&#xff1f;我们可以定一些评价指标…

详解准确率、精确率、召回率、F1值等评价指标的含义

机器学习问题之中&#xff0c;通常需要建立模型来解决具体问题&#xff0c;但对于模型的好坏&#xff0c;也就是模型的泛化能力&#xff0c;如何进行评估呢&#xff1f; 很简单&#xff0c;我们可以定一些评价指标&#xff0c;来度量模型的优劣。比如准确率、精确率、召回率、…

分类性能评价指标——精确率,召回率,F1值详细解释

分类性能的评价指标 准确率 准确率是全部参与分类的文本中&#xff0c;与人工分类结果吻合的文本所占的比例。 即&#xff1a;预测与真实标签相同的比例 A c c u r a c y T P T N T P T N F P F N Accuracy\frac{TPTN}{TPTNFPFN} AccuracyTPTNFPFNTPTN​ 精确率 也称…

准确率、精确率、召回率、F1值

1.TP、TN、FP、FN 先粘一个官方形式的。 用新冠来举例理解。下方正方形为样本&#xff0c;其中 圆的部分认定为检测后是阳性的&#xff0c;其余部分为检测为阴性的&#xff08;但是现在的情况是检测并不完全准确&#xff0c;有可能检测时阴性&#xff0c;但实际上已经有新冠…

机器学习中的二分类问题评价指标之精确率、召回率、F1值通俗理解

引言&#xff1a;对于分类问题&#xff0c;我们在评估一个模型的好坏时&#xff0c;通常想到的是把该模型在测试集上分类结果正确的样本数量比上测试集的样本数量的比值结果&#xff0c;即准确率&#xff08;精确率&#xff09;作为评价准则。但除此之外&#xff0c;还有精确率…

【转】一些因素对F1值的影响

截自&#xff1a;https://blog.csdn.net/qq_27590277/article/details/88374695 https://blog.csdn.net/qq_27590277/article/details/88367082 一些因素对F1值的影响 如果还没了解F1值的话&#xff0c;这里有我之前写的通俗易懂的文章 详谈P(查准率)&#xff0c;R(查全率)&…

keras计算precision、recall、F1值

近期写课程作业&#xff0c;需要用Keras搭建网络层&#xff0c;跑实验时需要计算precision&#xff0c;recall和F1值&#xff0c;在前几年&#xff0c;Keras没有更新时&#xff0c;我用的代码是直接取训练期间的预测标签&#xff0c;然后和真实标签之间计算求解&#xff0c;代码…

F1值(F-Measure)、准确率(Precision)、召回率(Recall) 菜鸡版理解

前置知识&#xff1a; T&#xff08;True&#xff09;&#xff1a; 正确的 F (False) &#xff1a; 错误的 P (Positive) : 正向的/积极的 N (Negetive): 负向的/消极的 则&#xff1a; TP&#xff1a;正确的 预测了 正向的 FN&#xff1a;错误的 预测了 负向的 FP&#xff1a…

准确率、精确率、召回率、F1值学习笔记

一、TN、TP、TN、FP、FN概念 TP与TN都是分对了情况&#xff0c;TP是正类&#xff0c;TN是负类。则推断出&#xff0c;FP是错误的正类&#xff0c;FN是错误的负类。 举例&#xff1a;我们需要从一个班级中的人中寻找所有女生,如果把这个任务当成一个分类器的话,那么女生就是我们…

为何选用F1值(调和平均数)衡量P与R?

二分类问题的性能度量为何选用 F 1 F_1 F1​ 值&#xff1f; 已知混淆矩阵 prediction positiveprediction negativeactuality positiveTrue Positive(TP)False Negative(FN)actuality negativeFalse Positive(FP)True Negative(TN) 其中&#xff1a;Precise&#xff08;精…

精确度/召回率/F1值/Micro-F1和Macro-F1的理解

如下图所示&#xff0c;假设有若干张图片&#xff0c;其中12张是狗的图片其余是猫的图片&#xff0e;现在利用程序去识别狗的图片&#xff0c;结果在识别出的8张图片中有5张是狗的图片&#xff0c;3张是猫的图片&#xff08;属于误报&#xff09;&#xff0e; 图中&#xff0c;…

混淆矩阵、精确率、召回率、F1值、ROC曲线、AUC曲线

假设一个分类器A&#xff0c;分类器A的作用是告诉你一张图片是不是汉堡&#xff0c;我们如果想知道这个分类器的效果到底好不好&#xff0c;如何做&#xff1f; 最简单的方法就是将手机里所有的图片都扔给分类器A看&#xff0c;让分类器告诉我们哪些是汉堡 我们无法直观的看到…

python实现计算精度、召回率和F1值

python实现计算精度、召回率和F1值 摘要&#xff1a;在深度学习的分类任务中&#xff0c;对模型的评估或测试时需要计算其在验证集或测试集上的预测精度&#xff08;prediction/accuracy&#xff09;、召回率&#xff08;recall&#xff09;和F1值。本文首先简要介绍如何计算精…

模型评价指标—F1值

最近空余时间在参加数字中国创新大赛&#xff0c;比赛规则是根据模型的F1值对参赛者进行排名。为了更深刻地理解这个指标&#xff0c;我最近对它做了一些梳理&#xff0c;现在把它分享给更多有需要的人图片。最近在参赛时也发现了一个问题&#xff0c;就是算法在训练集上完全拟…

精确率、召回率、F1 值、ROC、AUC等分类模型评价指标含义与作用详解

文章目录 摘要一、精确率、召回率、F函数、准确率和错误率1、定义2、区别与应用 二、ROC曲线、P-R曲线、AUC1、P-R曲线2、ROC曲线3、AUC 摘要 在涉及机器学习领域的分类问题时&#xff08;尤其是衡量推荐系统性能时&#xff09;&#xff0c;经常会遇到诸如准确率、召回率、ROC…

机器学习F1值的概念

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 一、什么是F1-score二、计算过程1.首先定义以下几个概念&#xff1a;2.通过第一步的统计值计算每个类别下的precision和recall3. 通过第二步计算结果计算每个类别下…

【数学建模】分类问题的几种常见指标(一)——准确率、召回率、F1值

分类问题的几种常见指标&#xff08;一&#xff09;——错误率、精度、准确率、召回率、F1值 前言1 错误率与精度2 准确率与召回率2.1 混淆矩阵2.2 准确率&#xff08;Precision&#xff09;2.3 召回率&#xff08;Recall&#xff09; 3 F1值&#xff08;F1-score&#xff09;4…

准确率、精确率、召回率、F1值、ROC/AUC整理笔记

文章目录 前言 一、TP、TN、FP、FN概念二、准确率、精确率&#xff08;精准率&#xff09;、召回率、F1值1.准确率&#xff08;Accuracy&#xff09;2.精确率&#xff08;Precision&#xff09;查准率3.召回率&#xff08;Recall&#xff09;查全率4.F1值&#xff08;H-mean值&…

准确率、精准率、召回率和F1值详解

专业术语的中英文对照表 英文名准确率Accuracy精准率Precise召回率RecallF1值F1 measure Precise和Recall是广泛应用在信息检索和统计学分类领域的两个度量值&#xff0c;用来评价结果的质量&#xff1b;F1 measure是综合Precise和Recall两个指标的评估指标&#xff0c;用于综…

matlab color选取(颜色对照表)

只看前面部分&#xff0c;后面的颜色不用看 参考链接&#xff1a;https://wenku.baidu.com/view/111e6c47773231126edb6f1aff00bed5b8f3734e.html