Files
Flexera-Launcher/quickstep/src/com/android/launcher3/hybridhotseat/HotseatEduController.java
T

250 lines
9.7 KiB
Java

/*
* Copyright (C) 2020 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.hybridhotseat;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_HOTSEAT_EDU_ONLY_TIP;
import android.content.Intent;
import android.graphics.Rect;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
import com.android.launcher3.BubbleTextView;
import com.android.launcher3.CellLayout;
import com.android.launcher3.Hotseat;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.Workspace;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.views.ArrowTipView;
import com.android.launcher3.views.Snackbar;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.IntStream;
/**
* Controller class for managing user onboaridng flow for hybrid hotseat
*/
public class HotseatEduController {
private static final String TAG = "HotseatEduController";
public static final String SETTINGS_ACTION =
"android.settings.ACTION_CONTENT_SUGGESTIONS_SETTINGS";
private final Launcher mLauncher;
private final Hotseat mHotseat;
private List<WorkspaceItemInfo> mPredictedApps;
private HotseatEduDialog mActiveDialog;
private ArrayList<ItemInfo> mNewItems = new ArrayList<>();
HotseatEduController(Launcher launcher) {
mLauncher = launcher;
mHotseat = launcher.getHotseat();
}
/**
* Checks what type of migration should be used and migrates hotseat
*/
void migrate() {
HotseatRestoreHelper.createBackup(mLauncher);
migrateHotseatWhole();
Snackbar.show(mLauncher, R.string.hotsaet_tip_prediction_enabled,
R.string.hotseat_prediction_settings, null,
() -> mLauncher.startActivity(getSettingsIntent()));
}
/**
* This migration option attempts to move the entire hotseat up to the first workspace that
* has space to host items. If no such page is found, it moves items to a new page.
*
* @return pageId where items are migrated
*/
private int migrateHotseatWhole() {
Workspace<?> workspace = mLauncher.getWorkspace();
int pageId = -1;
int toRow = 0;
for (int i = 0; i < workspace.getPageCount(); i++) {
CellLayout target = workspace.getScreenWithId(workspace.getScreenIdForPageIndex(i));
if (target.makeSpaceForHotseatMigration(true)) {
toRow = mLauncher.getDeviceProfile().inv.numRows - 1;
pageId = i;
break;
}
}
if (pageId == -1) {
pageId = mLauncher.getModel().getModelDbController().getNewScreenId();
}
boolean isPortrait = !mLauncher.getDeviceProfile().isVerticalBarLayout();
int numColumns = mLauncher.getDeviceProfile().inv.numColumns;
int destIndex = 0;
for (CellLayout page : mHotseat.getPageLayouts()) {
int countX = page.getCountX();
int countY = page.getCountY();
if (isPortrait) {
for (int y = 0; y < countY; y++) {
for (int x = 0; x < countX; x++) {
destIndex += migrateHotseatChild(page.getChildAt(x, y), pageId, toRow,
destIndex, numColumns);
}
}
} else {
for (int i = 0; i < countY; i++) {
destIndex += migrateHotseatChild(page.getChildAt(0, countY - i - 1), pageId,
toRow, destIndex, numColumns);
}
}
}
return pageId;
}
/** @return 1 if the item was migrated, otherwise 0 */
private int migrateHotseatChild(View child, int pageId, int toRow, int destIndex,
int numColumns) {
if (child == null || child.getTag() == null) {
return 0;
}
ItemInfo tag = (ItemInfo) child.getTag();
if (tag.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION) {
return 0;
}
int destX = numColumns > 0 ? destIndex % numColumns : destIndex;
int destY = numColumns > 0 ? toRow - destIndex / numColumns : toRow;
if (destY < 0) {
destY = 0;
}
mLauncher.getModelWriter().moveItemInDatabase(tag,
LauncherSettings.Favorites.CONTAINER_DESKTOP, pageId, destX, destY);
mNewItems.add(tag);
return 1;
}
void moveHotseatItems() {
for (CellLayout page : mHotseat.getPageLayouts()) {
page.removeAllViewsInLayout();
}
if (!mNewItems.isEmpty()) {
mLauncher.bindItemsAdded(mNewItems);
}
}
void finishOnboarding() {
mLauncher.getModel().onWorkspaceUiChanged();
}
void showDimissTip() {
CellLayout page = mHotseat.getCurrentPageLayout();
int childCount = page != null ? page.getShortcutsAndWidgets().getChildCount() : 0;
if (childCount < mLauncher.getDeviceProfile().numShownHotseatIcons) {
Snackbar.show(mLauncher, R.string.hotseat_tip_gaps_filled,
R.string.hotseat_prediction_settings, null,
() -> mLauncher.startActivity(getSettingsIntent()));
} else {
showHotseatArrowTip(true, mLauncher.getString(R.string.hotseat_tip_no_empty_slots));
}
}
void setPredictedApps(List<WorkspaceItemInfo> predictedApps) {
mPredictedApps = predictedApps;
}
void showEdu() {
CellLayout page = mHotseat.getCurrentPageLayout();
int childCount = page != null ? page.getShortcutsAndWidgets().getChildCount() : 0;
CellLayout cellLayout = mLauncher.getWorkspace().getScreenWithId(Workspace.FIRST_SCREEN_ID);
// hotseat is already empty and does not require migration. show edu tip
boolean requiresMigration = IntStream.range(0, childCount).anyMatch(i -> {
View v = page.getShortcutsAndWidgets().getChildAt(i);
return v != null && v.getTag() != null && ((ItemInfo) v.getTag()).container
!= LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION;
});
boolean canMigrateToFirstPage = cellLayout.makeSpaceForHotseatMigration(false);
if (requiresMigration && canMigrateToFirstPage) {
showDialog();
} else {
if (showHotseatArrowTip(requiresMigration, mLauncher.getString(
requiresMigration ? R.string.hotseat_tip_no_empty_slots
: R.string.hotseat_auto_enrolled))) {
mLauncher.getStatsLogManager().logger().log(LAUNCHER_HOTSEAT_EDU_ONLY_TIP);
}
finishOnboarding();
}
}
/**
* Finds a child suitable child in hotseat and shows arrow tip pointing at it.
*
* @param usePinned used to determine target view. If true, will use the first matching pinned
* item. Otherwise, will use the first predicted child
* @param message String to be shown inside the arrowView
* @return whether suitable child was found and tip was shown
*/
private boolean showHotseatArrowTip(boolean usePinned, String message) {
CellLayout page = mHotseat.getCurrentPageLayout();
if (page == null) {
Log.e(TAG, "Unable to find suitable view for ArrowTip");
return false;
}
int childCount = page.getShortcutsAndWidgets().getChildCount();
boolean isPortrait = !mLauncher.getDeviceProfile().isVerticalBarLayout();
BubbleTextView tipTargetView = null;
for (int i = childCount - 1; i > -1; i--) {
int x = isPortrait ? i : 0;
int y = isPortrait ? 0 : i;
View v = page.getShortcutsAndWidgets().getChildAt(x, y);
if (v instanceof BubbleTextView && v.getTag() instanceof WorkspaceItemInfo) {
ItemInfo info = (ItemInfo) v.getTag();
boolean isPinned = info.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT;
if (isPinned == usePinned) {
tipTargetView = (BubbleTextView) v;
break;
}
}
}
if (tipTargetView == null) {
Log.e(TAG, "Unable to find suitable view for ArrowTip");
return false;
}
Rect bounds = Utilities.getViewBounds(tipTargetView);
new ArrowTipView(mLauncher).show(message, Gravity.END, bounds.centerX(), bounds.top);
return true;
}
void showDialog() {
if (mPredictedApps == null || mPredictedApps.isEmpty()) {
return;
}
if (mActiveDialog != null) {
mActiveDialog.handleClose(false);
}
mActiveDialog = HotseatEduDialog.getDialog(mLauncher);
mActiveDialog.setHotseatEduController(this);
mActiveDialog.show(mPredictedApps);
}
static Intent getSettingsIntent() {
return new Intent(SETTINGS_ACTION).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}
}