将Launcher3改为单层模式,这是android系统定制遇到的一个常见的需求。下面我将介绍一下我再MTK源码下将Luancher3改为单层的步骤和方法,以及解决一些bug。希望这个总结对读者有一点启发和用途。
一、打开Launcher3的单层开关
MTK源码的Launcher3本省就有单层开关。这个开关就是LauncherAppState.java的public static boolean isDisableAllApps()方法,只要把这个方法的返回值改为true即可。做好这一步,重新编译安装后,Launcher3就变为单层模式了。
二、虽然Launcher3变成了单层,但是带来了几个问题
1、重新启动Launcher3,安装一个第三方应用,这时应用可以被卸载;但是安装第三方应用后,再重启后就不能被卸载(长按不会出现卸载提示)。通过debug断点查看Launcher3的卸载过程,发现Launcher3是否能够删除主要是根据ShortcutInfo或Appinfo的flags来决定。但是,通过查看代码可以看到在LauncherModel.java(数据库操作类)通过方法getShortcutInfo获取ShortcutInfo时,flags没有被设置数字,一直为默认值0,因而无法删除应用。原生代码的两层UI对应的数据分别是ShortcutInfo和Appinfo,查询AppInfo时不同于ShortcutInfo,flags值会有赋值。同时,根据安装第三方应用后不重启可以被删除的情况判断,安装广播时得到新的ShoertcurInfo会对flags赋值。所以解决的办法就有了:修改getShortcutInfo方法,在方法中实现当isDisableAllApps == true时对flags进行赋值。赋值的方法参照对AppInfo的flags赋值的方法,最后方法如下:
try {
final String packageName = componentName.getPackageName();
PackageInfo pi = manager.getPackageInfo(packageName, 0);
if (!pi.applicationInfo.enabled) {
return null;
}
final int appFlags = manager.getApplicationInfo(packageName, 0).flags;
if ((appFlags & android.content.pm.ApplicationInfo.FLAG_SYSTEM) == 0) {
info.flags |= AppInfo.DOWNLOADED_FLAG;
if ((appFlags & android.content.pm.ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) {
info.flags |= AppInfo.UPDATED_SYSTEM_APP_FLAG;
}
}
} catch (NameNotFoundException e) {
return null;
}
。。。。。。。。。。。。。。。。。。。。。。
打包、安装、运行,还是报错了。。。。。
查看日志,发现问题是DeleteDropTarget.java下:
onDragStart(DragSource source, Object info, int dragAction)实现图标更换:增加判断条件
boolean useUninstallLabel = LauncherAppState.isDisableAllApps() &&
(info instanceof ShortcutInfo);
boolean useDeleteLabel = !useUninstallLabel && (info instanceof LauncherAppWidgetInfo);
completeDrop(DragObject d)实现卸载操作:将11111111111111处改为2222222222222222
else if (isWorkspaceOrFolderApplication(d)) {
if (LauncherLog.DEBUG) {
LauncherLog.d(TAG, "33isWorkspaceOrFolderApplication");
}
//LauncherModel.deleteItemFromDatabase(mLauncher, item);//1111111111111111111111
///{22222222222
ShortcutInfo shortcut = (ShortcutInfo) item;
ComponentName componentName = shortcut.intent.getComponent();
AppInfo appInfo = (AppInfo) shortcut.makeAppInfo();
mLauncher.startApplicationUninstallActivity(componentName, appInfo.flags,
appInfo.user);
///22222222222}
}
private boolean isWorkspaceOrFolderApplication(DragObject d) {
return isDragSourceWorkspaceOrFolder(d) && (d.dragInfo instanceof ShortcutInfo);
}
2、修改桌面为循环滚动:\packages\apps\Launcher3\ext\src\com\mediatek\launcher3\ext\DefaultWorkspaceExt.java
@Override
public boolean supportAppListCycleSliding() {
LauncherLog.d(TAG, "default supportAppListCycleSliding called.");
return true;
}
3、修改后,添加appwidget后,workspace缩小后的状态不会变回来。解决的办法/packages/apps/Launcher3/src/com/android/launcher3/Launcher.java下
/**
* Zoom the camera back into the workspace, hiding 'fromView'.
* This is the opposite of showAppsCustomizeHelper.
* @param animated If true, the transition will be animated.
*/
private void hideAppsCustomizeHelper(Workspace.State toState, final boolean animated,
final boolean springLoaded, final Runnable onCompleteRunnable) {
==================================此处没有修改=========================================
if (animated && initialized) {
==================================此处没有修改=========================================
} else {
//yuanhcn add============================================================================================
mStateAnimation = LauncherAnimUtils.createAnimatorSet();
if (workspaceAnim != null) {
mStateAnimation.play(workspaceAnim);
}
final AppsCustomizePagedView content = (AppsCustomizePagedView)
fromView.findViewById(R.id.apps_customize_pane_content);
Log.i(TAG, "content visible: " + (content.getVisibility() == View.VISIBLE));
Log.i(TAG, "mAppsCustomizeTabHost visible: " + (mAppsCustomizeTabHost.getVisibility() == View.VISIBLE));
final View page = content.getPageAt(content.getNextPage());
Log.i(TAG, "content.getNextPage: " + content.getNextPage());
// We need to hide side pages of the Apps / Widget tray to avoid some ugly edge cases
int count = content.getChildCount();
for (int i = 0; i < count; i++) {
View child = content.getChildAt(i);
if (child != page) {
child.setVisibility(View.INVISIBLE);
}
}
final View revealView = fromView.findViewById(R.id.fake_page);
// hideAppsCustomizeHelper is called in some cases when it is already hidden
// don't perform all these no-op animations. In particularly, this was causing
// the all-apps button to pop in and out.
if (fromView.getVisibility() == View.VISIBLE) {
AppsCustomizePagedView.ContentType contentType = content.getContentType();
final boolean isWidgetTray =
contentType == AppsCustomizePagedView.ContentType.Widgets;
if (isWidgetTray) {
revealView.setBackground(res.getDrawable(R.drawable.quantum_panel_dark));
} else {
/*ltz modify begin*/
if(Launcher.DISABLE_APPLIST_WHITE_BG) {
revealView.setBackground(null);
} else {
revealView.setBackground(res.getDrawable(R.drawable.quantum_panel));
}
/*ltz modify end*/
}
int width = revealView.getMeasuredWidth();
int height = revealView.getMeasuredHeight();
float revealRadius = (float) Math.sqrt((width * width) / 4 + (height * height) / 4);
// Hide the real page background, and swap in the fake one
revealView.setVisibility(View.VISIBLE);
content.setPageBackgroundsVisible(false);
//////yuanhcn add final View allAppsButton = getAllAppsButton();replece allAppsButton by mHotseat
final View allAppsButton = getHotseat();
revealView.setTranslationY(0);
int[] allAppsToPanelDelta = Utilities.getCenterDeltaInScreenSpace(revealView,
allAppsButton, null);
float xDrift = 0;
float yDrift = 0;
if (material) {
yDrift = isWidgetTray ? height / 2 : allAppsToPanelDelta[1];
xDrift = isWidgetTray ? 0 : allAppsToPanelDelta[0];
} else {
yDrift = 2 * height / 3;
xDrift = 0;
}
Log.i(TAG, "yDrift: " + yDrift + ",xDrift: " + xDrift + ", isWidgetTray: " + isWidgetTray);
revealView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
TimeInterpolator decelerateInterpolator = material ?
new LogDecelerateInterpolator(100, 0) :
new DecelerateInterpolator(1f);
// The vertical motion of the apps panel should be delayed by one frame
// from the conceal animation in order to give the right feel. We correpsondingly
// shorten the duration so that the slide and conceal end at the same time.
ObjectAnimator panelDriftY = LauncherAnimUtils.ofFloat(revealView, "translationY",
0, yDrift);
panelDriftY.setDuration(revealDuration - SINGLE_FRAME_DELAY);
panelDriftY.setStartDelay(itemsAlphaStagger + SINGLE_FRAME_DELAY);
panelDriftY.setInterpolator(decelerateInterpolator);
mStateAnimation.play(panelDriftY);
ObjectAnimator panelDriftX = LauncherAnimUtils.ofFloat(revealView, "translationX",
0, xDrift);
panelDriftX.setDuration(revealDuration - SINGLE_FRAME_DELAY);
panelDriftX.setStartDelay(itemsAlphaStagger + SINGLE_FRAME_DELAY);
panelDriftX.setInterpolator(decelerateInterpolator);
// mStateAnimation.play(panelDriftX);
if (isWidgetTray || !material) {
float finalAlpha = material ? 0.4f : 0f;
revealView.setAlpha(1f);
ObjectAnimator panelAlpha = LauncherAnimUtils.ofFloat(revealView, "alpha",
1f, finalAlpha);
panelAlpha.setDuration(material ? revealDuration : 150);
panelAlpha.setInterpolator(decelerateInterpolator);
panelAlpha.setStartDelay(material ? 0 : itemsAlphaStagger + SINGLE_FRAME_DELAY);
mStateAnimation.play(panelAlpha);
}
if (page != null) {
page.setLayerType(View.LAYER_TYPE_HARDWARE, null);
ObjectAnimator pageDrift = LauncherAnimUtils.ofFloat(page, "translationY",
0, yDrift);
// page.setTranslationY(0);
pageDrift.setDuration(revealDuration - SINGLE_FRAME_DELAY);
pageDrift.setInterpolator(decelerateInterpolator);
pageDrift.setStartDelay(itemsAlphaStagger + SINGLE_FRAME_DELAY);
// mStateAnimation.play(pageDrift);
page.setAlpha(1f);
ObjectAnimator itemsAlpha = LauncherAnimUtils.ofFloat(page, "alpha", 1f, 0f);
itemsAlpha.setDuration(/*100*/60);
itemsAlpha.setInterpolator(decelerateInterpolator);
mStateAnimation.play(itemsAlpha);
}
View pageIndicators = fromView.findViewById(R.id.apps_customize_page_indicator);
// pageIndicators.setAlpha(1f);
pageIndicators.setAlpha(0f);
ObjectAnimator indicatorsAlpha =
LauncherAnimUtils.ofFloat(pageIndicators, "alpha", 0f);
indicatorsAlpha.setDuration(revealDuration);
indicatorsAlpha.setInterpolator(new DecelerateInterpolator(1.5f));
// mStateAnimation.play(indicatorsAlpha);
width = revealView.getMeasuredWidth();
if (material) {
if (!isWidgetTray) {
allAppsButton.setVisibility(View.INVISIBLE);
}
int allAppsButtonSize = LauncherAppState.getInstance().
getDynamicGrid().getDeviceProfile().allAppsButtonVisualSize;
float finalRadius = isWidgetTray ? 0 : allAppsButtonSize / 2;
Animator reveal =
LauncherAnimUtils.createCircularReveal(revealView, width / 2,
height / 2, revealRadius, finalRadius);
reveal.setInterpolator(new LogDecelerateInterpolator(100, 0));
reveal.setDuration(revealDuration);
reveal.setStartDelay(itemsAlphaStagger);
reveal.addListener(new AnimatorListenerAdapter() {
public void onAnimationEnd(Animator animation) {
revealView.setVisibility(View.INVISIBLE);
if (!isWidgetTray) {
allAppsButton.setVisibility(View.VISIBLE);
}
}
});
mStateAnimation.play(reveal);
}
dispatchOnLauncherTransitionPrepare(fromView, animated, true);
dispatchOnLauncherTransitionPrepare(toView, animated, true);
mAppsCustomizeContent.stopScrolling();
}
mStateAnimation.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
fromView.setVisibility(View.GONE);
dispatchOnLauncherTransitionEnd(fromView, animated, true);
dispatchOnLauncherTransitionEnd(toView, animated, true);
if (onCompleteRunnable != null) {
onCompleteRunnable.run();
}
revealView.setLayerType(View.LAYER_TYPE_NONE, null);
if (page != null) {
page.setLayerType(View.LAYER_TYPE_NONE, null);
}
content.setPageBackgroundsVisible(true);
// Unhide side pages
int count = content.getChildCount();
for (int i = 0; i < count; i++) {
View child = content.getChildAt(i);
child.setVisibility(View.VISIBLE);
}
// Reset page transforms
if (page != null) {
page.setTranslationX(0);
page.setTranslationY(0);
page.setAlpha(1);
}
content.setCurrentPage(content.getNextPage());
mAppsCustomizeContent.updateCurrentPageScroll();
// This can hold unnecessary references to views.
mStateAnimation = null;
}
});
final AnimatorSet stateAnimation = mStateAnimation;
final Runnable startAnimRunnable = new Runnable() {
public void run() {
// Check that mStateAnimation hasn't changed while
// we waited for a layout/draw pass
if (mStateAnimation != stateAnimation)
return;
dispatchOnLauncherTransitionStart(fromView, animated, false);
dispatchOnLauncherTransitionStart(toView, animated, false);
if (Utilities.isLmpOrAbove()) {
for (int i = 0; i < layerViews.size(); i++) {
View v = layerViews.get(i);
if (v != null) {
if (Utilities.isViewAttachedToWindow(v)) v.buildLayer();
}
}
}
mStateAnimation.start();
}
};
fromView.post(startAnimRunnable);
//yuanhcnadd
//yuanhcn delete
// fromView.setVisibility(View.GONE);
// dispatchOnLauncherTransitionPrepare(fromView, animated, true);
// dispatchOnLauncherTransitionStart(fromView, animated, true);
// dispatchOnLauncherTransitionEnd(fromView, animated, true);
// dispatchOnLauncherTransitionPrepare(toView, animated, true);
// dispatchOnLauncherTransitionStart(toView, animated, true);
// dispatchOnLauncherTransitionEnd(toView, animated, true);
//yuanhcn delete
}
}