Merge changes from topic "taskbar-hotseat" into sc-dev
* changes: Update taskbar to add extra hotseat items instead of recent apps Add support for having more hotseat icons in the DB than we show
This commit is contained in:
@@ -1,21 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2021 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.
|
||||
-->
|
||||
|
||||
<View
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="@dimen/taskbar_divider_thickness"
|
||||
android:layout_height="@dimen/taskbar_divider_height"
|
||||
android:background="@color/taskbar_divider" />
|
||||
@@ -27,5 +27,4 @@
|
||||
|
||||
<!-- Taskbar -->
|
||||
<color name="taskbar_background">#101010</color>
|
||||
<color name="taskbar_divider">#C0C0C0</color>
|
||||
</resources>
|
||||
@@ -134,7 +134,5 @@
|
||||
<dimen name="taskbar_icon_drag_icon_size">54dp</dimen>
|
||||
<!-- Note that this applies to both sides of all icons, so visible space is double this. -->
|
||||
<dimen name="taskbar_icon_spacing">8dp</dimen>
|
||||
<dimen name="taskbar_divider_thickness">1dp</dimen>
|
||||
<dimen name="taskbar_divider_height">32dp</dimen>
|
||||
<dimen name="taskbar_folder_margin">16dp</dimen>
|
||||
</resources>
|
||||
|
||||
@@ -108,6 +108,7 @@ public abstract class BaseQuickstepLauncher extends Launcher
|
||||
SysUINavigationMode.INSTANCE.get(this).removeModeChangeListener(this);
|
||||
if (mTaskbarController != null) {
|
||||
mTaskbarController.cleanup();
|
||||
mTaskbarController = null;
|
||||
}
|
||||
|
||||
super.onDestroy();
|
||||
|
||||
@@ -89,7 +89,7 @@ public class HotseatEduController {
|
||||
ArrayList<WorkspaceItemInfo> putIntoFolder = new ArrayList<>();
|
||||
|
||||
//separate folders and items that can get in folders
|
||||
for (int i = 0; i < mLauncher.getDeviceProfile().inv.numHotseatIcons; i++) {
|
||||
for (int i = 0; i < mLauncher.getDeviceProfile().numShownHotseatIcons; i++) {
|
||||
View view = mHotseat.getChildAt(i, 0);
|
||||
if (view == null) continue;
|
||||
ItemInfo info = (ItemInfo) view.getTag();
|
||||
@@ -188,7 +188,7 @@ public class HotseatEduController {
|
||||
.getInt(LauncherSettings.Settings.EXTRA_VALUE);
|
||||
mNewScreens = IntArray.wrap(pageId);
|
||||
}
|
||||
for (int i = 0; i < mLauncher.getDeviceProfile().inv.numHotseatIcons; i++) {
|
||||
for (int i = 0; i < mLauncher.getDeviceProfile().numShownHotseatIcons; i++) {
|
||||
View child = mHotseat.getChildAt(i, 0);
|
||||
if (child == null || child.getTag() == null) continue;
|
||||
ItemInfo tag = (ItemInfo) child.getTag();
|
||||
@@ -224,7 +224,7 @@ public class HotseatEduController {
|
||||
|
||||
void showDimissTip() {
|
||||
if (mHotseat.getShortcutsAndWidgets().getChildCount()
|
||||
< mLauncher.getDeviceProfile().inv.numHotseatIcons) {
|
||||
< mLauncher.getDeviceProfile().numShownHotseatIcons) {
|
||||
Snackbar.show(mLauncher, R.string.hotseat_tip_gaps_filled,
|
||||
R.string.hotseat_prediction_settings, null,
|
||||
() -> mLauncher.startActivity(getSettingsIntent()));
|
||||
|
||||
@@ -88,7 +88,7 @@ public class HotseatEduDialog extends AbstractSlideInView implements Insettable
|
||||
Rect padding = grid.getHotseatLayoutPadding();
|
||||
|
||||
mSampleHotseat.getLayoutParams().height = grid.cellHeightPx;
|
||||
mSampleHotseat.setGridSize(grid.inv.numHotseatIcons, 1);
|
||||
mSampleHotseat.setGridSize(grid.numShownHotseatIcons, 1);
|
||||
mSampleHotseat.setPadding(padding.left, 0, padding.right, 0);
|
||||
|
||||
Button turnOnBtn = findViewById(R.id.turn_predictions_on);
|
||||
@@ -178,7 +178,7 @@ public class HotseatEduDialog extends AbstractSlideInView implements Insettable
|
||||
}
|
||||
|
||||
private void populatePreview(List<WorkspaceItemInfo> predictions) {
|
||||
for (int i = 0; i < mLauncher.getDeviceProfile().inv.numHotseatIcons; i++) {
|
||||
for (int i = 0; i < mLauncher.getDeviceProfile().numShownHotseatIcons; i++) {
|
||||
WorkspaceItemInfo info = predictions.get(i);
|
||||
PredictedAppIcon icon = PredictedAppIcon.createIcon(mSampleHotseat, info);
|
||||
icon.setEnabled(false);
|
||||
@@ -194,7 +194,7 @@ public class HotseatEduDialog extends AbstractSlideInView implements Insettable
|
||||
*/
|
||||
public void show(List<WorkspaceItemInfo> predictions) {
|
||||
if (getParent() != null
|
||||
|| predictions.size() < mLauncher.getDeviceProfile().inv.numHotseatIcons
|
||||
|| predictions.size() < mLauncher.getDeviceProfile().numShownHotseatIcons
|
||||
|| mHotseatEduController == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -33,10 +33,10 @@ import android.view.ViewGroup;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.android.launcher3.DeviceProfile;
|
||||
import com.android.launcher3.DragSource;
|
||||
import com.android.launcher3.DropTarget;
|
||||
import com.android.launcher3.Hotseat;
|
||||
import com.android.launcher3.InvariantDeviceProfile;
|
||||
import com.android.launcher3.LauncherSettings;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.anim.AnimationSuccessListener;
|
||||
@@ -68,7 +68,7 @@ import java.util.stream.Collectors;
|
||||
* pinning of predicted apps and manages replacement of predicted apps with user drag.
|
||||
*/
|
||||
public class HotseatPredictionController implements DragController.DragListener,
|
||||
SystemShortcut.Factory<QuickstepLauncher>, InvariantDeviceProfile.OnIDPChangeListener,
|
||||
SystemShortcut.Factory<QuickstepLauncher>, DeviceProfile.OnDeviceProfileChangeListener,
|
||||
DragSource, ViewGroup.OnHierarchyChangeListener {
|
||||
|
||||
private static final int FLAG_UPDATE_PAUSED = 1 << 0;
|
||||
@@ -115,10 +115,10 @@ public class HotseatPredictionController implements DragController.DragListener,
|
||||
public HotseatPredictionController(QuickstepLauncher launcher) {
|
||||
mLauncher = launcher;
|
||||
mHotseat = launcher.getHotseat();
|
||||
mHotSeatItemsCount = mLauncher.getDeviceProfile().inv.numHotseatIcons;
|
||||
mHotSeatItemsCount = mLauncher.getDeviceProfile().numShownHotseatIcons;
|
||||
mLauncher.getDragController().addDragListener(this);
|
||||
|
||||
launcher.getDeviceProfile().inv.addOnChangeListener(this);
|
||||
launcher.addOnDeviceProfileChangeListener(this);
|
||||
mHotseat.getShortcutsAndWidgets().setOnHierarchyChangeListener(this);
|
||||
}
|
||||
|
||||
@@ -281,7 +281,7 @@ public class HotseatPredictionController implements DragController.DragListener,
|
||||
* Unregisters callbacks and frees resources
|
||||
*/
|
||||
public void destroy() {
|
||||
mLauncher.getDeviceProfile().inv.removeOnChangeListener(this);
|
||||
mLauncher.removeOnDeviceProfileChangeListener(this);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -446,8 +446,8 @@ public class HotseatPredictionController implements DragController.DragListener,
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onIdpChanged(int changeFlags, InvariantDeviceProfile profile) {
|
||||
this.mHotSeatItemsCount = profile.numHotseatIcons;
|
||||
public void onDeviceProfileChanged(DeviceProfile profile) {
|
||||
this.mHotSeatItemsCount = profile.numShownHotseatIcons;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -44,7 +44,7 @@ public class HotseatRestoreHelper {
|
||||
.getBinder(LauncherSettings.Settings.EXTRA_VALUE)) {
|
||||
InvariantDeviceProfile idp = LauncherAppState.getIDP(context);
|
||||
GridBackupTable backupTable = new GridBackupTable(context,
|
||||
transaction.getDb(), idp.numHotseatIcons, idp.numColumns,
|
||||
transaction.getDb(), idp.numDatabaseHotseatIcons, idp.numColumns,
|
||||
idp.numRows);
|
||||
backupTable.createCustomBackupTable(HYBRID_HOTSEAT_BACKUP_TABLE);
|
||||
transaction.commit();
|
||||
@@ -69,7 +69,7 @@ public class HotseatRestoreHelper {
|
||||
}
|
||||
InvariantDeviceProfile idp = LauncherAppState.getIDP(context);
|
||||
GridBackupTable backupTable = new GridBackupTable(context,
|
||||
transaction.getDb(), idp.numHotseatIcons, idp.numColumns,
|
||||
transaction.getDb(), idp.numDatabaseHotseatIcons, idp.numColumns,
|
||||
idp.numRows);
|
||||
backupTable.restoreFromCustomBackupTable(HYBRID_HOTSEAT_BACKUP_TABLE, true);
|
||||
transaction.commit();
|
||||
|
||||
@@ -111,7 +111,7 @@ public class QuickstepModelDelegate extends ModelDelegate implements OnIDPChange
|
||||
mDataModel.extraItems.put(CONTAINER_PREDICTION, mAllAppsState.items);
|
||||
|
||||
WorkspaceItemFactory hotseatFactory =
|
||||
new WorkspaceItemFactory(mApp, ums, pinnedShortcuts, mIDP.numHotseatIcons);
|
||||
new WorkspaceItemFactory(mApp, ums, pinnedShortcuts, mIDP.numDatabaseHotseatIcons);
|
||||
mHotseatState.items.setItems(
|
||||
mHotseatState.storage.read(mApp.getContext(), hotseatFactory, ums.allUsers::get));
|
||||
mDataModel.extraItems.put(CONTAINER_HOTSEAT_PREDICTION, mHotseatState.items);
|
||||
@@ -211,7 +211,7 @@ public class QuickstepModelDelegate extends ModelDelegate implements OnIDPChange
|
||||
registerPredictor(mHotseatState, apm.createAppPredictionSession(
|
||||
new AppPredictionContext.Builder(context)
|
||||
.setUiSurface("hotseat")
|
||||
.setPredictedTargetCount(mIDP.numHotseatIcons)
|
||||
.setPredictedTargetCount(mIDP.numDatabaseHotseatIcons)
|
||||
.setExtras(convertDataModelToAppTargetBundle(context, mDataModel))
|
||||
.build()));
|
||||
|
||||
|
||||
@@ -25,7 +25,6 @@ import static com.android.systemui.shared.system.WindowManagerWrapper.ITYPE_EXTR
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.app.ActivityOptions;
|
||||
import android.content.ComponentName;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
@@ -56,9 +55,6 @@ import com.android.systemui.shared.recents.model.Task;
|
||||
import com.android.systemui.shared.system.ActivityManagerWrapper;
|
||||
import com.android.systemui.shared.system.WindowManagerWrapper;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Interfaces with Launcher/WindowManager/SystemUI to determine what to show in TaskbarView.
|
||||
*/
|
||||
@@ -76,17 +72,11 @@ public class TaskbarController {
|
||||
private final TaskbarStateHandler mTaskbarStateHandler;
|
||||
private final TaskbarAnimationController mTaskbarAnimationController;
|
||||
private final TaskbarHotseatController mHotseatController;
|
||||
private final TaskbarRecentsController mRecentsController;
|
||||
private final TaskbarDragController mDragController;
|
||||
|
||||
// Initialized in init().
|
||||
private WindowManager.LayoutParams mWindowLayoutParams;
|
||||
|
||||
// Contains all loaded Tasks, not yet deduped from Hotseat items.
|
||||
private List<Task> mLatestLoadedRecentTasks;
|
||||
// Contains all loaded Hotseat items.
|
||||
private ItemInfo[] mLatestLoadedHotseatItems;
|
||||
|
||||
private @Nullable Animator mAnimator;
|
||||
private boolean mIsAnimatingToLauncher;
|
||||
|
||||
@@ -106,8 +96,6 @@ public class TaskbarController {
|
||||
createTaskbarAnimationControllerCallbacks());
|
||||
mHotseatController = new TaskbarHotseatController(mLauncher,
|
||||
createTaskbarHotseatControllerCallbacks());
|
||||
mRecentsController = new TaskbarRecentsController(mLauncher,
|
||||
createTaskbarRecentsControllerCallbacks());
|
||||
mDragController = new TaskbarDragController(mLauncher);
|
||||
}
|
||||
|
||||
@@ -220,24 +208,6 @@ public class TaskbarController {
|
||||
@Override
|
||||
public void updateHotseatItems(ItemInfo[] hotseatItemInfos) {
|
||||
mTaskbarViewInApp.updateHotseatItems(hotseatItemInfos);
|
||||
mLatestLoadedHotseatItems = hotseatItemInfos;
|
||||
dedupeAndUpdateRecentItems();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private TaskbarRecentsControllerCallbacks createTaskbarRecentsControllerCallbacks() {
|
||||
return new TaskbarRecentsControllerCallbacks() {
|
||||
@Override
|
||||
public void updateRecentItems(ArrayList<Task> recentTasks) {
|
||||
mLatestLoadedRecentTasks = recentTasks;
|
||||
dedupeAndUpdateRecentItems();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateRecentTaskAtIndex(int taskIndex, Task task) {
|
||||
mTaskbarViewInApp.updateRecentTaskAtIndex(taskIndex, task);
|
||||
mTaskbarViewOnHome.updateRecentTaskAtIndex(taskIndex, task);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -246,16 +216,13 @@ public class TaskbarController {
|
||||
* Initializes the Taskbar, including adding it to the screen.
|
||||
*/
|
||||
public void init() {
|
||||
mTaskbarViewInApp.init(mHotseatController.getNumHotseatIcons(),
|
||||
mRecentsController.getNumRecentIcons());
|
||||
mTaskbarViewOnHome.init(mHotseatController.getNumHotseatIcons(),
|
||||
mRecentsController.getNumRecentIcons());
|
||||
mTaskbarViewInApp.init(mHotseatController.getNumHotseatIcons());
|
||||
mTaskbarViewOnHome.init(mHotseatController.getNumHotseatIcons());
|
||||
mTaskbarContainerView.init(mTaskbarViewInApp);
|
||||
addToWindowManager();
|
||||
mTaskbarStateHandler.setTaskbarCallbacks(createTaskbarStateHandlerCallbacks());
|
||||
mTaskbarAnimationController.init();
|
||||
mHotseatController.init();
|
||||
mRecentsController.init();
|
||||
|
||||
setWhichTaskbarViewIsVisible(mLauncher.hasBeenResumed()
|
||||
? mTaskbarViewOnHome
|
||||
@@ -292,7 +259,6 @@ public class TaskbarController {
|
||||
mTaskbarStateHandler.setTaskbarCallbacks(null);
|
||||
mTaskbarAnimationController.cleanup();
|
||||
mHotseatController.cleanup();
|
||||
mRecentsController.cleanup();
|
||||
|
||||
setWhichTaskbarViewIsVisible(null);
|
||||
}
|
||||
@@ -425,53 +391,6 @@ public class TaskbarController {
|
||||
return mTaskbarViewInApp.isDraggingItem() || mTaskbarViewOnHome.isDraggingItem();
|
||||
}
|
||||
|
||||
private void dedupeAndUpdateRecentItems() {
|
||||
if (mLatestLoadedRecentTasks == null || mLatestLoadedHotseatItems == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final int numRecentIcons = mRecentsController.getNumRecentIcons();
|
||||
|
||||
// From most recent to least recently opened.
|
||||
List<Task> dedupedTasksInDescendingOrder = new ArrayList<>();
|
||||
for (int i = mLatestLoadedRecentTasks.size() - 1; i >= 0; i--) {
|
||||
Task task = mLatestLoadedRecentTasks.get(i);
|
||||
boolean isTaskInHotseat = false;
|
||||
for (ItemInfo hotseatItem : mLatestLoadedHotseatItems) {
|
||||
if (hotseatItem == null) {
|
||||
continue;
|
||||
}
|
||||
ComponentName hotseatActivity = hotseatItem.getTargetComponent();
|
||||
if (hotseatActivity != null && task.key.sourceComponent.getPackageName()
|
||||
.equals(hotseatActivity.getPackageName())) {
|
||||
isTaskInHotseat = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!isTaskInHotseat) {
|
||||
dedupedTasksInDescendingOrder.add(task);
|
||||
if (dedupedTasksInDescendingOrder.size() == numRecentIcons) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TaskbarView expects an array of all the recent tasks to show, in the order to show them.
|
||||
// So we create an array of the proper size, then fill it in such that the most recent items
|
||||
// are at the end. If there aren't enough elements to fill the array, leave them null.
|
||||
Task[] tasksArray = new Task[numRecentIcons];
|
||||
for (int i = 0; i < tasksArray.length; i++) {
|
||||
Task task = i >= dedupedTasksInDescendingOrder.size()
|
||||
? null
|
||||
: dedupedTasksInDescendingOrder.get(i);
|
||||
tasksArray[tasksArray.length - 1 - i] = task;
|
||||
}
|
||||
|
||||
mTaskbarViewInApp.updateRecentTasks(tasksArray);
|
||||
mTaskbarViewOnHome.updateRecentTasks(tasksArray);
|
||||
mRecentsController.loadIconsForTasks(tasksArray);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Whether the given View is in the same window as Taskbar.
|
||||
*/
|
||||
@@ -573,12 +492,4 @@ public class TaskbarController {
|
||||
protected interface TaskbarHotseatControllerCallbacks {
|
||||
void updateHotseatItems(ItemInfo[] hotseatItemInfos);
|
||||
}
|
||||
|
||||
/**
|
||||
* Contains methods that TaskbarRecentsController can call to interface with TaskbarController.
|
||||
*/
|
||||
protected interface TaskbarRecentsControllerCallbacks {
|
||||
void updateRecentItems(ArrayList<Task> recentTasks);
|
||||
void updateRecentTaskAtIndex(int taskIndex, Task task);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ public class TaskbarHotseatController {
|
||||
mLauncher = launcher;
|
||||
mHotseat = mLauncher.getHotseat();
|
||||
mTaskbarCallbacks = taskbarCallbacks;
|
||||
mNumHotseatIcons = mLauncher.getDeviceProfile().inv.numHotseatIcons;
|
||||
mNumHotseatIcons = mLauncher.getDeviceProfile().numShownHotseatIcons;
|
||||
}
|
||||
|
||||
protected void init() {
|
||||
|
||||
@@ -1,120 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.
|
||||
*/
|
||||
package com.android.launcher3.taskbar;
|
||||
|
||||
import com.android.launcher3.BaseQuickstepLauncher;
|
||||
import com.android.quickstep.RecentsModel;
|
||||
import com.android.quickstep.util.CancellableTask;
|
||||
import com.android.systemui.shared.recents.model.Task;
|
||||
import com.android.systemui.shared.system.TaskStackChangeListener;
|
||||
import com.android.systemui.shared.system.TaskStackChangeListeners;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Works with TaskbarController to update the TaskbarView's Recent items.
|
||||
*/
|
||||
public class TaskbarRecentsController {
|
||||
|
||||
private final int mNumRecentIcons = 2;
|
||||
private final BaseQuickstepLauncher mLauncher;
|
||||
private final TaskbarController.TaskbarRecentsControllerCallbacks mTaskbarCallbacks;
|
||||
private final RecentsModel mRecentsModel;
|
||||
|
||||
private final TaskStackChangeListener mTaskStackChangeListener = new TaskStackChangeListener() {
|
||||
@Override
|
||||
public void onTaskStackChanged() {
|
||||
reloadRecentTasksIfNeeded();
|
||||
}
|
||||
};
|
||||
|
||||
// TODO: add TaskbarVisualsChangedListener as well (for calendar/clock?)
|
||||
|
||||
// Used to keep track of the last requested task list id, so that we do not request to load the
|
||||
// tasks again if we have already requested it and the task list has not changed
|
||||
private int mTaskListChangeId = -1;
|
||||
|
||||
// The current background requests to load the task icons
|
||||
private CancellableTask[] mIconLoadRequests = new CancellableTask[mNumRecentIcons];
|
||||
|
||||
private boolean mIsAlive;
|
||||
|
||||
public TaskbarRecentsController(BaseQuickstepLauncher launcher,
|
||||
TaskbarController.TaskbarRecentsControllerCallbacks taskbarCallbacks) {
|
||||
mLauncher = launcher;
|
||||
mTaskbarCallbacks = taskbarCallbacks;
|
||||
mRecentsModel = RecentsModel.INSTANCE.get(mLauncher);
|
||||
}
|
||||
|
||||
protected void init() {
|
||||
mIsAlive = true;
|
||||
TaskStackChangeListeners.getInstance().registerTaskStackListener(mTaskStackChangeListener);
|
||||
reloadRecentTasksIfNeeded();
|
||||
}
|
||||
|
||||
protected void cleanup() {
|
||||
mIsAlive = false;
|
||||
TaskStackChangeListeners.getInstance().unregisterTaskStackListener(
|
||||
mTaskStackChangeListener);
|
||||
cancelAllPendingIconLoadTasks();
|
||||
}
|
||||
|
||||
private void reloadRecentTasksIfNeeded() {
|
||||
if (!mRecentsModel.isTaskListValid(mTaskListChangeId)) {
|
||||
mTaskListChangeId = mRecentsModel.getTasks(this::onRecentTasksChanged);
|
||||
}
|
||||
}
|
||||
|
||||
private void cancelAllPendingIconLoadTasks() {
|
||||
for (int i = 0; i < mIconLoadRequests.length; i++) {
|
||||
if (mIconLoadRequests[i] != null) {
|
||||
mIconLoadRequests[i].cancel();
|
||||
}
|
||||
mIconLoadRequests[i] = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void onRecentTasksChanged(ArrayList<Task> tasks) {
|
||||
if (mIsAlive) {
|
||||
mTaskbarCallbacks.updateRecentItems(tasks);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* For each Task, loads its icon from the cache in the background, then calls
|
||||
* {@link TaskbarController.TaskbarRecentsControllerCallbacks#updateRecentTaskAtIndex}.
|
||||
*/
|
||||
protected void loadIconsForTasks(Task[] tasks) {
|
||||
cancelAllPendingIconLoadTasks();
|
||||
for (int i = 0; i < tasks.length; i++) {
|
||||
Task task = tasks[i];
|
||||
if (task == null) {
|
||||
continue;
|
||||
}
|
||||
final int taskIndex = i;
|
||||
mIconLoadRequests[i] = mRecentsModel.getIconCache().updateIconInBackground(
|
||||
task, updatedTask -> onTaskIconLoaded(task, taskIndex));
|
||||
}
|
||||
}
|
||||
|
||||
private void onTaskIconLoaded(Task task, int taskIndex) {
|
||||
mTaskbarCallbacks.updateRecentTaskAtIndex(taskIndex, task);
|
||||
}
|
||||
|
||||
protected int getNumRecentIcons() {
|
||||
return mNumRecentIcons;
|
||||
}
|
||||
}
|
||||
@@ -25,7 +25,6 @@ import android.graphics.Canvas;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.DragEvent;
|
||||
import android.view.MotionEvent;
|
||||
@@ -47,7 +46,6 @@ import com.android.launcher3.model.data.FolderInfo;
|
||||
import com.android.launcher3.model.data.ItemInfo;
|
||||
import com.android.launcher3.model.data.WorkspaceItemInfo;
|
||||
import com.android.launcher3.views.ActivityContext;
|
||||
import com.android.systemui.shared.recents.model.Task;
|
||||
|
||||
/**
|
||||
* Hosts the Taskbar content such as Hotseat and Recent Apps. Drawn on top of other apps.
|
||||
@@ -55,8 +53,6 @@ import com.android.systemui.shared.recents.model.Task;
|
||||
public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconParent, Insettable {
|
||||
|
||||
private final ColorDrawable mBackgroundDrawable;
|
||||
private final int mDividerWidth;
|
||||
private final int mDividerHeight;
|
||||
private final int mIconTouchSize;
|
||||
private final boolean mIsRtl;
|
||||
private final int mTouchSlop;
|
||||
@@ -74,9 +70,6 @@ public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconPa
|
||||
private LayoutTransition mLayoutTransition;
|
||||
private int mHotseatStartIndex;
|
||||
private int mHotseatEndIndex;
|
||||
private View mHotseatRecentsDivider;
|
||||
private int mRecentsStartIndex;
|
||||
private int mRecentsEndIndex;
|
||||
|
||||
// Delegate touches to the closest view if within mIconTouchSize.
|
||||
private boolean mDelegateTargeted;
|
||||
@@ -105,8 +98,6 @@ public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconPa
|
||||
|
||||
Resources resources = getResources();
|
||||
mBackgroundDrawable = (ColorDrawable) getBackground();
|
||||
mDividerWidth = resources.getDimensionPixelSize(R.dimen.taskbar_divider_thickness);
|
||||
mDividerHeight = resources.getDimensionPixelSize(R.dimen.taskbar_divider_height);
|
||||
mIconTouchSize = resources.getDimensionPixelSize(R.dimen.taskbar_icon_touch_size);
|
||||
mIsRtl = Utilities.isRtl(resources);
|
||||
mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
|
||||
@@ -119,18 +110,11 @@ public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconPa
|
||||
mItemMarginLeftRight = Math.round(mItemMarginLeftRight * mNonIconScale);
|
||||
}
|
||||
|
||||
protected void init(int numHotseatIcons, int numRecentIcons) {
|
||||
protected void init(int numHotseatIcons) {
|
||||
mHotseatStartIndex = 0;
|
||||
mHotseatEndIndex = mHotseatStartIndex + numHotseatIcons - 1;
|
||||
updateHotseatItems(new ItemInfo[numHotseatIcons]);
|
||||
|
||||
int dividerIndex = mHotseatEndIndex + 1;
|
||||
mHotseatRecentsDivider = addDivider(dividerIndex);
|
||||
|
||||
mRecentsStartIndex = dividerIndex + 1;
|
||||
mRecentsEndIndex = mRecentsStartIndex + numRecentIcons - 1;
|
||||
updateRecentTasks(new Task[numRecentIcons]);
|
||||
|
||||
mLayoutTransition = new LayoutTransition();
|
||||
addUpdateListenerForAllLayoutTransitions(() -> {
|
||||
if (getLayoutTransition() == mLayoutTransition) {
|
||||
@@ -165,7 +149,6 @@ public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconPa
|
||||
endAllLayoutTransitionAnimators();
|
||||
setLayoutTransition(null);
|
||||
removeAllViews();
|
||||
mHotseatRecentsDivider = null;
|
||||
}
|
||||
|
||||
private void endAllLayoutTransitionAnimators() {
|
||||
@@ -248,8 +231,6 @@ public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconPa
|
||||
}
|
||||
updateHotseatItemVisibility(hotseatView);
|
||||
}
|
||||
|
||||
updateHotseatRecentsDividerVisibility();
|
||||
}
|
||||
|
||||
protected void updateHotseatItemsVisibility() {
|
||||
@@ -273,95 +254,6 @@ public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconPa
|
||||
}
|
||||
}
|
||||
|
||||
private View addDivider(int dividerIndex) {
|
||||
View divider = inflate(R.layout.taskbar_divider);
|
||||
LayoutParams lp = new LayoutParams(mDividerWidth, mDividerHeight);
|
||||
lp.setMargins(mItemMarginLeftRight, 0, mItemMarginLeftRight, 0);
|
||||
divider.setScaleX(mNonIconScale);
|
||||
divider.setScaleY(mNonIconScale);
|
||||
addView(divider, dividerIndex, lp);
|
||||
return divider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inflates/binds the Recents items to show in the Taskbar given their Tasks.
|
||||
*/
|
||||
protected void updateRecentTasks(Task[] tasks) {
|
||||
for (int i = 0; i < tasks.length; i++) {
|
||||
Task task = tasks[i];
|
||||
int recentsIndex = mRecentsStartIndex + i;
|
||||
View recentsView = getChildAt(recentsIndex);
|
||||
|
||||
// Inflate empty icon Views.
|
||||
if (recentsView == null) {
|
||||
BubbleTextView btv = (BubbleTextView) inflate(R.layout.taskbar_app_icon);
|
||||
LayoutParams lp = new LayoutParams(btv.getIconSize(), btv.getIconSize());
|
||||
lp.setMargins(mItemMarginLeftRight, 0, mItemMarginLeftRight, 0);
|
||||
recentsView = btv;
|
||||
addView(recentsView, recentsIndex, lp);
|
||||
}
|
||||
|
||||
// Apply the Task, or hide the view if there is none for a given index.
|
||||
if (recentsView instanceof BubbleTextView && task != null) {
|
||||
applyTaskToBubbleTextView((BubbleTextView) recentsView, task);
|
||||
recentsView.setVisibility(VISIBLE);
|
||||
recentsView.setOnClickListener(mControllerCallbacks.getItemOnClickListener());
|
||||
recentsView.setOnLongClickListener(
|
||||
mControllerCallbacks.getItemOnLongClickListener());
|
||||
} else {
|
||||
recentsView.setVisibility(GONE);
|
||||
recentsView.setOnClickListener(null);
|
||||
recentsView.setOnLongClickListener(null);
|
||||
}
|
||||
}
|
||||
|
||||
updateHotseatRecentsDividerVisibility();
|
||||
}
|
||||
|
||||
private void applyTaskToBubbleTextView(BubbleTextView btv, Task task) {
|
||||
if (task.icon != null) {
|
||||
Drawable icon = task.icon.getConstantState().newDrawable().mutate();
|
||||
btv.applyIconAndLabel(icon, task.titleDescription);
|
||||
}
|
||||
btv.setTag(task);
|
||||
}
|
||||
|
||||
protected void updateRecentTaskAtIndex(int taskIndex, Task task) {
|
||||
View taskView = getChildAt(mRecentsStartIndex + taskIndex);
|
||||
if (taskView instanceof BubbleTextView) {
|
||||
applyTaskToBubbleTextView((BubbleTextView) taskView, task);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Make the divider VISIBLE between the Hotseat and Recents if there is at least one icon in
|
||||
* each, otherwise make it GONE.
|
||||
*/
|
||||
private void updateHotseatRecentsDividerVisibility() {
|
||||
if (mHotseatRecentsDivider == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
boolean hasAtLeastOneHotseatItem = false;
|
||||
for (int i = mHotseatStartIndex; i <= mHotseatEndIndex; i++) {
|
||||
if (getChildAt(i).getVisibility() != GONE) {
|
||||
hasAtLeastOneHotseatItem = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
boolean hasAtLeastOneRecentItem = false;
|
||||
for (int i = mRecentsStartIndex; i <= mRecentsEndIndex; i++) {
|
||||
if (getChildAt(i).getVisibility() != GONE) {
|
||||
hasAtLeastOneRecentItem = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mHotseatRecentsDivider.setVisibility(hasAtLeastOneHotseatItem && hasAtLeastOneRecentItem
|
||||
? VISIBLE : GONE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
boolean handled = delegateTouchIfNecessary(event);
|
||||
|
||||
@@ -149,6 +149,7 @@ public class SettingsChangeLogger implements
|
||||
|
||||
SharedPreferences prefs = getPrefs(mContext);
|
||||
StatsLogManager.LauncherEvent gridSizeChangedEvent = null;
|
||||
// TODO(b/184981523): This doesn't work for 2-panel grid, which has 6 hotseat icons
|
||||
switch (prefs.getInt(KEY_MIGRATION_SRC_HOTSEAT_COUNT, -1)) {
|
||||
case 5:
|
||||
gridSizeChangedEvent = LAUNCHER_GRID_SIZE_5;
|
||||
|
||||
@@ -175,6 +175,9 @@
|
||||
|
||||
<!-- numAllAppsColumns defaults to GridDisplayOption.numColumns, if not specified -->
|
||||
<attr name="numAllAppsColumns" format="integer" />
|
||||
|
||||
<!-- numShownHotseatIcons defaults to GridDisplayOption.numHotseatIcons, if not specified -->
|
||||
<attr name="numShownHotseatIcons" format="integer" />
|
||||
</declare-styleable>
|
||||
|
||||
<declare-styleable name="CellLayout">
|
||||
|
||||
@@ -127,7 +127,7 @@ public class BackupRestoreTest {
|
||||
{ APP_ICON, SHORTCUT, SHORTCUT, NO__ICON},
|
||||
}}, 2, OLD_WORK_PROFILE_ID);
|
||||
// simulates the creation of backup upon restore
|
||||
new GridBackupTable(RuntimeEnvironment.application, mDb, mIdp.numHotseatIcons,
|
||||
new GridBackupTable(RuntimeEnvironment.application, mDb, mIdp.numDatabaseHotseatIcons,
|
||||
mIdp.numColumns, mIdp.numRows).doBackup(
|
||||
MY_OLD_PROFILE_ID, GridBackupTable.OPTION_REQUIRES_SANITIZATION);
|
||||
// reset favorites table
|
||||
|
||||
@@ -64,7 +64,7 @@ public class GridSizeMigrationTaskTest {
|
||||
mModelHelper.addItem(APP_ICON, 4, HOTSEAT, 0, 0),
|
||||
};
|
||||
|
||||
mIdp.numHotseatIcons = 3;
|
||||
mIdp.numDatabaseHotseatIcons = 3;
|
||||
new GridSizeMigrationTask(mContext, mDb, mValidPackages, false, 5, 3)
|
||||
.migrateHotseat();
|
||||
// First item is dropped as it has the least weight.
|
||||
@@ -81,7 +81,7 @@ public class GridSizeMigrationTaskTest {
|
||||
mModelHelper.addItem(10, 4, HOTSEAT, 0, 0),
|
||||
};
|
||||
|
||||
mIdp.numHotseatIcons = 3;
|
||||
mIdp.numDatabaseHotseatIcons = 3;
|
||||
new GridSizeMigrationTask(mContext, mDb, mValidPackages, false, 5, 3)
|
||||
.migrateHotseat();
|
||||
// First item is dropped as it has the least weight.
|
||||
|
||||
+100
-4
@@ -120,7 +120,7 @@ public class GridSizeMigrationTaskV2Test {
|
||||
};
|
||||
mModelHelper.addItem(APP_ICON, 0, DESKTOP, 2, 2, testPackage7);
|
||||
|
||||
mIdp.numHotseatIcons = 4;
|
||||
mIdp.numDatabaseHotseatIcons = 4;
|
||||
mIdp.numColumns = 4;
|
||||
mIdp.numRows = 4;
|
||||
GridSizeMigrationTaskV2.DbReader srcReader = new GridSizeMigrationTaskV2.DbReader(mDb,
|
||||
@@ -128,16 +128,16 @@ public class GridSizeMigrationTaskV2Test {
|
||||
srcHotseatItems.length);
|
||||
GridSizeMigrationTaskV2.DbReader destReader = new GridSizeMigrationTaskV2.DbReader(mDb,
|
||||
LauncherSettings.Favorites.TABLE_NAME, mContext, mValidPackages,
|
||||
mIdp.numHotseatIcons);
|
||||
mIdp.numDatabaseHotseatIcons);
|
||||
GridSizeMigrationTaskV2 task = new GridSizeMigrationTaskV2(mContext, mDb, srcReader,
|
||||
destReader, mIdp.numHotseatIcons, new Point(mIdp.numColumns, mIdp.numRows));
|
||||
destReader, mIdp.numDatabaseHotseatIcons, new Point(mIdp.numColumns, mIdp.numRows));
|
||||
task.migrate();
|
||||
|
||||
// Check hotseat items
|
||||
Cursor c = mContext.getContentResolver().query(LauncherSettings.Favorites.CONTENT_URI,
|
||||
new String[]{LauncherSettings.Favorites.SCREEN, LauncherSettings.Favorites.INTENT},
|
||||
"container=" + CONTAINER_HOTSEAT, null, null, null);
|
||||
assertEquals(c.getCount(), mIdp.numHotseatIcons);
|
||||
assertEquals(c.getCount(), mIdp.numDatabaseHotseatIcons);
|
||||
int screenIndex = c.getColumnIndex(LauncherSettings.Favorites.SCREEN);
|
||||
int intentIndex = c.getColumnIndex(LauncherSettings.Favorites.INTENT);
|
||||
c.moveToNext();
|
||||
@@ -186,5 +186,101 @@ public class GridSizeMigrationTaskV2Test {
|
||||
assertTrue(c.getString(intentIndex).contains(testPackage8));
|
||||
assertEquals(c.getInt(cellXIndex), 0);
|
||||
assertEquals(c.getInt(cellYIndex), 2);
|
||||
|
||||
c.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void migrateToLargerHotseat() {
|
||||
int[] srcHotseatItems = {
|
||||
mModelHelper.addItem(APP_ICON, 0, HOTSEAT, 0, 0, testPackage1, 1, TMP_CONTENT_URI),
|
||||
mModelHelper.addItem(SHORTCUT, 1, HOTSEAT, 0, 0, testPackage2, 2, TMP_CONTENT_URI),
|
||||
mModelHelper.addItem(APP_ICON, 2, HOTSEAT, 0, 0, testPackage3, 3, TMP_CONTENT_URI),
|
||||
mModelHelper.addItem(SHORTCUT, 3, HOTSEAT, 0, 0, testPackage4, 4, TMP_CONTENT_URI),
|
||||
};
|
||||
|
||||
int numSrcDatabaseHotseatIcons = srcHotseatItems.length;
|
||||
mIdp.numDatabaseHotseatIcons = 6;
|
||||
mIdp.numColumns = 4;
|
||||
mIdp.numRows = 4;
|
||||
GridSizeMigrationTaskV2.DbReader srcReader = new GridSizeMigrationTaskV2.DbReader(mDb,
|
||||
LauncherSettings.Favorites.TMP_TABLE, mContext, mValidPackages,
|
||||
numSrcDatabaseHotseatIcons);
|
||||
GridSizeMigrationTaskV2.DbReader destReader = new GridSizeMigrationTaskV2.DbReader(mDb,
|
||||
LauncherSettings.Favorites.TABLE_NAME, mContext, mValidPackages,
|
||||
mIdp.numDatabaseHotseatIcons);
|
||||
GridSizeMigrationTaskV2 task = new GridSizeMigrationTaskV2(mContext, mDb, srcReader,
|
||||
destReader, mIdp.numDatabaseHotseatIcons, new Point(mIdp.numColumns, mIdp.numRows));
|
||||
task.migrate();
|
||||
|
||||
// Check hotseat items
|
||||
Cursor c = mContext.getContentResolver().query(LauncherSettings.Favorites.CONTENT_URI,
|
||||
new String[]{LauncherSettings.Favorites.SCREEN, LauncherSettings.Favorites.INTENT},
|
||||
"container=" + CONTAINER_HOTSEAT, null, null, null);
|
||||
assertEquals(c.getCount(), numSrcDatabaseHotseatIcons);
|
||||
int screenIndex = c.getColumnIndex(LauncherSettings.Favorites.SCREEN);
|
||||
int intentIndex = c.getColumnIndex(LauncherSettings.Favorites.INTENT);
|
||||
c.moveToNext();
|
||||
assertEquals(c.getInt(screenIndex), 0);
|
||||
assertTrue(c.getString(intentIndex).contains(testPackage1));
|
||||
c.moveToNext();
|
||||
assertEquals(c.getInt(screenIndex), 1);
|
||||
assertTrue(c.getString(intentIndex).contains(testPackage2));
|
||||
c.moveToNext();
|
||||
assertEquals(c.getInt(screenIndex), 2);
|
||||
assertTrue(c.getString(intentIndex).contains(testPackage3));
|
||||
c.moveToNext();
|
||||
assertEquals(c.getInt(screenIndex), 3);
|
||||
assertTrue(c.getString(intentIndex).contains(testPackage4));
|
||||
|
||||
c.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void migrateFromLargerHotseat() {
|
||||
int[] srcHotseatItems = {
|
||||
mModelHelper.addItem(APP_ICON, 0, HOTSEAT, 0, 0, testPackage1, 1, TMP_CONTENT_URI),
|
||||
-1,
|
||||
mModelHelper.addItem(SHORTCUT, 2, HOTSEAT, 0, 0, testPackage2, 2, TMP_CONTENT_URI),
|
||||
mModelHelper.addItem(APP_ICON, 3, HOTSEAT, 0, 0, testPackage3, 3, TMP_CONTENT_URI),
|
||||
mModelHelper.addItem(SHORTCUT, 4, HOTSEAT, 0, 0, testPackage4, 4, TMP_CONTENT_URI),
|
||||
mModelHelper.addItem(APP_ICON, 5, HOTSEAT, 0, 0, testPackage5, 5, TMP_CONTENT_URI),
|
||||
};
|
||||
|
||||
int numSrcDatabaseHotseatIcons = srcHotseatItems.length;
|
||||
mIdp.numDatabaseHotseatIcons = 4;
|
||||
mIdp.numColumns = 4;
|
||||
mIdp.numRows = 4;
|
||||
GridSizeMigrationTaskV2.DbReader srcReader = new GridSizeMigrationTaskV2.DbReader(mDb,
|
||||
LauncherSettings.Favorites.TMP_TABLE, mContext, mValidPackages,
|
||||
numSrcDatabaseHotseatIcons);
|
||||
GridSizeMigrationTaskV2.DbReader destReader = new GridSizeMigrationTaskV2.DbReader(mDb,
|
||||
LauncherSettings.Favorites.TABLE_NAME, mContext, mValidPackages,
|
||||
mIdp.numDatabaseHotseatIcons);
|
||||
GridSizeMigrationTaskV2 task = new GridSizeMigrationTaskV2(mContext, mDb, srcReader,
|
||||
destReader, mIdp.numDatabaseHotseatIcons, new Point(mIdp.numColumns, mIdp.numRows));
|
||||
task.migrate();
|
||||
|
||||
// Check hotseat items
|
||||
Cursor c = mContext.getContentResolver().query(LauncherSettings.Favorites.CONTENT_URI,
|
||||
new String[]{LauncherSettings.Favorites.SCREEN, LauncherSettings.Favorites.INTENT},
|
||||
"container=" + CONTAINER_HOTSEAT, null, null, null);
|
||||
assertEquals(c.getCount(), mIdp.numDatabaseHotseatIcons);
|
||||
int screenIndex = c.getColumnIndex(LauncherSettings.Favorites.SCREEN);
|
||||
int intentIndex = c.getColumnIndex(LauncherSettings.Favorites.INTENT);
|
||||
c.moveToNext();
|
||||
assertEquals(c.getInt(screenIndex), 0);
|
||||
assertTrue(c.getString(intentIndex).contains(testPackage1));
|
||||
c.moveToNext();
|
||||
assertEquals(c.getInt(screenIndex), 1);
|
||||
assertTrue(c.getString(intentIndex).contains(testPackage2));
|
||||
c.moveToNext();
|
||||
assertEquals(c.getInt(screenIndex), 2);
|
||||
assertTrue(c.getString(intentIndex).contains(testPackage3));
|
||||
c.moveToNext();
|
||||
assertEquals(c.getInt(screenIndex), 3);
|
||||
assertTrue(c.getString(intentIndex).contains(testPackage4));
|
||||
|
||||
c.close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -160,7 +160,7 @@ public class LoaderCursorTest {
|
||||
public void checkItemPlacement_outsideBounds() {
|
||||
mIDP.numRows = 4;
|
||||
mIDP.numColumns = 4;
|
||||
mIDP.numHotseatIcons = 3;
|
||||
mIDP.numDatabaseHotseatIcons = 3;
|
||||
|
||||
// Item outside screen bounds are not placed
|
||||
assertFalse(mLoaderCursor.checkItemPlacement(
|
||||
@@ -171,7 +171,7 @@ public class LoaderCursorTest {
|
||||
public void checkItemPlacement_overlappingItems() {
|
||||
mIDP.numRows = 4;
|
||||
mIDP.numColumns = 4;
|
||||
mIDP.numHotseatIcons = 3;
|
||||
mIDP.numDatabaseHotseatIcons = 3;
|
||||
|
||||
// Overlapping mItems are not placed
|
||||
assertTrue(mLoaderCursor.checkItemPlacement(
|
||||
@@ -197,7 +197,7 @@ public class LoaderCursorTest {
|
||||
public void checkItemPlacement_hotseat() {
|
||||
mIDP.numRows = 4;
|
||||
mIDP.numColumns = 4;
|
||||
mIDP.numHotseatIcons = 3;
|
||||
mIDP.numDatabaseHotseatIcons = 3;
|
||||
|
||||
// Hotseat mItems are only placed based on screenId
|
||||
assertTrue(mLoaderCursor.checkItemPlacement(
|
||||
|
||||
@@ -355,7 +355,7 @@ public class LauncherModelHelper {
|
||||
throws Exception {
|
||||
Context context = RuntimeEnvironment.application;
|
||||
InvariantDeviceProfile idp = InvariantDeviceProfile.INSTANCE.get(context);
|
||||
idp.numRows = idp.numColumns = idp.numHotseatIcons = DEFAULT_GRID_SIZE;
|
||||
idp.numRows = idp.numColumns = idp.numDatabaseHotseatIcons = DEFAULT_GRID_SIZE;
|
||||
idp.iconBitmapSize = DEFAULT_BITMAP_SIZE;
|
||||
|
||||
Settings.Secure.putString(context.getContentResolver(),
|
||||
|
||||
@@ -89,7 +89,7 @@ public class AutoInstallsLayout {
|
||||
|
||||
// Try with grid size and hotseat count
|
||||
String layoutName = String.format(Locale.ENGLISH, FORMATTED_LAYOUT_RES_WITH_HOSTEAT,
|
||||
grid.numColumns, grid.numRows, grid.numHotseatIcons);
|
||||
grid.numColumns, grid.numRows, grid.numDatabaseHotseatIcons);
|
||||
int layoutId = targetRes.getIdentifier(layoutName, "xml", pkg);
|
||||
|
||||
// Try with only grid size
|
||||
|
||||
@@ -137,6 +137,7 @@ public class DeviceProfile {
|
||||
public int folderChildDrawablePaddingPx;
|
||||
|
||||
// Hotseat
|
||||
public final int numShownHotseatIcons;
|
||||
public int hotseatCellHeightPx;
|
||||
// In portrait: size = height, in landscape: size = width
|
||||
public int hotseatBarSizePx;
|
||||
@@ -293,6 +294,7 @@ public class DeviceProfile {
|
||||
|
||||
workspaceCellPaddingXPx = res.getDimensionPixelSize(R.dimen.dynamic_grid_cell_padding_x);
|
||||
|
||||
numShownHotseatIcons = inv.numShownHotseatIcons;
|
||||
hotseatBarTopPaddingPx =
|
||||
res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_top_padding);
|
||||
hotseatBarBottomPaddingPx = (isTallDevice ? 0
|
||||
@@ -735,7 +737,7 @@ public class DeviceProfile {
|
||||
// for this, we pad the left and right of the hotseat with half of the difference of a
|
||||
// workspace cell vs a hotseat cell.
|
||||
float workspaceCellWidth = (float) widthPx / inv.numColumns;
|
||||
float hotseatCellWidth = (float) widthPx / inv.numHotseatIcons;
|
||||
float hotseatCellWidth = (float) widthPx / inv.numShownHotseatIcons;
|
||||
int hotseatAdjustment = Math.round((workspaceCellWidth - hotseatCellWidth) / 2);
|
||||
mHotseatPadding.set(
|
||||
hotseatAdjustment + workspacePadding.left + cellLayoutPaddingLeftRightPx
|
||||
|
||||
@@ -92,9 +92,9 @@ public class Hotseat extends CellLayout implements Insettable {
|
||||
mHasVerticalHotseat = hasVerticalHotseat;
|
||||
InvariantDeviceProfile idp = mActivity.getDeviceProfile().inv;
|
||||
if (hasVerticalHotseat) {
|
||||
setGridSize(1, idp.numHotseatIcons);
|
||||
setGridSize(1, idp.numShownHotseatIcons);
|
||||
} else {
|
||||
setGridSize(idp.numHotseatIcons, 1);
|
||||
setGridSize(idp.numShownHotseatIcons, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -122,7 +122,14 @@ public class InvariantDeviceProfile {
|
||||
/**
|
||||
* Number of icons inside the hotseat area.
|
||||
*/
|
||||
public int numHotseatIcons;
|
||||
protected int numShownHotseatIcons;
|
||||
|
||||
/**
|
||||
* Number of icons inside the hotseat area that is stored in the database. This is greater than
|
||||
* or equal to numnShownHotseatIcons, allowing for a seamless transition between two hotseat
|
||||
* sizes that share the same DB.
|
||||
*/
|
||||
public int numDatabaseHotseatIcons;
|
||||
|
||||
/**
|
||||
* Number of columns in the all apps list.
|
||||
@@ -165,7 +172,8 @@ public class InvariantDeviceProfile {
|
||||
iconBitmapSize = p.iconBitmapSize;
|
||||
iconTextSize = p.iconTextSize;
|
||||
landscapeIconTextSize = p.landscapeIconTextSize;
|
||||
numHotseatIcons = p.numHotseatIcons;
|
||||
numShownHotseatIcons = p.numShownHotseatIcons;
|
||||
numDatabaseHotseatIcons = p.numDatabaseHotseatIcons;
|
||||
numAllAppsColumns = p.numAllAppsColumns;
|
||||
isScalable = p.isScalable;
|
||||
devicePaddingId = p.devicePaddingId;
|
||||
@@ -190,7 +198,7 @@ public class InvariantDeviceProfile {
|
||||
Utilities.getPrefs(context).edit().putString(KEY_IDP_GRID_NAME, newGridName).apply();
|
||||
}
|
||||
Utilities.getPrefs(context).edit()
|
||||
.putInt(KEY_MIGRATION_SRC_HOTSEAT_COUNT, numHotseatIcons)
|
||||
.putInt(KEY_MIGRATION_SRC_HOTSEAT_COUNT, numDatabaseHotseatIcons)
|
||||
.putString(KEY_MIGRATION_SRC_WORKSPACE_SIZE, getPointString(numColumns, numRows))
|
||||
.apply();
|
||||
|
||||
@@ -229,6 +237,7 @@ public class InvariantDeviceProfile {
|
||||
.add(myDisplayOption);
|
||||
result.iconSize = defaultDisplayOption.iconSize;
|
||||
result.landscapeIconSize = defaultDisplayOption.landscapeIconSize;
|
||||
result.numShownHotseatIcons = myDisplayOption.numShownHotseatIcons;
|
||||
if (defaultDisplayOption.allAppsIconSize < myDisplayOption.allAppsIconSize) {
|
||||
result.allAppsIconSize = defaultDisplayOption.allAppsIconSize;
|
||||
result.numAllAppsColumns = defaultDisplayOption.numAllAppsColumns;
|
||||
@@ -279,7 +288,7 @@ public class InvariantDeviceProfile {
|
||||
GridOption closestProfile = displayOption.grid;
|
||||
numRows = closestProfile.numRows;
|
||||
numColumns = closestProfile.numColumns;
|
||||
numHotseatIcons = closestProfile.numHotseatIcons;
|
||||
numDatabaseHotseatIcons = closestProfile.numDatabaseHotseatIcons;
|
||||
dbFile = closestProfile.dbFile;
|
||||
defaultLayoutId = closestProfile.defaultLayoutId;
|
||||
demoModeLayoutId = closestProfile.demoModeLayoutId;
|
||||
@@ -301,6 +310,7 @@ public class InvariantDeviceProfile {
|
||||
minCellHeight = displayOption.minCellHeight;
|
||||
minCellWidth = displayOption.minCellWidth;
|
||||
borderSpacing = displayOption.borderSpacing;
|
||||
numShownHotseatIcons = Math.round(displayOption.numShownHotseatIcons);
|
||||
numAllAppsColumns = Math.round(displayOption.numAllAppsColumns);
|
||||
|
||||
if (Utilities.isGridOptionsEnabled(context)) {
|
||||
@@ -391,7 +401,7 @@ public class InvariantDeviceProfile {
|
||||
numColumns != oldProfile.numColumns ||
|
||||
numFolderColumns != oldProfile.numFolderColumns ||
|
||||
numFolderRows != oldProfile.numFolderRows ||
|
||||
numHotseatIcons != oldProfile.numHotseatIcons) {
|
||||
numDatabaseHotseatIcons != oldProfile.numDatabaseHotseatIcons) {
|
||||
changeFlags |= CHANGE_FLAG_GRID;
|
||||
}
|
||||
|
||||
@@ -619,7 +629,7 @@ public class InvariantDeviceProfile {
|
||||
private final int numFolderRows;
|
||||
private final int numFolderColumns;
|
||||
|
||||
private final int numHotseatIcons;
|
||||
private final int numDatabaseHotseatIcons;
|
||||
|
||||
private final String dbFile;
|
||||
|
||||
@@ -645,7 +655,7 @@ public class InvariantDeviceProfile {
|
||||
R.styleable.GridDisplayOption_defaultLayoutId, 0);
|
||||
demoModeLayoutId = a.getResourceId(
|
||||
R.styleable.GridDisplayOption_demoModeLayoutId, defaultLayoutId);
|
||||
numHotseatIcons = a.getInt(
|
||||
numDatabaseHotseatIcons = a.getInt(
|
||||
R.styleable.GridDisplayOption_numHotseatIcons, numColumns);
|
||||
numFolderRows = a.getInt(
|
||||
R.styleable.GridDisplayOption_numFolderRows, numRows);
|
||||
@@ -673,6 +683,7 @@ public class InvariantDeviceProfile {
|
||||
private final float minHeightDps;
|
||||
private final boolean canBeDefault;
|
||||
|
||||
private float numShownHotseatIcons;
|
||||
private float numAllAppsColumns;
|
||||
private float minCellHeight;
|
||||
private float minCellWidth;
|
||||
@@ -695,6 +706,8 @@ public class InvariantDeviceProfile {
|
||||
minHeightDps = a.getFloat(R.styleable.ProfileDisplayOption_minHeightDps, 0);
|
||||
canBeDefault = a.getBoolean(
|
||||
R.styleable.ProfileDisplayOption_canBeDefault, false);
|
||||
numShownHotseatIcons = a.getInt(R.styleable.ProfileDisplayOption_numShownHotseatIcons,
|
||||
grid.numDatabaseHotseatIcons);
|
||||
numAllAppsColumns = a.getInt(R.styleable.ProfileDisplayOption_numAllAppsColumns,
|
||||
grid.numColumns);
|
||||
|
||||
@@ -725,6 +738,7 @@ public class InvariantDeviceProfile {
|
||||
minWidthDps = 0;
|
||||
minHeightDps = 0;
|
||||
canBeDefault = false;
|
||||
numShownHotseatIcons = 0;
|
||||
numAllAppsColumns = 0;
|
||||
minCellHeight = 0;
|
||||
minCellWidth = 0;
|
||||
@@ -732,6 +746,7 @@ public class InvariantDeviceProfile {
|
||||
}
|
||||
|
||||
private DisplayOption multiply(float w) {
|
||||
numShownHotseatIcons *= w;
|
||||
numAllAppsColumns *= w;
|
||||
iconSize *= w;
|
||||
landscapeIconSize *= w;
|
||||
@@ -746,6 +761,7 @@ public class InvariantDeviceProfile {
|
||||
}
|
||||
|
||||
private DisplayOption add(DisplayOption p) {
|
||||
numShownHotseatIcons += p.numShownHotseatIcons;
|
||||
numAllAppsColumns += p.numAllAppsColumns;
|
||||
iconSize += p.iconSize;
|
||||
landscapeIconSize += p.landscapeIconSize;
|
||||
|
||||
@@ -618,7 +618,7 @@ public class LauncherProvider extends ContentProvider {
|
||||
.appendQueryParameter("version", "1")
|
||||
.appendQueryParameter("gridWidth", Integer.toString(grid.numColumns))
|
||||
.appendQueryParameter("gridHeight", Integer.toString(grid.numRows))
|
||||
.appendQueryParameter("hotseatSize", Integer.toString(grid.numHotseatIcons))
|
||||
.appendQueryParameter("hotseatSize", Integer.toString(grid.numDatabaseHotseatIcons))
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
@@ -106,7 +106,7 @@ public class AppsSearchContainerLayout extends ExtendedEditText
|
||||
- mAppsView.getActiveRecyclerView().getPaddingRight();
|
||||
|
||||
int cellWidth = DeviceProfile.calculateCellWidth(rowWidth, dp.cellLayoutBorderSpacingPx,
|
||||
dp.inv.numHotseatIcons);
|
||||
dp.numShownHotseatIcons);
|
||||
int iconVisibleSize = Math.round(ICON_VISIBLE_AREA_FACTOR * dp.iconSizePx);
|
||||
int iconPadding = cellWidth - iconVisibleSize;
|
||||
|
||||
|
||||
@@ -467,7 +467,7 @@ public class LauncherPreviewRenderer extends ContextThemeWrapper
|
||||
}
|
||||
}
|
||||
IntArray ranks = getMissingHotseatRanks(currentWorkspaceItems,
|
||||
mIdp.numHotseatIcons);
|
||||
mDp.numShownHotseatIcons);
|
||||
List<ItemInfo> predictions = workspaceResult.mHotseatPredictions == null
|
||||
? Collections.emptyList() : workspaceResult.mHotseatPredictions.items;
|
||||
int count = Math.min(ranks.size(), predictions.size());
|
||||
@@ -484,7 +484,7 @@ public class LauncherPreviewRenderer extends ContextThemeWrapper
|
||||
}
|
||||
} else {
|
||||
// Add hotseat icons
|
||||
for (int i = 0; i < mIdp.numHotseatIcons; i++) {
|
||||
for (int i = 0; i < mDp.numShownHotseatIcons; i++) {
|
||||
WorkspaceItemInfo info = new WorkspaceItemInfo(mWorkspaceItemInfo);
|
||||
info.container = Favorites.CONTAINER_HOTSEAT;
|
||||
info.screenId = i;
|
||||
|
||||
@@ -893,7 +893,7 @@ public class GridSizeMigrationTask {
|
||||
String gridSizeString = getPointString(idp.numColumns, idp.numRows);
|
||||
|
||||
return !gridSizeString.equals(prefs.getString(KEY_MIGRATION_SRC_WORKSPACE_SIZE, ""))
|
||||
|| idp.numHotseatIcons != prefs.getInt(KEY_MIGRATION_SRC_HOTSEAT_COUNT, -1);
|
||||
|| idp.numDatabaseHotseatIcons != prefs.getInt(KEY_MIGRATION_SRC_HOTSEAT_COUNT, -1);
|
||||
}
|
||||
|
||||
/** See {@link #migrateGridIfNeeded(Context, InvariantDeviceProfile)} */
|
||||
@@ -928,7 +928,7 @@ public class GridSizeMigrationTask {
|
||||
.getBinder(Settings.EXTRA_VALUE)) {
|
||||
|
||||
int srcHotseatCount = prefs.getInt(KEY_MIGRATION_SRC_HOTSEAT_COUNT,
|
||||
idp.numHotseatIcons);
|
||||
idp.numDatabaseHotseatIcons);
|
||||
Point sourceSize = parsePoint(prefs.getString(
|
||||
KEY_MIGRATION_SRC_WORKSPACE_SIZE, gridSizeString));
|
||||
|
||||
@@ -948,10 +948,10 @@ public class GridSizeMigrationTask {
|
||||
|
||||
HashSet<String> validPackages = getValidPackages(context);
|
||||
// Hotseat.
|
||||
if (srcHotseatCount != idp.numHotseatIcons
|
||||
if (srcHotseatCount != idp.numDatabaseHotseatIcons
|
||||
&& new GridSizeMigrationTask(context, transaction.getDb(), validPackages,
|
||||
migrateForPreview, srcHotseatCount,
|
||||
idp.numHotseatIcons).migrateHotseat()) {
|
||||
idp.numDatabaseHotseatIcons).migrateHotseat()) {
|
||||
dbChanged = true;
|
||||
}
|
||||
|
||||
@@ -991,7 +991,7 @@ public class GridSizeMigrationTask {
|
||||
// Save current configuration, so that the migration does not run again.
|
||||
prefs.edit()
|
||||
.putString(KEY_MIGRATION_SRC_WORKSPACE_SIZE, gridSizeString)
|
||||
.putInt(KEY_MIGRATION_SRC_HOTSEAT_COUNT, idp.numHotseatIcons)
|
||||
.putInt(KEY_MIGRATION_SRC_HOTSEAT_COUNT, idp.numDatabaseHotseatIcons)
|
||||
.apply();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,7 +110,7 @@ public class GridSizeMigrationTaskV2 {
|
||||
String gridSizeString = getPointString(idp.numColumns, idp.numRows);
|
||||
|
||||
return !gridSizeString.equals(prefs.getString(KEY_MIGRATION_SRC_WORKSPACE_SIZE, ""))
|
||||
|| idp.numHotseatIcons != prefs.getInt(KEY_MIGRATION_SRC_HOTSEAT_COUNT, -1);
|
||||
|| idp.numDatabaseHotseatIcons != prefs.getInt(KEY_MIGRATION_SRC_HOTSEAT_COUNT, -1);
|
||||
}
|
||||
|
||||
/** See {@link #migrateGridIfNeeded(Context, InvariantDeviceProfile)} */
|
||||
@@ -148,7 +148,8 @@ public class GridSizeMigrationTaskV2 {
|
||||
SharedPreferences prefs = Utilities.getPrefs(context);
|
||||
String gridSizeString = getPointString(idp.numColumns, idp.numRows);
|
||||
HashSet<String> validPackages = getValidPackages(context);
|
||||
int srcHotseatCount = prefs.getInt(KEY_MIGRATION_SRC_HOTSEAT_COUNT, idp.numHotseatIcons);
|
||||
int srcHotseatCount = prefs.getInt(KEY_MIGRATION_SRC_HOTSEAT_COUNT,
|
||||
idp.numDatabaseHotseatIcons);
|
||||
|
||||
if (migrateForPreview) {
|
||||
if (!LauncherSettings.Settings.call(
|
||||
@@ -177,11 +178,11 @@ public class GridSizeMigrationTaskV2 {
|
||||
DbReader destReader = new DbReader(t.getDb(),
|
||||
migrateForPreview ? LauncherSettings.Favorites.PREVIEW_TABLE_NAME
|
||||
: LauncherSettings.Favorites.TABLE_NAME,
|
||||
context, validPackages, idp.numHotseatIcons);
|
||||
context, validPackages, idp.numDatabaseHotseatIcons);
|
||||
|
||||
Point targetSize = new Point(idp.numColumns, idp.numRows);
|
||||
GridSizeMigrationTaskV2 task = new GridSizeMigrationTaskV2(context, t.getDb(),
|
||||
srcReader, destReader, idp.numHotseatIcons, targetSize);
|
||||
srcReader, destReader, idp.numDatabaseHotseatIcons, targetSize);
|
||||
task.migrate();
|
||||
|
||||
if (!migrateForPreview) {
|
||||
@@ -202,7 +203,7 @@ public class GridSizeMigrationTaskV2 {
|
||||
// Save current configuration, so that the migration does not run again.
|
||||
prefs.edit()
|
||||
.putString(KEY_MIGRATION_SRC_WORKSPACE_SIZE, gridSizeString)
|
||||
.putInt(KEY_MIGRATION_SRC_HOTSEAT_COUNT, idp.numHotseatIcons)
|
||||
.putInt(KEY_MIGRATION_SRC_HOTSEAT_COUNT, idp.numDatabaseHotseatIcons)
|
||||
.apply();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -410,10 +410,10 @@ public class LoaderCursor extends CursorWrapper {
|
||||
final GridOccupancy hotseatOccupancy =
|
||||
occupied.get(LauncherSettings.Favorites.CONTAINER_HOTSEAT);
|
||||
|
||||
if (item.screenId >= mIDP.numHotseatIcons) {
|
||||
if (item.screenId >= mIDP.numDatabaseHotseatIcons) {
|
||||
Log.e(TAG, "Error loading shortcut " + item
|
||||
+ " into hotseat position " + item.screenId
|
||||
+ ", position out of bounds: (0 to " + (mIDP.numHotseatIcons - 1)
|
||||
+ ", position out of bounds: (0 to " + (mIDP.numDatabaseHotseatIcons - 1)
|
||||
+ ")");
|
||||
return false;
|
||||
}
|
||||
@@ -429,7 +429,7 @@ public class LoaderCursor extends CursorWrapper {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
final GridOccupancy occupancy = new GridOccupancy(mIDP.numHotseatIcons, 1);
|
||||
final GridOccupancy occupancy = new GridOccupancy(mIDP.numDatabaseHotseatIcons, 1);
|
||||
occupancy.cells[item.screenId][0] = true;
|
||||
occupied.put(LauncherSettings.Favorites.CONTAINER_HOTSEAT, occupancy);
|
||||
return true;
|
||||
|
||||
@@ -91,7 +91,7 @@ public class ModelWriter {
|
||||
// in the hotseat
|
||||
if (container == Favorites.CONTAINER_HOTSEAT) {
|
||||
item.screenId = mHasVerticalHotseat
|
||||
? LauncherAppState.getIDP(mContext).numHotseatIcons - cellY - 1 : cellX;
|
||||
? LauncherAppState.getIDP(mContext).numDatabaseHotseatIcons - cellY - 1 : cellX;
|
||||
} else {
|
||||
item.screenId = screenId;
|
||||
}
|
||||
|
||||
@@ -284,8 +284,9 @@ public class ImportDataTask {
|
||||
insertOperations.clear();
|
||||
}
|
||||
|
||||
IntSparseArrayMap<Object> hotseatItems = GridSizeMigrationTask.removeBrokenHotseatItems(mContext);
|
||||
int myHotseatCount = LauncherAppState.getIDP(mContext).numHotseatIcons;
|
||||
IntSparseArrayMap<Object> hotseatItems = GridSizeMigrationTask
|
||||
.removeBrokenHotseatItems(mContext);
|
||||
int myHotseatCount = LauncherAppState.getIDP(mContext).numDatabaseHotseatIcons;
|
||||
if (hotseatItems.size() < myHotseatCount) {
|
||||
// Insufficient hotseat items. Add a few more.
|
||||
HotseatParserCallback parserCallback = new HotseatParserCallback(
|
||||
|
||||
@@ -103,7 +103,7 @@ public class RestoreDbTask {
|
||||
*/
|
||||
private void backupWorkspace(Context context, SQLiteDatabase db) throws Exception {
|
||||
InvariantDeviceProfile idp = LauncherAppState.getIDP(context);
|
||||
new GridBackupTable(context, db, idp.numHotseatIcons, idp.numColumns, idp.numRows)
|
||||
new GridBackupTable(context, db, idp.numDatabaseHotseatIcons, idp.numColumns, idp.numRows)
|
||||
.doBackup(getDefaultProfileId(db), GridBackupTable.OPTION_REQUIRES_SANITIZATION);
|
||||
}
|
||||
|
||||
@@ -111,7 +111,7 @@ public class RestoreDbTask {
|
||||
@NonNull DatabaseHelper helper, @NonNull BackupManager backupManager)
|
||||
throws Exception {
|
||||
final InvariantDeviceProfile idp = LauncherAppState.getIDP(context);
|
||||
GridBackupTable backupTable = new GridBackupTable(context, db, idp.numHotseatIcons,
|
||||
GridBackupTable backupTable = new GridBackupTable(context, db, idp.numDatabaseHotseatIcons,
|
||||
idp.numColumns, idp.numRows);
|
||||
if (backupTable.restoreFromRawBackupIfAvailable(getDefaultProfileId(db))) {
|
||||
int itemsDeleted = sanitizeDB(helper, db, backupManager);
|
||||
|
||||
Reference in New Issue
Block a user