[图片走丢了]
1、增加全局控制变量 sys.launcher3.is_full_app,用来动态切换
2、增加两套布局,对应有抽屉和无抽屉
3、去除 allAppsButton
4、将 AllAppsContainerView 中的图标加载到 Workspace
5、新安装的 app 自动添加图标到 Workspace
6、禁止 Workspace 图标长按删除选项
7、屏蔽上拉显示抽屉页面手势
8、Workspace 第一屏禁止增加图标
vendor\mediatek\proprietary\packages\apps\Launcher3\src\com\android\launcher3\LauncherAppState.java
private static Context mContext;
public static boolean isDisableAllApps() {
if (mContext != null) {
return Settings.System.getInt(mContext.getContentResolver(),
"sys.launcher3.is_full_app", 0) == 1;
}
return true;
}
vendor\mediatek\proprietary\packages\apps\Launcher3\AndroidManifest-common.xml
AndroidManifest-common.xml 中增加权限
在 SettingsActivity 中增加 SwitchPreference 用以动态修改 sys.launcher3.is_full_app
vendor\mediatek\proprietary\packages\apps\Launcher3\src\com\android\launcher3\SettingsActivity.java
在内部类 LauncherSettingsFragment 中重写 onPreferenceTreeClick() 用以监听 SwitchPreference 点击
/**
* This fragment shows the launcher preferences.
*/
public static class LauncherSettingsFragment extends PreferenceFragment {
.....
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
....
//读取保存的值,初始化 SwitchPreference 的初始状态,是否选中
int isFull = Settings.System.getInt(getActivity().getContentResolver(),
"sys.launcher3.is_full_app", 0);
Log.d("Launcher3", "sys.launcher3.is_full_app="+isFull);
SwitchPreference fullSwitch = (SwitchPreference) findPreference("pref_is_full_app");
fullSwitch.setChecked(isFull==1);
}
//add for change is_full_app value
@Override
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
boolean result = true;
final String key = preference.getKey();
if ("pref_is_full_app".equals(key)) {
boolean checked = ((SwitchPreference) preference).isChecked();
Settings.System.putInt(getActivity().getContentResolver(), "sys.launcher3.is_full_app",
checked ? 1 : 0);
Log.e("Launcher3", "SwitchPreference checked="+checked);
// Value has changed
ProgressDialog.show(getActivity(),
null /* title */,
getActivity().getString(R.string.full_app_override_progress),
true /* indeterminate */,
false /* cancelable */);
new LooperExecutor(LauncherModel.getWorkerLooper()).execute(
new OverrideApplyHandler(getActivity()));
}
return result;
}
}
点击 SwitchPreference 后需要保存 sys.launcher3.is_full_app 新值,同时清除 Launcher3 的缓存,延时启动并结束当前进程
清除缓存方法 clearApplicationUserData 在 Launcher3 中编译报错,所以通过发送广播到 Setting 中进行真正的清缓存操作
//add for change is_full_app value
private static class OverrideApplyHandler implements Runnable {
private final Context mContext;
private OverrideApplyHandler(Context context) {
mContext = context;
}
@Override
public void run() {
// Clear the icon cache.
LauncherAppState.getInstance(mContext).getIconCache().clear();
// Wait for it
try {
Thread.sleep(1000);
} catch (Exception e) {
Log.e("Launcher3", "Error waiting", e);
}
// Schedule an alarm before we kill ourself.
Intent homeIntent = new Intent(Intent.ACTION_MAIN)
.addCategory(Intent.CATEGORY_HOME)
.setPackage(mContext.getPackageName())
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent pi = PendingIntent.getActivity(mContext, 42,
homeIntent, PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT);
mContext.getSystemService(AlarmManager.class).setExact(
AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime() + 50, pi);
//clear data will kill process
Intent intent = new Intent("com.android.action.CLEAR_APP_DATA");
intent.putExtra("pkgName", "com.android.launcher3");
intent.addFlags(0x01000000);
mContext.sendBroadcast(intent);
Log.i("Launcher3", "Clearing user data com.android.launcher3");
// Kill process
android.os.Process.killProcess(android.os.Process.myPid());
}
}
vendor\mediatek\proprietary\packages\apps\Launcher3\res\xml\launcher_preferences.xml
<SwitchPreference
android:key="pref_is_full_app"
android:title="@string/is_full_app_title"
android:summary="@string/is_full_app_desc"
android:defaultValue="false"
android:persistent="true" />
对应的 string 文件就不贴了,自己增加下就行
加载布局文件对应的 xml 为 vendor\mediatek\proprietary\packages\apps\Launcher3\res\xml\device_profiles.xml
Launcher3 通过获取 minWidthDps 和 minHeightDps 来确定加载哪一个 profile,我的平板分辨率是 1280*800 的,增加两个 profile 节点
<profile
launcher:name="Tablet"
launcher:minWidthDps="376"
launcher:minHeightDps="586"
launcher:numRows="4"
launcher:numColumns="5"
launcher:numFolderRows="4"
launcher:numFolderColumns="5"
launcher:iconSize="50"
launcher:iconTextSize="11"
launcher:numHotseatIcons="5"
launcher:defaultLayoutId="@xml/default_workspace_tb_5x6"
/>
<profile
launcher:name="Tablet_no_all_app"
launcher:minWidthDps="380"
launcher:minHeightDps="590"
launcher:numRows="4"
launcher:numColumns="5"
launcher:numFolderRows="4"
launcher:numFolderColumns="5"
launcher:iconSize="50"
launcher:iconTextSize="11"
launcher:numHotseatIcons="4"
launcher:defaultLayoutId="@xml/default_workspace_tb_5x6_no_all_app"
/>
对应的你需要在 xml 文件下增加 4 个文件,分别是 default_workspace_tb_5x6.xml dw_hotseat_tb.xml default_workspace_tb_5x6_no_all_app.xml dw_hotseat_tb_no_all_app.xml
这样的好处是你可以自定义不同的布局文件加载内容,上面的配置含义简单说一下,分别是最小宽度、最小高度、布局的行和列、文件夹中布局行和列、图标大小、图标文字大小、HotSeat 个数,加载的布局文件
在 InvariantDeviceProfile() 判断是否需要加载 Tablet_no_all_app profile
vendor\mediatek\proprietary\packages\apps\Launcher3\src\com\android\launcher3\InvariantDeviceProfile.java
public InvariantDeviceProfile(Context context) {
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
DisplayMetrics dm = new DisplayMetrics();
display.getMetrics(dm);
Point smallestSize = new Point();
Point largestSize = new Point();
display.getCurrentSizeRange(smallestSize, largestSize);
// This guarantees that width < height
minWidthDps = Utilities.dpiFromPx(Math.min(smallestSize.x, smallestSize.y), dm);
minHeightDps = Utilities.dpiFromPx(Math.min(largestSize.x, largestSize.y), dm);
Log.i("Launcher3.profiles", "orignalminWidthDps="+minWidthDps + " orignalminHeightDps="+minHeightDps);
//add for load no_all_app xml
if (LauncherAppState.isDisableAllApps()) {
Log.e("Launcher3.profiles", "load no all app profiles");
//对应 device_profiles.xml 中 Tablet_no_all_app 的值
minWidthDps = 380.0f;
minHeightDps = 590.0f;
}
.....
}
vendor\mediatek\proprietary\packages\apps\Launcher3\src\com\android\launcher3\Hotseat.java
将 resetLayout() 中 FeatureFlags.NO_ALL_APPS_ICON 替换为 LauncherAppState.isDisableAllApps()
void resetLayout(boolean hasVerticalHotseat) {
mContent.removeAllViewsInLayout();
mHasVerticalHotseat = hasVerticalHotseat;
InvariantDeviceProfile idp = mLauncher.getDeviceProfile().inv;
if (hasVerticalHotseat) {
mContent.setGridSize(1, idp.numHotseatIcons);
} else {
mContent.setGridSize(idp.numHotseatIcons, 1);
}
//if (!FeatureFlags.NO_ALL_APPS_ICON) {
/// add for check is need allappbutton
if (!LauncherAppState.isDisableAllApps()) {
// Add the Apps button
Context context = getContext();
DeviceProfile grid = mLauncher.getDeviceProfile();
...
}
vendor\mediatek\proprietary\packages\apps\Launcher3\src\com\android\launcher3\model\LoaderTask.java
run() 中增加判断,添加 verifyApplications(), 修改 InstallShortcutReceiver 中 PendingInstallShortcutInfo 为 public
public void run() {
synchronized (this) {
// Skip fast if we are already stopped.
if (mStopped) {
return;
}
}
....
// second step
TraceHelper.partitionSection(TAG, "step 2.1: loading all apps");
loadAllApps();
//add for load all app on workspace
if (LauncherAppState.isDisableAllApps()) {
android.util.Log.e("Launcher3", "verifyApplications()");
verifyApplications();
}
....
}
//add for load all app on workspace
private void verifyApplications() {
final Context context = mApp.getContext();
ArrayList<Pair<ItemInfo, Object>> installQueue = new ArrayList<>();
final List<UserHandle> profiles = mUserManager.getUserProfiles();
for (UserHandle user : profiles) {
final List<LauncherActivityInfo> apps = mLauncherApps.getActivityList(null, user);
ArrayList<InstallShortcutReceiver.PendingInstallShortcutInfo> added = new ArrayList<InstallShortcutReceiver.PendingInstallShortcutInfo>();
synchronized (this) {
for (LauncherActivityInfo app : apps) {
InstallShortcutReceiver.PendingInstallShortcutInfo pendingInstallShortcutInfo = new InstallShortcutReceiver.PendingInstallShortcutInfo(app, context);
added.add(pendingInstallShortcutInfo);
installQueue.add(pendingInstallShortcutInfo.getItemInfo());
}
}
if (!added.isEmpty()) {
mApp.getModel().addAndBindAddedWorkspaceItems(installQueue);
}
}
}
vendor\mediatek\proprietary\packages\apps\Launcher3\src\com\android\launcher3\model\BaseModelUpdateTask.java
注释 run() 中的 return
@Override
public final void run() {
if (!mModel.isModelLoaded()) {
if (DEBUG_TASKS) {
Log.d(TAG, "Ignoring model task since loader is pending=" + this);
}
// Loader has not yet run.
//annotaion for load all app on workspace
// return;
}
execute(mApp, mDataModel, mAllAppsList);
}
vendor\mediatek\proprietary\packages\apps\Launcher3\src\com\android\launcher3\model\PackageUpdatedTask.java
execute() 中增加判断,添加 updateToWorkSpace()
public void execute(LauncherAppState app, BgDataModel dataModel, AllAppsList appsList) {
....
final ArrayList<AppInfo> addedOrModified = new ArrayList<>();
addedOrModified.addAll(appsList.added);
//add for load new install app on workspace
if (LauncherAppState.isDisableAllApps()) {
android.util.Log.e("cczLauncher3", "updateToWorkSpace()");
updateToWorkSpace(context, app, appsList);
}
...
}
//add for load new install app on workspace
public void updateToWorkSpace(Context context, LauncherAppState app , AllAppsList appsList){
ArrayList<Pair<ItemInfo, Object>> installQueue = new ArrayList<>();
final List<UserHandle> profiles = UserManagerCompat.getInstance(context).getUserProfiles();
ArrayList<InstallShortcutReceiver.PendingInstallShortcutInfo> added
= new ArrayList<InstallShortcutReceiver.PendingInstallShortcutInfo>();
for (UserHandle user : profiles) {
final List<LauncherActivityInfo> apps = LauncherAppsCompat.getInstance(context).getActivityList(null, user);
synchronized (this) {
for (LauncherActivityInfo info : apps) {
for (AppInfo appInfo : appsList.added) {
if(info.getComponentName().equals(appInfo.componentName)){
InstallShortcutReceiver.PendingInstallShortcutInfo mPendingInstallShortcutInfo
= new InstallShortcutReceiver.PendingInstallShortcutInfo(info,context);
added.add(mPendingInstallShortcutInfo);
}
}
}
}
}
if (!added.isEmpty()) {
app.getModel().addAndBindAddedWorkspaceItems(
new InstallShortcutReceiver.LazyShortcutsProvider(context.getApplicationContext(), added));
}
}
vendor\mediatek\proprietary\packages\apps\Launcher3\src\com\android\launcher3\DeleteDropTarget.java
在 setTextBasedOnDragSource() 、setControlTypeBasedOnDragSource()、onAccessibilityDrop() 中分别增加判断是否需要删除图标
方法一、直接将 supportsDrop() 返回 false
@Override
protected boolean supportsDrop(DragSource source, ItemInfo info) {
//return true;
return false;// change false
}
方法二、拖拽至删除区域放手时不处理
//public void setTextBasedOnDragSource(DragSource dragSource) {
public void setTextBasedOnDragSource(DropTarget.DragObject dragObject) {
if (!TextUtils.isEmpty(mText)) {
mText = getResources().getString(/*dragSource*/dragObject.dragSource.supportsDeleteDropTarget()
? R.string.remove_drop_target_label
: android.R.string.cancel);
//add for hide deletedroptarget
if (LauncherAppState.isDisableAllApps()) {
android.util.Log.e("Launcher3", "hide delete drop target");
mText = getResources().getString(isCanDrop(dragObject.dragInfo)
? R.string.remove_drop_target_label
: android.R.string.cancel);
}
requestLayout();
}
}
public static void removeWorkspaceOrFolderItem(Launcher launcher, ItemInfo item, View view) {
// Remove the item from launcher and the db, we can ignore the containerInfo in this call
// because we already remove the drag view from the folder (if the drag originated from
// a folder) in Folder.beginDrag()
//add if juge is need remove item from workspace
if (!LauncherAppState.isDisableAllApps() || isCanDrop(item)) {
launcher.removeItem(view, item, true /* deleteFromDb */);
launcher.getWorkspace().stripEmptyScreens();
launcher.getDragLayer().announceForAccessibility(launcher.getString(R.string.item_removed));
}
}
private static boolean isCanDrop(ItemInfo item){
return !(item.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION ||
item.itemType == LauncherSettings.Favorites.ITEM_TYPE_FOLDER);
}
vendor\mediatek\proprietary\packages\apps\Launcher3\src\com\android\launcher3\dragndrop\DragController.java
drop() 中增加判断,取消当前拖拽操作
private void drop(DropTarget dropTarget, Runnable flingAnimation) {
....
boolean accepted = false;
if (dropTarget != null) {
dropTarget.onDragExit(mDragObject);
if (dropTarget.acceptDrop(mDragObject)) {
if (flingAnimation != null) {
flingAnimation.run();
} else {
dropTarget.onDrop(mDragObject, mOptions);
}
accepted = true;
//add for cancel canceldroptarget handle
if (LauncherAppState.isDisableAllApps() && dropTarget instanceof DeleteDropTarget &&
isNeedCancelDrag(mDragObject.dragInfo)) {
cancelDrag();
}
}
}
...
}
private boolean isNeedCancelDrag(ItemInfo item){
return (item.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION ||
item.itemType == LauncherSettings.Favorites.ITEM_TYPE_FOLDER);
}
vendor\mediatek\proprietary\packages\apps\Launcher3\src\com\android\launcher3\allapps\AllAppsTransitionController.java
canInterceptTouch() 中增加判断是否直接拦截
@Override
public boolean onDrag(float displacement, float velocity) {
Log.e("Launcher3", "onDrag()");
if (true) return true;
//add for forbidden workspace drag change GradientView alph
if (mAppsView == null) {
return false; // early termination.
}
mContainerVelocity = velocity;
float shift = Math.min(Math.max(0, mShiftStart + displacement), mShiftRange);
setProgress(shift / mShiftRange);
return true;
}
@Override
public void onDragEnd(float velocity, boolean fling) {
Log.e("Launcher3", "onDragEnd()");
//add for forbidden workspace drag change GradientView alph
if (true){
if (velocity < 0) {
mLauncher.showWorkspace(true);
}
return;
}
//add for forbidden workspace drag change GradientView alph
if (mAppsView == null) {
return; // early termination.
}
final int containerType = mTouchEventStartedOnHotseat
? ContainerType.HOTSEAT : ContainerType.WORKSPACE;
.....
}
vendor\mediatek\proprietary\packages\apps\LauncherSip\src\com\android\launcher3\Workspace.java
图标最后放置是会调用 onDrop() 方法,在此处进行处理,screenId 为 0 则禁止放置,让图标回位到原始位置
//静止增加 icon
public void onDrop(final DragObject d) {
mDragViewVisualCenter = d.getVisualCenter(mDragViewVisualCenter);
CellLayout dropTargetLayout = mDropToLayout;
....
//cczheng add screenId > 0 for first screen forbidden add icon
if (screenId > 0 && foundCell) {
if (getScreenIdForPageIndex(mCurrentPage) != screenId && !hasMovedIntoHotseat) {
snapScreen = getPageIndexForScreenId(screenId);
snapToPage(snapScreen);
}
} else {//cczheng add screenId == 0 for first screen forbidden add icon
if (screenId == 0 || !returnToOriginalCellToPreventShuffling) {
onNoCellFound(dropTargetLayout);
}
// If we can't find a drop location, we return the item to its original position
CellLayout.LayoutParams lp = (CellLayout.LayoutParams) cell.getLayoutParams();
mTargetCell[0] = lp.cellX;
mTargetCell[1] = lp.cellY;
CellLayout layout = (CellLayout) cell.getParent().getParent();
layout.markCellsAsOccupiedForView(cell);
}
.....
}
//禁止增加 weight
public boolean acceptDrop(DragObject d) {
// If it's an external drop (e.g. from All Apps), check if it should be accepted
CellLayout dropTargetLayout = mDropToLayout;
if (d.dragSource != this) {
// Don't accept the drop if we're not over a screen at time of drop
if (dropTargetLayout == null) {
return false;
}
....
//cczheng add screenId > 0 for first screen forbidden add weight
long screenId = getIdForScreen(dropTargetLayout);
// Don't accept the drop if there's no room for the item
if (screenId==0 || !foundCell) {
Log.e("Launcher3", "acceptDrop() onNoCellFound");
onNoCellFound(dropTargetLayout);
return false;
}
}
long screenId = getIdForScreen(dropTargetLayout);
if (screenId == EXTRA_EMPTY_SCREEN_ID) {
commitExtraEmptyScreen();
}
return true;
}
Workspace 第一屏图标禁止拖动
vendor\mediatek\proprietary\packages\apps\LauncherSip\src\com\android\launcher3\Launcher.java
在 onLongClick() 中进行 screenId==0 判断
@Override
public boolean onLongClick(View v) {
if (!isDraggingEnabled()) return false;
if (isWorkspaceLocked()) return false;
if (mState != State.WORKSPACE) return false;
....
CellLayout.CellInfo longClickCellInfo = null;
View itemUnderLongClick = null;
if (v.getTag() instanceof ItemInfo) {
ItemInfo info = (ItemInfo) v.getTag();
longClickCellInfo = new CellLayout.CellInfo(v, info);
itemUnderLongClick = longClickCellInfo.cell;
mPendingRequestArgs = null;
}
//cczheng add , hotseat can't be moved and deleted [S]
if(longClickCellInfo != null && (longClickCellInfo.container==-101
|| longClickCellInfo.screenId==0)){
return false;
}//E
...
}