Merging from ub-launcher3-rvc-dev @ build 6595814
Bug:150504032 Test: manual, presubmit on the source branch x20/teams/android-launcher/merge/ub-launcher3-rvc-dev_rvc-dev_6595814.html Change-Id: I4be85d0e52cc3cb8801012a7313a269851680c8b
This commit is contained in:
@@ -54,6 +54,7 @@ message ContainerInfo {
|
|||||||
ShortcutsContainer shortcuts_container = 8;
|
ShortcutsContainer shortcuts_container = 8;
|
||||||
SettingsContainer settings_container = 9;
|
SettingsContainer settings_container = 9;
|
||||||
PredictedHotseatContainer predicted_hotseat_container = 10;
|
PredictedHotseatContainer predicted_hotseat_container = 10;
|
||||||
|
TaskSwitcherContainer task_switcher_container = 11;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,6 +83,9 @@ message ShortcutsContainer {
|
|||||||
message SettingsContainer {
|
message SettingsContainer {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message TaskSwitcherContainer {
|
||||||
|
}
|
||||||
|
|
||||||
enum Attribute {
|
enum Attribute {
|
||||||
UNKNOWN = 0;
|
UNKNOWN = 0;
|
||||||
DEFAULT_LAYOUT = 1; // icon automatically placed in workspace, folder, hotseat
|
DEFAULT_LAYOUT = 1; // icon automatically placed in workspace, folder, hotseat
|
||||||
|
|||||||
+40
@@ -18,6 +18,7 @@ package com.android.launcher3.appprediction;
|
|||||||
|
|
||||||
import static com.android.launcher3.LauncherState.BACKGROUND_APP;
|
import static com.android.launcher3.LauncherState.BACKGROUND_APP;
|
||||||
import static com.android.launcher3.LauncherState.OVERVIEW;
|
import static com.android.launcher3.LauncherState.OVERVIEW;
|
||||||
|
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALL_APPS_RANKED;
|
||||||
|
|
||||||
import android.app.prediction.AppPredictor;
|
import android.app.prediction.AppPredictor;
|
||||||
import android.app.prediction.AppTarget;
|
import android.app.prediction.AppTarget;
|
||||||
@@ -37,6 +38,8 @@ import com.android.launcher3.allapps.AllAppsContainerView;
|
|||||||
import com.android.launcher3.allapps.AllAppsStore.OnUpdateListener;
|
import com.android.launcher3.allapps.AllAppsStore.OnUpdateListener;
|
||||||
import com.android.launcher3.hybridhotseat.HotseatPredictionController;
|
import com.android.launcher3.hybridhotseat.HotseatPredictionController;
|
||||||
import com.android.launcher3.icons.IconCache.ItemInfoUpdateReceiver;
|
import com.android.launcher3.icons.IconCache.ItemInfoUpdateReceiver;
|
||||||
|
import com.android.launcher3.logger.LauncherAtom;
|
||||||
|
import com.android.launcher3.logging.InstanceId;
|
||||||
import com.android.launcher3.model.data.ItemInfo;
|
import com.android.launcher3.model.data.ItemInfo;
|
||||||
import com.android.launcher3.model.data.ItemInfoWithIcon;
|
import com.android.launcher3.model.data.ItemInfoWithIcon;
|
||||||
import com.android.launcher3.shortcuts.ShortcutKey;
|
import com.android.launcher3.shortcuts.ShortcutKey;
|
||||||
@@ -48,6 +51,7 @@ import com.android.launcher3.util.MainThreadInitializedObject;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.OptionalInt;
|
||||||
import java.util.stream.IntStream;
|
import java.util.stream.IntStream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -301,6 +305,41 @@ public class PredictionUiStateManager implements StateListener<LauncherState>,
|
|||||||
return mCurrentState;
|
return mCurrentState;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logs ranking info for launched app within all apps prediction.
|
||||||
|
* Only applicable when {@link ItemInfo#itemType} is one of the followings:
|
||||||
|
* {@link LauncherSettings.Favorites#ITEM_TYPE_APPLICATION},
|
||||||
|
* {@link LauncherSettings.Favorites#ITEM_TYPE_SHORTCUT},
|
||||||
|
* {@link LauncherSettings.Favorites#ITEM_TYPE_DEEP_SHORTCUT}
|
||||||
|
*/
|
||||||
|
public void logLaunchedAppRankingInfo(@NonNull ItemInfo itemInfo, InstanceId instanceId) {
|
||||||
|
if (itemInfo.getTargetComponent() == null || itemInfo.user == null
|
||||||
|
|| (itemInfo.itemType != LauncherSettings.Favorites.ITEM_TYPE_APPLICATION
|
||||||
|
&& itemInfo.itemType != LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT
|
||||||
|
&& itemInfo.itemType != LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Launcher launcher = Launcher.getLauncher(mAppsView.getContext());
|
||||||
|
final ComponentKey k = new ComponentKey(itemInfo.getTargetComponent(), itemInfo.user);
|
||||||
|
final List<ComponentKeyMapper> predictedApps = getCurrentState().apps;
|
||||||
|
OptionalInt rank = IntStream.range(0, predictedApps.size())
|
||||||
|
.filter((i) -> k.equals(predictedApps.get(i).getComponentKey()))
|
||||||
|
.findFirst();
|
||||||
|
if (!rank.isPresent()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LauncherAtom.ItemInfo.Builder atomBuilder = LauncherAtom.ItemInfo.newBuilder();
|
||||||
|
atomBuilder.setRank(rank.getAsInt());
|
||||||
|
atomBuilder.setContainerInfo(
|
||||||
|
LauncherAtom.ContainerInfo.newBuilder().setPredictionContainer(
|
||||||
|
LauncherAtom.PredictionContainer.newBuilder().build()).build());
|
||||||
|
launcher.getStatsLogManager().log(LAUNCHER_ALL_APPS_RANKED, instanceId,
|
||||||
|
atomBuilder.build());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fill in predicted_rank field based on app prediction.
|
* Fill in predicted_rank field based on app prediction.
|
||||||
* Only applicable when {@link ItemInfo#itemType} is one of the followings:
|
* Only applicable when {@link ItemInfo#itemType} is one of the followings:
|
||||||
@@ -310,6 +349,7 @@ public class PredictionUiStateManager implements StateListener<LauncherState>,
|
|||||||
*/
|
*/
|
||||||
public static void fillInPredictedRank(
|
public static void fillInPredictedRank(
|
||||||
@NonNull ItemInfo itemInfo, @NonNull LauncherLogProto.Target target) {
|
@NonNull ItemInfo itemInfo, @NonNull LauncherLogProto.Target target) {
|
||||||
|
|
||||||
final PredictionUiStateManager manager = PredictionUiStateManager.INSTANCE.getNoCreate();
|
final PredictionUiStateManager manager = PredictionUiStateManager.INSTANCE.getNoCreate();
|
||||||
if (manager == null || itemInfo.getTargetComponent() == null || itemInfo.user == null
|
if (manager == null || itemInfo.getTargetComponent() == null || itemInfo.user == null
|
||||||
|| (itemInfo.itemType != LauncherSettings.Favorites.ITEM_TYPE_APPLICATION
|
|| (itemInfo.itemType != LauncherSettings.Favorites.ITEM_TYPE_APPLICATION
|
||||||
|
|||||||
+15
-14
@@ -15,6 +15,9 @@
|
|||||||
*/
|
*/
|
||||||
package com.android.launcher3.hybridhotseat;
|
package com.android.launcher3.hybridhotseat;
|
||||||
|
|
||||||
|
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent
|
||||||
|
.LAUNCHER_HOTSEAT_EDU_ONLY_TIP;
|
||||||
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
@@ -47,12 +50,12 @@ public class HotseatEduController {
|
|||||||
public static final String KEY_HOTSEAT_EDU_SEEN = "hotseat_edu_seen";
|
public static final String KEY_HOTSEAT_EDU_SEEN = "hotseat_edu_seen";
|
||||||
public static final String HOTSEAT_EDU_ACTION =
|
public static final String HOTSEAT_EDU_ACTION =
|
||||||
"com.android.launcher3.action.SHOW_HYBRID_HOTSEAT_EDU";
|
"com.android.launcher3.action.SHOW_HYBRID_HOTSEAT_EDU";
|
||||||
private static final String SETTINGS_ACTION =
|
public static final String SETTINGS_ACTION =
|
||||||
"android.settings.ACTION_CONTENT_SUGGESTIONS_SETTINGS";
|
"android.settings.ACTION_CONTENT_SUGGESTIONS_SETTINGS";
|
||||||
|
|
||||||
private final Launcher mLauncher;
|
private final Launcher mLauncher;
|
||||||
private final Hotseat mHotseat;
|
private final Hotseat mHotseat;
|
||||||
private final HotseatRestoreHelper mRestoreHelper;
|
private HotseatRestoreHelper mRestoreHelper;
|
||||||
private List<WorkspaceItemInfo> mPredictedApps;
|
private List<WorkspaceItemInfo> mPredictedApps;
|
||||||
private HotseatEduDialog mActiveDialog;
|
private HotseatEduDialog mActiveDialog;
|
||||||
|
|
||||||
@@ -71,14 +74,17 @@ public class HotseatEduController {
|
|||||||
* Checks what type of migration should be used and migrates hotseat
|
* Checks what type of migration should be used and migrates hotseat
|
||||||
*/
|
*/
|
||||||
void migrate() {
|
void migrate() {
|
||||||
mRestoreHelper.createBackup();
|
if (mRestoreHelper != null) {
|
||||||
|
mRestoreHelper.createBackup();
|
||||||
|
}
|
||||||
if (FeatureFlags.HOTSEAT_MIGRATE_TO_FOLDER.get()) {
|
if (FeatureFlags.HOTSEAT_MIGRATE_TO_FOLDER.get()) {
|
||||||
migrateToFolder();
|
migrateToFolder();
|
||||||
} else {
|
} else {
|
||||||
migrateHotseatWhole();
|
migrateHotseatWhole();
|
||||||
}
|
}
|
||||||
Snackbar.show(mLauncher, R.string.hotsaet_tip_prediction_enabled, R.string.hotseat_turn_off,
|
Snackbar.show(mLauncher, R.string.hotsaet_tip_prediction_enabled,
|
||||||
null, () -> mLauncher.startActivity(new Intent(SETTINGS_ACTION)));
|
R.string.hotseat_prediction_settings, null,
|
||||||
|
() -> mLauncher.startActivity(new Intent(SETTINGS_ACTION)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -223,15 +229,15 @@ public class HotseatEduController {
|
|||||||
|
|
||||||
void finishOnboarding() {
|
void finishOnboarding() {
|
||||||
mOnOnboardingComplete.run();
|
mOnOnboardingComplete.run();
|
||||||
destroy();
|
|
||||||
mLauncher.getSharedPrefs().edit().putBoolean(KEY_HOTSEAT_EDU_SEEN, true).apply();
|
mLauncher.getSharedPrefs().edit().putBoolean(KEY_HOTSEAT_EDU_SEEN, true).apply();
|
||||||
}
|
}
|
||||||
|
|
||||||
void showDimissTip() {
|
void showDimissTip() {
|
||||||
if (mHotseat.getShortcutsAndWidgets().getChildCount()
|
if (mHotseat.getShortcutsAndWidgets().getChildCount()
|
||||||
< mLauncher.getDeviceProfile().inv.numHotseatIcons) {
|
< mLauncher.getDeviceProfile().inv.numHotseatIcons) {
|
||||||
Snackbar.show(mLauncher, R.string.hotseat_tip_gaps_filled, R.string.hotseat_turn_off,
|
Snackbar.show(mLauncher, R.string.hotseat_tip_gaps_filled,
|
||||||
null, () -> mLauncher.startActivity(new Intent(SETTINGS_ACTION)));
|
R.string.hotseat_prediction_settings, null,
|
||||||
|
() -> mLauncher.startActivity(new Intent(SETTINGS_ACTION)));
|
||||||
} else {
|
} else {
|
||||||
new ArrowTipView(mLauncher).show(
|
new ArrowTipView(mLauncher).show(
|
||||||
mLauncher.getString(R.string.hotseat_tip_no_empty_slots), mHotseat.getTop());
|
mLauncher.getString(R.string.hotseat_tip_no_empty_slots), mHotseat.getTop());
|
||||||
@@ -242,12 +248,6 @@ public class HotseatEduController {
|
|||||||
mPredictedApps = predictedApps;
|
mPredictedApps = predictedApps;
|
||||||
}
|
}
|
||||||
|
|
||||||
void destroy() {
|
|
||||||
if (mActiveDialog != null) {
|
|
||||||
mActiveDialog.setHotseatEduController(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void showEdu() {
|
void showEdu() {
|
||||||
int childCount = mHotseat.getShortcutsAndWidgets().getChildCount();
|
int childCount = mHotseat.getShortcutsAndWidgets().getChildCount();
|
||||||
CellLayout cellLayout = mLauncher.getWorkspace().getScreenWithId(Workspace.FIRST_SCREEN_ID);
|
CellLayout cellLayout = mLauncher.getWorkspace().getScreenWithId(Workspace.FIRST_SCREEN_ID);
|
||||||
@@ -265,6 +265,7 @@ public class HotseatEduController {
|
|||||||
requiresMigration ? R.string.hotseat_tip_no_empty_slots
|
requiresMigration ? R.string.hotseat_tip_no_empty_slots
|
||||||
: R.string.hotseat_auto_enrolled),
|
: R.string.hotseat_auto_enrolled),
|
||||||
mHotseat.getTop());
|
mHotseat.getTop());
|
||||||
|
mLauncher.getStatsLogManager().log(LAUNCHER_HOTSEAT_EDU_ONLY_TIP);
|
||||||
finishOnboarding();
|
finishOnboarding();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-43
@@ -15,9 +15,10 @@
|
|||||||
*/
|
*/
|
||||||
package com.android.launcher3.hybridhotseat;
|
package com.android.launcher3.hybridhotseat;
|
||||||
|
|
||||||
import static com.android.launcher3.logging.LoggerUtils.newLauncherEvent;
|
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent
|
||||||
import static com.android.launcher3.userevent.nano.LauncherLogProto.ControlType
|
.LAUNCHER_HOTSEAT_EDU_ACCEPT;
|
||||||
.HYBRID_HOTSEAT_CANCELED;
|
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_HOTSEAT_EDU_DENY;
|
||||||
|
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_HOTSEAT_EDU_SEEN;
|
||||||
|
|
||||||
import android.animation.PropertyValuesHolder;
|
import android.animation.PropertyValuesHolder;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
@@ -29,15 +30,14 @@ import android.view.View;
|
|||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import com.android.launcher3.AbstractFloatingView;
|
||||||
import com.android.launcher3.CellLayout;
|
import com.android.launcher3.CellLayout;
|
||||||
import com.android.launcher3.DeviceProfile;
|
import com.android.launcher3.DeviceProfile;
|
||||||
import com.android.launcher3.Insettable;
|
import com.android.launcher3.Insettable;
|
||||||
import com.android.launcher3.Launcher;
|
import com.android.launcher3.Launcher;
|
||||||
import com.android.launcher3.R;
|
import com.android.launcher3.R;
|
||||||
import com.android.launcher3.Workspace;
|
|
||||||
import com.android.launcher3.anim.Interpolators;
|
import com.android.launcher3.anim.Interpolators;
|
||||||
import com.android.launcher3.config.FeatureFlags;
|
import com.android.launcher3.config.FeatureFlags;
|
||||||
import com.android.launcher3.logging.UserEventDispatcher;
|
|
||||||
import com.android.launcher3.model.data.WorkspaceItemInfo;
|
import com.android.launcher3.model.data.WorkspaceItemInfo;
|
||||||
import com.android.launcher3.uioverrides.PredictedAppIcon;
|
import com.android.launcher3.uioverrides.PredictedAppIcon;
|
||||||
import com.android.launcher3.userevent.nano.LauncherLogProto;
|
import com.android.launcher3.userevent.nano.LauncherLogProto;
|
||||||
@@ -111,15 +111,13 @@ public class HotseatEduDialog extends AbstractSlideInView implements Insettable
|
|||||||
|
|
||||||
mHotseatEduController.moveHotseatItems();
|
mHotseatEduController.moveHotseatItems();
|
||||||
mHotseatEduController.finishOnboarding();
|
mHotseatEduController.finishOnboarding();
|
||||||
//TODO: pass actual page index here.
|
mLauncher.getStatsLogManager().log(LAUNCHER_HOTSEAT_EDU_ACCEPT);
|
||||||
// Temporarily we're passing 1 for folder migration and 2 for page migration
|
|
||||||
logUserAction(true, FeatureFlags.HOTSEAT_MIGRATE_TO_FOLDER.get() ? 1 : 2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onDismiss(View v) {
|
private void onDismiss(View v) {
|
||||||
mHotseatEduController.showDimissTip();
|
mHotseatEduController.showDimissTip();
|
||||||
mHotseatEduController.finishOnboarding();
|
mHotseatEduController.finishOnboarding();
|
||||||
logUserAction(false, -1);
|
mLauncher.getStatsLogManager().log(LAUNCHER_HOTSEAT_EDU_DENY);
|
||||||
handleClose(true);
|
handleClose(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -163,39 +161,6 @@ public class HotseatEduDialog extends AbstractSlideInView implements Insettable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void logUserAction(boolean migrated, int pageIndex) {
|
|
||||||
LauncherLogProto.Action action = new LauncherLogProto.Action();
|
|
||||||
LauncherLogProto.Target target = new LauncherLogProto.Target();
|
|
||||||
|
|
||||||
int hotseatItemsCount = mLauncher.getHotseat().getShortcutsAndWidgets().getChildCount();
|
|
||||||
// -1 to exclude smart space
|
|
||||||
int workspaceItemCount = mLauncher.getWorkspace().getScreenWithId(
|
|
||||||
Workspace.FIRST_SCREEN_ID).getShortcutsAndWidgets().getChildCount() - 1;
|
|
||||||
|
|
||||||
action.type = LauncherLogProto.Action.Type.TOUCH;
|
|
||||||
action.touch = LauncherLogProto.Action.Touch.TAP;
|
|
||||||
target.containerType = LauncherLogProto.ContainerType.TIP;
|
|
||||||
target.tipType = LauncherLogProto.TipType.HYBRID_HOTSEAT;
|
|
||||||
target.controlType = migrated ? LauncherLogProto.ControlType.HYBRID_HOTSEAT_ACCEPTED
|
|
||||||
: HYBRID_HOTSEAT_CANCELED;
|
|
||||||
target.rank = MIGRATION_EXPERIMENT_IDENTIFIER;
|
|
||||||
// encoding migration type on pageIndex
|
|
||||||
target.pageIndex = pageIndex;
|
|
||||||
target.cardinality = (workspaceItemCount * 1000) + hotseatItemsCount;
|
|
||||||
LauncherLogProto.LauncherEvent event = newLauncherEvent(action, target);
|
|
||||||
UserEventDispatcher.newInstance(getContext()).dispatchUserEvent(event, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void logOnBoardingSeen() {
|
|
||||||
LauncherLogProto.Action action = new LauncherLogProto.Action();
|
|
||||||
LauncherLogProto.Target target = new LauncherLogProto.Target();
|
|
||||||
action.type = LauncherLogProto.Action.Type.TIP;
|
|
||||||
target.containerType = LauncherLogProto.ContainerType.TIP;
|
|
||||||
target.tipType = LauncherLogProto.TipType.HYBRID_HOTSEAT;
|
|
||||||
LauncherLogProto.LauncherEvent event = newLauncherEvent(action, target);
|
|
||||||
UserEventDispatcher.newInstance(getContext()).dispatchUserEvent(event, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void animateOpen() {
|
private void animateOpen() {
|
||||||
if (mIsOpen || mOpenCloseAnimator.isRunning()) {
|
if (mIsOpen || mOpenCloseAnimator.isRunning()) {
|
||||||
return;
|
return;
|
||||||
@@ -244,8 +209,9 @@ public class HotseatEduDialog extends AbstractSlideInView implements Insettable
|
|||||||
|| mHotseatEduController == null) {
|
|| mHotseatEduController == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
AbstractFloatingView.closeAllOpenViews(mLauncher);
|
||||||
attachToContainer();
|
attachToContainer();
|
||||||
logOnBoardingSeen();
|
mLauncher.getStatsLogManager().log(LAUNCHER_HOTSEAT_EDU_SEEN);
|
||||||
animateOpen();
|
animateOpen();
|
||||||
populatePreview(predictions);
|
populatePreview(predictions);
|
||||||
}
|
}
|
||||||
|
|||||||
+129
@@ -0,0 +1,129 @@
|
|||||||
|
/*
|
||||||
|
* 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 android.content.Context;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.android.launcher3.logging.FileLog;
|
||||||
|
import com.android.launcher3.util.Executors;
|
||||||
|
import com.android.launcher3.util.MainThreadInitializedObject;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileWriter;
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
import java.text.DateFormat;
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper class to allow hot seat file logging
|
||||||
|
*/
|
||||||
|
public class HotseatFileLog {
|
||||||
|
|
||||||
|
public static final int LOG_DAYS = 10;
|
||||||
|
private static final String FILE_NAME_PREFIX = "hotseat-log-";
|
||||||
|
private static final DateFormat DATE_FORMAT =
|
||||||
|
DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT);
|
||||||
|
public static final MainThreadInitializedObject<HotseatFileLog> INSTANCE =
|
||||||
|
new MainThreadInitializedObject<>(HotseatFileLog::new);
|
||||||
|
|
||||||
|
|
||||||
|
private final Handler mHandler = new Handler(
|
||||||
|
Executors.createAndStartNewLooper("hotseat-logger"));
|
||||||
|
private final File mLogsDir;
|
||||||
|
private PrintWriter mCurrentWriter;
|
||||||
|
private String mFileName;
|
||||||
|
|
||||||
|
private HotseatFileLog(Context context) {
|
||||||
|
mLogsDir = context.getFilesDir();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prints log values to disk
|
||||||
|
*/
|
||||||
|
public void log(String tag, String msg) {
|
||||||
|
String out = String.format("%s %s %s", DATE_FORMAT.format(new Date()), tag, msg);
|
||||||
|
|
||||||
|
mHandler.post(() -> {
|
||||||
|
synchronized (this) {
|
||||||
|
PrintWriter writer = getWriter();
|
||||||
|
if (writer != null) {
|
||||||
|
writer.println(out);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private PrintWriter getWriter() {
|
||||||
|
String fName = FILE_NAME_PREFIX + (LOG_DAYS % 10);
|
||||||
|
if (fName.equals(mFileName)) return mCurrentWriter;
|
||||||
|
|
||||||
|
Calendar cal = Calendar.getInstance();
|
||||||
|
|
||||||
|
boolean append = false;
|
||||||
|
File logFile = new File(mLogsDir, fName);
|
||||||
|
if (logFile.exists()) {
|
||||||
|
Calendar modifiedTime = Calendar.getInstance();
|
||||||
|
modifiedTime.setTimeInMillis(logFile.lastModified());
|
||||||
|
|
||||||
|
// If the file was modified more that 36 hours ago, purge the file.
|
||||||
|
// We use instead of 24 to account for day-365 followed by day-1
|
||||||
|
modifiedTime.add(Calendar.HOUR, 36);
|
||||||
|
append = cal.before(modifiedTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (mCurrentWriter != null) {
|
||||||
|
mCurrentWriter.close();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
mCurrentWriter = new PrintWriter(new FileWriter(logFile, append));
|
||||||
|
mFileName = fName;
|
||||||
|
} catch (Exception ex) {
|
||||||
|
Log.e("HotseatLogs", "Error writing logs to file", ex);
|
||||||
|
closeWriter();
|
||||||
|
}
|
||||||
|
return mCurrentWriter;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private synchronized void closeWriter() {
|
||||||
|
mFileName = null;
|
||||||
|
if (mCurrentWriter != null) {
|
||||||
|
mCurrentWriter.close();
|
||||||
|
}
|
||||||
|
mCurrentWriter = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a list of all log files
|
||||||
|
*/
|
||||||
|
public synchronized File[] getLogFiles() {
|
||||||
|
File[] files = new File[LOG_DAYS + FileLog.LOG_DAYS];
|
||||||
|
//include file log files here
|
||||||
|
System.arraycopy(FileLog.getLogFiles(), 0, files, 0, FileLog.LOG_DAYS);
|
||||||
|
|
||||||
|
closeWriter();
|
||||||
|
for (int i = 0; i < LOG_DAYS; i++) {
|
||||||
|
files[FileLog.LOG_DAYS + i] = new File(mLogsDir, FILE_NAME_PREFIX + i);
|
||||||
|
}
|
||||||
|
return files;
|
||||||
|
}
|
||||||
|
}
|
||||||
+99
-20
@@ -17,6 +17,8 @@ package com.android.launcher3.hybridhotseat;
|
|||||||
|
|
||||||
import static com.android.launcher3.InvariantDeviceProfile.CHANGE_FLAG_GRID;
|
import static com.android.launcher3.InvariantDeviceProfile.CHANGE_FLAG_GRID;
|
||||||
import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
|
import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
|
||||||
|
import static com.android.launcher3.hybridhotseat.HotseatEduController.SETTINGS_ACTION;
|
||||||
|
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_HOTSEAT_RANKED;
|
||||||
|
|
||||||
import android.animation.Animator;
|
import android.animation.Animator;
|
||||||
import android.animation.AnimatorSet;
|
import android.animation.AnimatorSet;
|
||||||
@@ -27,6 +29,8 @@ import android.app.prediction.AppPredictor;
|
|||||||
import android.app.prediction.AppTarget;
|
import android.app.prediction.AppTarget;
|
||||||
import android.app.prediction.AppTargetEvent;
|
import android.app.prediction.AppTargetEvent;
|
||||||
import android.content.ComponentName;
|
import android.content.ComponentName;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Process;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
@@ -50,7 +54,8 @@ import com.android.launcher3.appprediction.DynamicItemCache;
|
|||||||
import com.android.launcher3.dragndrop.DragController;
|
import com.android.launcher3.dragndrop.DragController;
|
||||||
import com.android.launcher3.dragndrop.DragOptions;
|
import com.android.launcher3.dragndrop.DragOptions;
|
||||||
import com.android.launcher3.icons.IconCache;
|
import com.android.launcher3.icons.IconCache;
|
||||||
import com.android.launcher3.logging.FileLog;
|
import com.android.launcher3.logger.LauncherAtom;
|
||||||
|
import com.android.launcher3.logging.InstanceId;
|
||||||
import com.android.launcher3.model.data.AppInfo;
|
import com.android.launcher3.model.data.AppInfo;
|
||||||
import com.android.launcher3.model.data.FolderInfo;
|
import com.android.launcher3.model.data.FolderInfo;
|
||||||
import com.android.launcher3.model.data.ItemInfo;
|
import com.android.launcher3.model.data.ItemInfo;
|
||||||
@@ -64,6 +69,8 @@ import com.android.launcher3.uioverrides.QuickstepLauncher;
|
|||||||
import com.android.launcher3.userevent.nano.LauncherLogProto;
|
import com.android.launcher3.userevent.nano.LauncherLogProto;
|
||||||
import com.android.launcher3.util.ComponentKey;
|
import com.android.launcher3.util.ComponentKey;
|
||||||
import com.android.launcher3.util.IntArray;
|
import com.android.launcher3.util.IntArray;
|
||||||
|
import com.android.launcher3.views.ArrowTipView;
|
||||||
|
import com.android.launcher3.views.Snackbar;
|
||||||
|
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -107,8 +114,6 @@ public class HotseatPredictionController implements DragController.DragListener,
|
|||||||
private boolean mIsCacheEmpty;
|
private boolean mIsCacheEmpty;
|
||||||
private boolean mIsDestroyed = false;
|
private boolean mIsDestroyed = false;
|
||||||
|
|
||||||
private HotseatEduController mHotseatEduController;
|
|
||||||
|
|
||||||
|
|
||||||
private List<PredictedAppIcon.PredictedIconOutlineDrawing> mOutlineDrawings = new ArrayList<>();
|
private List<PredictedAppIcon.PredictedIconOutlineDrawing> mOutlineDrawings = new ArrayList<>();
|
||||||
|
|
||||||
@@ -146,11 +151,47 @@ public class HotseatPredictionController implements DragController.DragListener,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transitions to NORMAL workspace mode and shows edu
|
* Shows appropriate hotseat education based on prediction enabled and migration states.
|
||||||
*/
|
*/
|
||||||
public void showEdu() {
|
public void showEdu() {
|
||||||
if (mHotseatEduController == null) return;
|
if (mComponentKeyMappers.isEmpty()) {
|
||||||
mHotseatEduController.showEdu();
|
// launcher has empty predictions set
|
||||||
|
Snackbar.show(mLauncher, R.string.hotsaet_tip_prediction_disabled,
|
||||||
|
R.string.hotseat_prediction_settings, null,
|
||||||
|
() -> mLauncher.startActivity(
|
||||||
|
new Intent(SETTINGS_ACTION)));
|
||||||
|
} else if (isEduSeen()) {
|
||||||
|
// user has already went through education
|
||||||
|
new ArrowTipView(mLauncher).show(
|
||||||
|
mLauncher.getString(R.string.hotsaet_tip_prediction_enabled),
|
||||||
|
mHotseat.getTop());
|
||||||
|
} else {
|
||||||
|
HotseatEduController eduController = new HotseatEduController(mLauncher, mRestoreHelper,
|
||||||
|
this::createPredictor);
|
||||||
|
eduController.setPredictedApps(mapToWorkspaceItemInfo(mComponentKeyMappers));
|
||||||
|
eduController.showEdu();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows educational tip for hotseat if user does not go through Tips app.
|
||||||
|
*/
|
||||||
|
public void showDiscoveryTip() {
|
||||||
|
if (getPredictedIcons().size() == mHotSeatItemsCount) {
|
||||||
|
new ArrowTipView(mLauncher).show(
|
||||||
|
mLauncher.getString(R.string.hotseat_tip_no_empty_slots), mHotseat.getTop());
|
||||||
|
} else {
|
||||||
|
Snackbar.show(mLauncher, R.string.hotseat_tip_gaps_filled,
|
||||||
|
R.string.hotseat_prediction_settings, null,
|
||||||
|
() -> mLauncher.startActivity(new Intent(SETTINGS_ACTION)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns if hotseat client has predictions
|
||||||
|
*/
|
||||||
|
public boolean hasPredictions() {
|
||||||
|
return !mComponentKeyMappers.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -250,10 +291,6 @@ public class HotseatPredictionController implements DragController.DragListener,
|
|||||||
if (mAppPredictor != null) {
|
if (mAppPredictor != null) {
|
||||||
mAppPredictor.destroy();
|
mAppPredictor.destroy();
|
||||||
}
|
}
|
||||||
if (mHotseatEduController != null) {
|
|
||||||
mHotseatEduController.destroy();
|
|
||||||
mHotseatEduController = null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -299,20 +336,20 @@ public class HotseatPredictionController implements DragController.DragListener,
|
|||||||
mAppPredictor.requestPredictionUpdate();
|
mAppPredictor.requestPredictionUpdate();
|
||||||
});
|
});
|
||||||
setPauseUIUpdate(false);
|
setPauseUIUpdate(false);
|
||||||
if (!isEduSeen()) {
|
|
||||||
mHotseatEduController = new HotseatEduController(mLauncher, mRestoreHelper,
|
|
||||||
this::createPredictor);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create WorkspaceItemInfo objects and binds PredictedAppIcon views for cached predicted items.
|
* Create WorkspaceItemInfo objects and binds PredictedAppIcon views for cached predicted items.
|
||||||
*/
|
*/
|
||||||
public void showCachedItems(List<AppInfo> apps, IntArray ranks) {
|
public void showCachedItems(List<AppInfo> apps, IntArray ranks) {
|
||||||
|
if (hasPredictions() && mAppPredictor != null) {
|
||||||
|
mAppPredictor.requestPredictionUpdate();
|
||||||
|
fillGapsWithPrediction();
|
||||||
|
return;
|
||||||
|
}
|
||||||
mIsCacheEmpty = apps.isEmpty();
|
mIsCacheEmpty = apps.isEmpty();
|
||||||
int count = Math.min(ranks.size(), apps.size());
|
int count = Math.min(ranks.size(), apps.size());
|
||||||
List<WorkspaceItemInfo> items = new ArrayList<>(count);
|
List<WorkspaceItemInfo> items = new ArrayList<>(count);
|
||||||
mComponentKeyMappers.clear();
|
|
||||||
for (int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
WorkspaceItemInfo item = new WorkspaceItemInfo(apps.get(i));
|
WorkspaceItemInfo item = new WorkspaceItemInfo(apps.get(i));
|
||||||
ComponentKey componentKey = new ComponentKey(item.getTargetComponent(), item.user);
|
ComponentKey componentKey = new ComponentKey(item.getTargetComponent(), item.user);
|
||||||
@@ -324,6 +361,7 @@ public class HotseatPredictionController implements DragController.DragListener,
|
|||||||
updateDependencies();
|
updateDependencies();
|
||||||
bindItems(items, false, null);
|
bindItems(items, false, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setPredictedApps(List<AppTarget> appTargets) {
|
private void setPredictedApps(List<AppTarget> appTargets) {
|
||||||
mComponentKeyMappers.clear();
|
mComponentKeyMappers.clear();
|
||||||
if (appTargets.isEmpty()) {
|
if (appTargets.isEmpty()) {
|
||||||
@@ -347,12 +385,11 @@ public class HotseatPredictionController implements DragController.DragListener,
|
|||||||
mComponentKeyMappers.add(new ComponentKeyMapper(key, mDynamicItemCache));
|
mComponentKeyMappers.add(new ComponentKeyMapper(key, mDynamicItemCache));
|
||||||
}
|
}
|
||||||
predictionLog.append("]");
|
predictionLog.append("]");
|
||||||
if (Utilities.IS_DEBUG_DEVICE) FileLog.d(TAG, predictionLog.toString());
|
if (Utilities.IS_DEBUG_DEVICE) {
|
||||||
|
HotseatFileLog.INSTANCE.get(mLauncher).log(TAG, predictionLog.toString());
|
||||||
|
}
|
||||||
updateDependencies();
|
updateDependencies();
|
||||||
fillGapsWithPrediction();
|
fillGapsWithPrediction();
|
||||||
if (!isEduSeen() && mHotseatEduController != null) {
|
|
||||||
mHotseatEduController.setPredictedApps(mapToWorkspaceItemInfo(mComponentKeyMappers));
|
|
||||||
}
|
|
||||||
cachePredictionComponentKeysIfNecessary(componentKeys);
|
cachePredictionComponentKeysIfNecessary(componentKeys);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -602,6 +639,48 @@ public class HotseatPredictionController implements DragController.DragListener,
|
|||||||
mHotseat.fillInLogContainerData(childInfo, child, parents);
|
mHotseat.fillInLogContainerData(childInfo, child, parents);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logs rank info based on current list of predicted items
|
||||||
|
*/
|
||||||
|
public void logLaunchedAppRankingInfo(@NonNull ItemInfo itemInfo, InstanceId instanceId) {
|
||||||
|
if (Utilities.IS_DEBUG_DEVICE) {
|
||||||
|
final String pkg = itemInfo.getTargetComponent() != null
|
||||||
|
? itemInfo.getTargetComponent().getPackageName() : "unknown";
|
||||||
|
HotseatFileLog.INSTANCE.get(mLauncher).log("UserEvent",
|
||||||
|
"appLaunch: packageName:" + pkg + ",isWorkApp:" + (itemInfo.user != null
|
||||||
|
&& !Process.myUserHandle().equals(itemInfo.user))
|
||||||
|
+ ",launchLocation:" + itemInfo.container);
|
||||||
|
}
|
||||||
|
|
||||||
|
final ComponentKey k = new ComponentKey(itemInfo.getTargetComponent(), itemInfo.user);
|
||||||
|
|
||||||
|
final List<ComponentKeyMapper> predictedApps = new ArrayList<>(mComponentKeyMappers);
|
||||||
|
OptionalInt rank = IntStream.range(0, predictedApps.size())
|
||||||
|
.filter((i) -> k.equals(predictedApps.get(i).getComponentKey()))
|
||||||
|
.findFirst();
|
||||||
|
if (!rank.isPresent()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
LauncherAtom.PredictedHotseatContainer.Builder containerBuilder =
|
||||||
|
LauncherAtom.PredictedHotseatContainer.newBuilder();
|
||||||
|
LauncherAtom.ItemInfo.Builder atomBuilder = LauncherAtom.ItemInfo.newBuilder();
|
||||||
|
int cardinality = 0;
|
||||||
|
for (PredictedAppIcon icon : getPredictedIcons()) {
|
||||||
|
ItemInfo info = (ItemInfo) icon.getTag();
|
||||||
|
cardinality |= 1 << info.screenId;
|
||||||
|
}
|
||||||
|
containerBuilder.setCardinality(cardinality);
|
||||||
|
atomBuilder.setRank(rank.getAsInt());
|
||||||
|
if (itemInfo.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION) {
|
||||||
|
containerBuilder.setIndex(rank.getAsInt());
|
||||||
|
}
|
||||||
|
atomBuilder.setContainerInfo(
|
||||||
|
LauncherAtom.ContainerInfo.newBuilder().setPredictedHotseatContainer(
|
||||||
|
containerBuilder).build());
|
||||||
|
mLauncher.getStatsLogManager().log(LAUNCHER_HOTSEAT_RANKED, instanceId,
|
||||||
|
atomBuilder.build());
|
||||||
|
}
|
||||||
|
|
||||||
private class PinPrediction extends SystemShortcut<QuickstepLauncher> {
|
private class PinPrediction extends SystemShortcut<QuickstepLauncher> {
|
||||||
|
|
||||||
private PinPrediction(QuickstepLauncher target, ItemInfo itemInfo) {
|
private PinPrediction(QuickstepLauncher target, ItemInfo itemInfo) {
|
||||||
|
|||||||
+13
-11
@@ -29,7 +29,6 @@ import static com.android.quickstep.SysUINavigationMode.Mode.NO_BUTTON;
|
|||||||
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.res.Configuration;
|
import android.content.res.Configuration;
|
||||||
import android.os.Bundle;
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
@@ -42,10 +41,12 @@ import com.android.launcher3.LauncherState;
|
|||||||
import com.android.launcher3.Workspace;
|
import com.android.launcher3.Workspace;
|
||||||
import com.android.launcher3.allapps.DiscoveryBounce;
|
import com.android.launcher3.allapps.DiscoveryBounce;
|
||||||
import com.android.launcher3.anim.AnimatorPlaybackController;
|
import com.android.launcher3.anim.AnimatorPlaybackController;
|
||||||
|
import com.android.launcher3.appprediction.PredictionUiStateManager;
|
||||||
import com.android.launcher3.config.FeatureFlags;
|
import com.android.launcher3.config.FeatureFlags;
|
||||||
import com.android.launcher3.folder.Folder;
|
import com.android.launcher3.folder.Folder;
|
||||||
import com.android.launcher3.hybridhotseat.HotseatEduController;
|
import com.android.launcher3.hybridhotseat.HotseatEduController;
|
||||||
import com.android.launcher3.hybridhotseat.HotseatPredictionController;
|
import com.android.launcher3.hybridhotseat.HotseatPredictionController;
|
||||||
|
import com.android.launcher3.logging.InstanceId;
|
||||||
import com.android.launcher3.model.data.AppInfo;
|
import com.android.launcher3.model.data.AppInfo;
|
||||||
import com.android.launcher3.model.data.ItemInfo;
|
import com.android.launcher3.model.data.ItemInfo;
|
||||||
import com.android.launcher3.model.data.WorkspaceItemInfo;
|
import com.android.launcher3.model.data.WorkspaceItemInfo;
|
||||||
@@ -88,11 +89,10 @@ public class QuickstepLauncher extends BaseQuickstepLauncher {
|
|||||||
*/
|
*/
|
||||||
public static final AsyncCommand SET_SHELF_HEIGHT = (context, arg1, arg2) ->
|
public static final AsyncCommand SET_SHELF_HEIGHT = (context, arg1, arg2) ->
|
||||||
SystemUiProxy.INSTANCE.get(context).setShelfHeight(arg1 != 0, arg2);
|
SystemUiProxy.INSTANCE.get(context).setShelfHeight(arg1 != 0, arg2);
|
||||||
private HotseatPredictionController mHotseatPredictionController;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void setupViews() {
|
||||||
super.onCreate(savedInstanceState);
|
super.setupViews();
|
||||||
if (FeatureFlags.ENABLE_HYBRID_HOTSEAT.get()) {
|
if (FeatureFlags.ENABLE_HYBRID_HOTSEAT.get()) {
|
||||||
mHotseatPredictionController = new HotseatPredictionController(this);
|
mHotseatPredictionController = new HotseatPredictionController(this);
|
||||||
mHotseatPredictionController.createPredictor();
|
mHotseatPredictionController.createPredictor();
|
||||||
@@ -113,6 +113,15 @@ public class QuickstepLauncher extends BaseQuickstepLauncher {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void logAppLaunch(ItemInfo info, InstanceId instanceId) {
|
||||||
|
super.logAppLaunch(info, instanceId);
|
||||||
|
if (mHotseatPredictionController != null) {
|
||||||
|
mHotseatPredictionController.logLaunchedAppRankingInfo(info, instanceId);
|
||||||
|
}
|
||||||
|
PredictionUiStateManager.INSTANCE.get(this).logLaunchedAppRankingInfo(info, instanceId);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onConfigurationChanged(Configuration newConfig) {
|
public void onConfigurationChanged(Configuration newConfig) {
|
||||||
super.onConfigurationChanged(newConfig);
|
super.onConfigurationChanged(newConfig);
|
||||||
@@ -168,13 +177,6 @@ public class QuickstepLauncher extends BaseQuickstepLauncher {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns Prediction controller for hybrid hotseat
|
|
||||||
*/
|
|
||||||
public HotseatPredictionController getHotseatPredictionController() {
|
|
||||||
return mHotseatPredictionController;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Recents logic that triggers when launcher state changes or launcher activity stops/resumes.
|
* Recents logic that triggers when launcher state changes or launcher activity stops/resumes.
|
||||||
*/
|
*/
|
||||||
|
|||||||
+12
@@ -20,6 +20,7 @@ import android.graphics.Rect;
|
|||||||
|
|
||||||
import com.android.launcher3.BaseDraggingActivity;
|
import com.android.launcher3.BaseDraggingActivity;
|
||||||
import com.android.launcher3.Launcher;
|
import com.android.launcher3.Launcher;
|
||||||
|
import com.android.launcher3.LauncherState;
|
||||||
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
|
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
|
||||||
import com.android.quickstep.views.RecentsView;
|
import com.android.quickstep.views.RecentsView;
|
||||||
|
|
||||||
@@ -56,6 +57,17 @@ public class OverviewModalTaskState extends OverviewState {
|
|||||||
return 1.0f;
|
return 1.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBackPressed(Launcher launcher) {
|
||||||
|
launcher.getStateManager().goToState(LauncherState.OVERVIEW);
|
||||||
|
RecentsView recentsView = launcher.<RecentsView>getOverviewPanel();
|
||||||
|
if (recentsView != null) {
|
||||||
|
recentsView.resetModalVisuals();
|
||||||
|
} else {
|
||||||
|
super.onBackPressed(launcher);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static float[] getOverviewScaleAndOffsetForModalState(BaseDraggingActivity activity) {
|
public static float[] getOverviewScaleAndOffsetForModalState(BaseDraggingActivity activity) {
|
||||||
Rect out = new Rect();
|
Rect out = new Rect();
|
||||||
activity.<RecentsView>getOverviewPanel().getTaskSize(out);
|
activity.<RecentsView>getOverviewPanel().getTaskSize(out);
|
||||||
|
|||||||
+2
@@ -156,6 +156,7 @@ public class QuickstepAtomicAnimationFactory extends
|
|||||||
if (toState == NORMAL && fromState == OVERVIEW) {
|
if (toState == NORMAL && fromState == OVERVIEW) {
|
||||||
config.setInterpolator(ANIM_WORKSPACE_SCALE, DEACCEL);
|
config.setInterpolator(ANIM_WORKSPACE_SCALE, DEACCEL);
|
||||||
config.setInterpolator(ANIM_WORKSPACE_FADE, ACCEL);
|
config.setInterpolator(ANIM_WORKSPACE_FADE, ACCEL);
|
||||||
|
config.setInterpolator(ANIM_ALL_APPS_FADE, ACCEL);
|
||||||
config.setInterpolator(ANIM_OVERVIEW_SCALE, clampToProgress(ACCEL, 0, 0.9f));
|
config.setInterpolator(ANIM_OVERVIEW_SCALE, clampToProgress(ACCEL, 0, 0.9f));
|
||||||
config.setInterpolator(ANIM_OVERVIEW_TRANSLATE_X, ACCEL);
|
config.setInterpolator(ANIM_OVERVIEW_TRANSLATE_X, ACCEL);
|
||||||
config.setInterpolator(ANIM_OVERVIEW_FADE, DEACCEL_1_7);
|
config.setInterpolator(ANIM_OVERVIEW_FADE, DEACCEL_1_7);
|
||||||
@@ -210,6 +211,7 @@ public class QuickstepAtomicAnimationFactory extends
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
config.setInterpolator(ANIM_WORKSPACE_FADE, OVERSHOOT_1_2);
|
config.setInterpolator(ANIM_WORKSPACE_FADE, OVERSHOOT_1_2);
|
||||||
|
config.setInterpolator(ANIM_ALL_APPS_FADE, OVERSHOOT_1_2);
|
||||||
config.setInterpolator(ANIM_OVERVIEW_SCALE, OVERSHOOT_1_2);
|
config.setInterpolator(ANIM_OVERVIEW_SCALE, OVERSHOOT_1_2);
|
||||||
config.setInterpolator(ANIM_DEPTH, OVERSHOOT_1_2);
|
config.setInterpolator(ANIM_DEPTH, OVERSHOOT_1_2);
|
||||||
Interpolator translationInterpolator = ENABLE_OVERVIEW_ACTIONS.get()
|
Interpolator translationInterpolator = ENABLE_OVERVIEW_ACTIONS.get()
|
||||||
|
|||||||
@@ -32,7 +32,6 @@ import androidx.annotation.CallSuper;
|
|||||||
import androidx.annotation.UiThread;
|
import androidx.annotation.UiThread;
|
||||||
|
|
||||||
import com.android.launcher3.DeviceProfile;
|
import com.android.launcher3.DeviceProfile;
|
||||||
import com.android.launcher3.InvariantDeviceProfile;
|
|
||||||
import com.android.launcher3.statemanager.StatefulActivity;
|
import com.android.launcher3.statemanager.StatefulActivity;
|
||||||
import com.android.launcher3.testing.TestProtocol;
|
import com.android.launcher3.testing.TestProtocol;
|
||||||
import com.android.launcher3.util.VibratorWrapper;
|
import com.android.launcher3.util.VibratorWrapper;
|
||||||
@@ -96,8 +95,8 @@ public abstract class BaseSwipeUpHandler<T extends StatefulActivity<?>, Q extend
|
|||||||
* depend on proper class initialization.
|
* depend on proper class initialization.
|
||||||
*/
|
*/
|
||||||
protected void initAfterSubclassConstructor() {
|
protected void initAfterSubclassConstructor() {
|
||||||
initTransitionEndpoints(InvariantDeviceProfile.INSTANCE.get(mContext)
|
initTransitionEndpoints(
|
||||||
.getDeviceProfile(mContext));
|
mTaskViewSimulator.getOrientationState().getLauncherDeviceProfile());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void performHapticFeedback() {
|
protected void performHapticFeedback() {
|
||||||
@@ -144,13 +143,14 @@ public abstract class BaseSwipeUpHandler<T extends StatefulActivity<?>, Q extend
|
|||||||
TaskView nextTask = mRecentsView.getTaskView(taskId);
|
TaskView nextTask = mRecentsView.getTaskView(taskId);
|
||||||
if (nextTask != null) {
|
if (nextTask != null) {
|
||||||
mGestureState.updateLastStartedTaskId(taskId);
|
mGestureState.updateLastStartedTaskId(taskId);
|
||||||
|
boolean hasTaskPreviouslyAppeared = mGestureState.getPreviouslyAppearedTaskIds()
|
||||||
|
.contains(taskId);
|
||||||
nextTask.launchTask(false /* animate */, true /* freezeTaskList */,
|
nextTask.launchTask(false /* animate */, true /* freezeTaskList */,
|
||||||
success -> {
|
success -> {
|
||||||
resultCallback.accept(success);
|
resultCallback.accept(success);
|
||||||
if (success) {
|
if (success) {
|
||||||
if (mRecentsView.indexOfChild(nextTask)
|
if (hasTaskPreviouslyAppeared) {
|
||||||
== getLastAppearedTaskIndex()) {
|
onRestartPreviouslyAppearedTask();
|
||||||
onRestartLastAppearedTask();
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
mActivityInterface.onLaunchTaskFailed();
|
mActivityInterface.onLaunchTaskFailed();
|
||||||
@@ -171,7 +171,7 @@ public abstract class BaseSwipeUpHandler<T extends StatefulActivity<?>, Q extend
|
|||||||
* start A again to ensure it stays on top.
|
* start A again to ensure it stays on top.
|
||||||
*/
|
*/
|
||||||
@CallSuper
|
@CallSuper
|
||||||
protected void onRestartLastAppearedTask() {
|
protected void onRestartPreviouslyAppearedTask() {
|
||||||
// Finish the controller here, since we won't get onTaskAppeared() for a task that already
|
// Finish the controller here, since we won't get onTaskAppeared() for a task that already
|
||||||
// appeared.
|
// appeared.
|
||||||
if (mRecentsAnimationController != null) {
|
if (mRecentsAnimationController != null) {
|
||||||
@@ -205,7 +205,7 @@ public abstract class BaseSwipeUpHandler<T extends StatefulActivity<?>, Q extend
|
|||||||
mRecentsAnimationController = recentsAnimationController;
|
mRecentsAnimationController = recentsAnimationController;
|
||||||
mRecentsAnimationTargets = targets;
|
mRecentsAnimationTargets = targets;
|
||||||
mTransformParams.setTargetSet(mRecentsAnimationTargets);
|
mTransformParams.setTargetSet(mRecentsAnimationTargets);
|
||||||
DeviceProfile dp = InvariantDeviceProfile.INSTANCE.get(mContext).getDeviceProfile(mContext);
|
DeviceProfile dp = mTaskViewSimulator.getOrientationState().getLauncherDeviceProfile();
|
||||||
RemoteAnimationTargetCompat runningTaskTarget = targets.findTask(
|
RemoteAnimationTargetCompat runningTaskTarget = targets.findTask(
|
||||||
mGestureState.getRunningTaskId());
|
mGestureState.getRunningTaskId());
|
||||||
|
|
||||||
@@ -300,8 +300,7 @@ public abstract class BaseSwipeUpHandler<T extends StatefulActivity<?>, Q extend
|
|||||||
if (TestProtocol.sDebugTracing) {
|
if (TestProtocol.sDebugTracing) {
|
||||||
Log.d(TestProtocol.PAUSE_NOT_DETECTED, "BaseSwipeUpHandler.2");
|
Log.d(TestProtocol.PAUSE_NOT_DETECTED, "BaseSwipeUpHandler.2");
|
||||||
}
|
}
|
||||||
initTransitionEndpoints(InvariantDeviceProfile.INSTANCE.get(mContext)
|
initTransitionEndpoints(createdActivity.getDeviceProfile());
|
||||||
.getDeviceProfile(mContext));
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1122,8 +1122,8 @@ public abstract class BaseSwipeUpHandlerV2<T extends StatefulActivity<?>, Q exte
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onRestartLastAppearedTask() {
|
protected void onRestartPreviouslyAppearedTask() {
|
||||||
super.onRestartLastAppearedTask();
|
super.onRestartPreviouslyAppearedTask();
|
||||||
reset();
|
reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -37,7 +37,7 @@ public class QuickstepTestInformationHandler extends TestInformationHandler {
|
|||||||
case TestProtocol.REQUEST_BACKGROUND_TO_OVERVIEW_SWIPE_HEIGHT: {
|
case TestProtocol.REQUEST_BACKGROUND_TO_OVERVIEW_SWIPE_HEIGHT: {
|
||||||
final float swipeHeight =
|
final float swipeHeight =
|
||||||
LayoutUtils.getShelfTrackingDistance(mContext, mDeviceProfile,
|
LayoutUtils.getShelfTrackingDistance(mContext, mDeviceProfile,
|
||||||
PagedOrientationHandler.HOME_ROTATED);
|
PagedOrientationHandler.PORTRAIT);
|
||||||
response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD, (int) swipeHeight);
|
response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD, (int) swipeHeight);
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -139,13 +139,12 @@ public final class RecentsActivity extends StatefulActivity<RecentsState> {
|
|||||||
*/
|
*/
|
||||||
protected DeviceProfile createDeviceProfile() {
|
protected DeviceProfile createDeviceProfile() {
|
||||||
DeviceProfile dp = InvariantDeviceProfile.INSTANCE.get(this).getDeviceProfile(this);
|
DeviceProfile dp = InvariantDeviceProfile.INSTANCE.get(this).getDeviceProfile(this);
|
||||||
DeviceProfile dp1 = InvariantDeviceProfile.INSTANCE.get(this).getDeviceProfile(this);
|
|
||||||
|
|
||||||
// In case we are reusing IDP, create a copy so that we don't conflict with Launcher
|
// In case we are reusing IDP, create a copy so that we don't conflict with Launcher
|
||||||
// activity.
|
// activity.
|
||||||
return (mRecentsRootView != null) && isInMultiWindowMode()
|
return (mRecentsRootView != null) && isInMultiWindowMode()
|
||||||
? dp.getMultiWindowProfile(this, getMultiWindowDisplaySize())
|
? dp.getMultiWindowProfile(this, getMultiWindowDisplaySize())
|
||||||
: dp1.copy(this);
|
: dp.copy(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -83,15 +83,15 @@ public abstract class SwipeUpAnimationLogic {
|
|||||||
mGestureState = gestureState;
|
mGestureState = gestureState;
|
||||||
mTaskViewSimulator = new TaskViewSimulator(context, gestureState.getActivityInterface());
|
mTaskViewSimulator = new TaskViewSimulator(context, gestureState.getActivityInterface());
|
||||||
mTransformParams = transformParams;
|
mTransformParams = transformParams;
|
||||||
|
|
||||||
|
mTaskViewSimulator.setLayoutRotation(
|
||||||
|
mDeviceState.getCurrentActiveRotation(), mDeviceState.getDisplayRotation());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void initTransitionEndpoints(DeviceProfile dp) {
|
protected void initTransitionEndpoints(DeviceProfile dp) {
|
||||||
mDp = dp;
|
mDp = dp;
|
||||||
|
|
||||||
mTaskViewSimulator.setDp(dp);
|
mTaskViewSimulator.setDp(dp);
|
||||||
mTaskViewSimulator.setLayoutRotation(
|
|
||||||
mDeviceState.getCurrentActiveRotation(),
|
|
||||||
mDeviceState.getDisplayRotation());
|
|
||||||
mTransitionDragLength = mGestureState.getActivityInterface().getSwipeUpDestinationAndLength(
|
mTransitionDragLength = mGestureState.getActivityInterface().getSwipeUpDestinationAndLength(
|
||||||
dp, mContext, TEMP_RECT,
|
dp, mContext, TEMP_RECT,
|
||||||
mTaskViewSimulator.getOrientationState().getOrientationHandler());
|
mTaskViewSimulator.getOrientationState().getOrientationHandler());
|
||||||
|
|||||||
@@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
package com.android.quickstep;
|
package com.android.quickstep;
|
||||||
|
|
||||||
|
import static android.view.Surface.ROTATION_0;
|
||||||
|
|
||||||
import static com.android.launcher3.util.MainThreadInitializedObject.forOverride;
|
import static com.android.launcher3.util.MainThreadInitializedObject.forOverride;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
@@ -24,6 +26,7 @@ import android.graphics.Insets;
|
|||||||
import android.graphics.Matrix;
|
import android.graphics.Matrix;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
|
import android.view.View;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import androidx.annotation.RequiresApi;
|
import androidx.annotation.RequiresApi;
|
||||||
@@ -31,9 +34,12 @@ import androidx.annotation.RequiresApi;
|
|||||||
import com.android.launcher3.BaseActivity;
|
import com.android.launcher3.BaseActivity;
|
||||||
import com.android.launcher3.BaseDraggingActivity;
|
import com.android.launcher3.BaseDraggingActivity;
|
||||||
import com.android.launcher3.R;
|
import com.android.launcher3.R;
|
||||||
|
import com.android.launcher3.model.data.ItemInfo;
|
||||||
|
import com.android.launcher3.model.data.WorkspaceItemInfo;
|
||||||
import com.android.launcher3.popup.SystemShortcut;
|
import com.android.launcher3.popup.SystemShortcut;
|
||||||
import com.android.launcher3.util.MainThreadInitializedObject;
|
import com.android.launcher3.util.MainThreadInitializedObject;
|
||||||
import com.android.launcher3.util.ResourceBasedOverride;
|
import com.android.launcher3.util.ResourceBasedOverride;
|
||||||
|
import com.android.quickstep.util.RecentsOrientedState;
|
||||||
import com.android.quickstep.views.OverviewActionsView;
|
import com.android.quickstep.views.OverviewActionsView;
|
||||||
import com.android.quickstep.views.TaskThumbnailView;
|
import com.android.quickstep.views.TaskThumbnailView;
|
||||||
import com.android.quickstep.views.TaskView;
|
import com.android.quickstep.views.TaskView;
|
||||||
@@ -58,6 +64,19 @@ public class TaskOverlayFactory implements ResourceBasedOverride {
|
|||||||
shortcuts.add(shortcut);
|
shortcuts.add(shortcut);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
RecentsOrientedState orientedState = taskView.getRecentsView().getPagedViewOrientedState();
|
||||||
|
boolean canLauncherRotate = orientedState.canLauncherRotate();
|
||||||
|
boolean isInLandscape = orientedState.getTouchRotation() != ROTATION_0;
|
||||||
|
|
||||||
|
// Add overview actions to the menu when in in-place rotate landscape mode.
|
||||||
|
if (!canLauncherRotate && isInLandscape) {
|
||||||
|
for (TaskShortcutFactory actionMenuOption : ACTION_MENU_OPTIONS) {
|
||||||
|
SystemShortcut shortcut = actionMenuOption.getShortcut(activity, taskView);
|
||||||
|
if (shortcut != null) {
|
||||||
|
shortcuts.add(shortcut);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return shortcuts;
|
return shortcuts;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,6 +104,11 @@ public class TaskOverlayFactory implements ResourceBasedOverride {
|
|||||||
TaskShortcutFactory.WELLBEING
|
TaskShortcutFactory.WELLBEING
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private static final TaskShortcutFactory[] ACTION_MENU_OPTIONS = new TaskShortcutFactory[]{
|
||||||
|
TaskShortcutFactory.SCREENSHOT,
|
||||||
|
TaskShortcutFactory.MODAL
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Overlay on each task handling Overview Action Buttons.
|
* Overlay on each task handling Overview Action Buttons.
|
||||||
*/
|
*/
|
||||||
@@ -94,10 +118,14 @@ public class TaskOverlayFactory implements ResourceBasedOverride {
|
|||||||
protected final TaskThumbnailView mThumbnailView;
|
protected final TaskThumbnailView mThumbnailView;
|
||||||
|
|
||||||
private T mActionsView;
|
private T mActionsView;
|
||||||
|
private ImageActionsApi mImageApi;
|
||||||
|
private boolean mIsAllowedByPolicy;
|
||||||
|
|
||||||
protected TaskOverlay(TaskThumbnailView taskThumbnailView) {
|
protected TaskOverlay(TaskThumbnailView taskThumbnailView) {
|
||||||
mApplicationContext = taskThumbnailView.getContext().getApplicationContext();
|
mApplicationContext = taskThumbnailView.getContext().getApplicationContext();
|
||||||
mThumbnailView = taskThumbnailView;
|
mThumbnailView = taskThumbnailView;
|
||||||
|
mImageApi = new ImageActionsApi(
|
||||||
|
mApplicationContext, mThumbnailView::getThumbnail);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected T getActionsView() {
|
protected T getActionsView() {
|
||||||
@@ -112,15 +140,12 @@ public class TaskOverlayFactory implements ResourceBasedOverride {
|
|||||||
* Called when the current task is interactive for the user
|
* Called when the current task is interactive for the user
|
||||||
*/
|
*/
|
||||||
public void initOverlay(Task task, ThumbnailData thumbnail, Matrix matrix) {
|
public void initOverlay(Task task, ThumbnailData thumbnail, Matrix matrix) {
|
||||||
ImageActionsApi imageApi = new ImageActionsApi(
|
|
||||||
mApplicationContext, mThumbnailView::getThumbnail);
|
|
||||||
final boolean isAllowedByPolicy = thumbnail.isRealSnapshot;
|
final boolean isAllowedByPolicy = thumbnail.isRealSnapshot;
|
||||||
|
|
||||||
getActionsView().setCallbacks(new OverlayUICallbacks() {
|
getActionsView().setCallbacks(new OverlayUICallbacks() {
|
||||||
@Override
|
@Override
|
||||||
public void onShare() {
|
public void onShare() {
|
||||||
if (isAllowedByPolicy) {
|
if (isAllowedByPolicy) {
|
||||||
imageApi.startShareActivity();
|
mImageApi.startShareActivity();
|
||||||
} else {
|
} else {
|
||||||
showBlockedByPolicyMessage();
|
showBlockedByPolicyMessage();
|
||||||
}
|
}
|
||||||
@@ -129,16 +154,23 @@ public class TaskOverlayFactory implements ResourceBasedOverride {
|
|||||||
@SuppressLint("NewApi")
|
@SuppressLint("NewApi")
|
||||||
@Override
|
@Override
|
||||||
public void onScreenshot() {
|
public void onScreenshot() {
|
||||||
if (isAllowedByPolicy) {
|
saveScreenshot(task);
|
||||||
imageApi.saveScreenshot(mThumbnailView.getThumbnail(),
|
|
||||||
getTaskSnapshotBounds(), getTaskSnapshotInsets(), task.key);
|
|
||||||
} else {
|
|
||||||
showBlockedByPolicyMessage();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called to save screenshot of the task thumbnail.
|
||||||
|
*/
|
||||||
|
@SuppressLint("NewApi")
|
||||||
|
private void saveScreenshot(Task task) {
|
||||||
|
if (mThumbnailView.isRealSnapshot()) {
|
||||||
|
mImageApi.saveScreenshot(mThumbnailView.getThumbnail(),
|
||||||
|
getTaskSnapshotBounds(), getTaskSnapshotInsets(), task.key);
|
||||||
|
} else {
|
||||||
|
showBlockedByPolicyMessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when the overlay is no longer used.
|
* Called when the overlay is no longer used.
|
||||||
@@ -146,6 +178,26 @@ public class TaskOverlayFactory implements ResourceBasedOverride {
|
|||||||
public void reset() {
|
public void reset() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when the system wants to reset the modal visuals.
|
||||||
|
*/
|
||||||
|
public void resetModalVisuals() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the modal state system shortcut.
|
||||||
|
*/
|
||||||
|
public SystemShortcut getModalStateSystemShortcut(WorkspaceItemInfo itemInfo) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the system shortcut for the screenshot that will be added to the task menu.
|
||||||
|
*/
|
||||||
|
public SystemShortcut getScreenshotShortcut(BaseDraggingActivity activity,
|
||||||
|
ItemInfo iteminfo) {
|
||||||
|
return new ScreenshotSystemShortcut(activity, iteminfo);
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* Gets the task snapshot as it is displayed on the screen.
|
* Gets the task snapshot as it is displayed on the screen.
|
||||||
*
|
*
|
||||||
@@ -175,6 +227,22 @@ public class TaskOverlayFactory implements ResourceBasedOverride {
|
|||||||
R.string.blocked_by_policy,
|
R.string.blocked_by_policy,
|
||||||
Toast.LENGTH_LONG).show();
|
Toast.LENGTH_LONG).show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class ScreenshotSystemShortcut extends SystemShortcut {
|
||||||
|
|
||||||
|
private final BaseDraggingActivity mActivity;
|
||||||
|
|
||||||
|
ScreenshotSystemShortcut(BaseDraggingActivity activity, ItemInfo itemInfo) {
|
||||||
|
super(R.drawable.ic_screenshot, R.string.action_screenshot, activity, itemInfo);
|
||||||
|
mActivity = activity;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClick(View view) {
|
||||||
|
saveScreenshot(mThumbnailView.getTaskView().getTask());
|
||||||
|
dismissTaskMenuView(mActivity);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -18,29 +18,26 @@ package com.android.quickstep;
|
|||||||
|
|
||||||
import static android.view.Display.DEFAULT_DISPLAY;
|
import static android.view.Display.DEFAULT_DISPLAY;
|
||||||
|
|
||||||
|
import static com.android.launcher3.config.FeatureFlags.ENABLE_OVERVIEW_ACTIONS;
|
||||||
|
import static com.android.launcher3.config.FeatureFlags.ENABLE_OVERVIEW_SELECTIONS;
|
||||||
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SYSTEM_SHORTCUT_FREE_FORM_TAP;
|
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SYSTEM_SHORTCUT_FREE_FORM_TAP;
|
||||||
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SYSTEM_SHORTCUT_SPLIT_SCREEN_TAP;
|
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SYSTEM_SHORTCUT_SPLIT_SCREEN_TAP;
|
||||||
import static com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch.TAP;
|
import static com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch.TAP;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.ActivityOptions;
|
import android.app.ActivityOptions;
|
||||||
import android.content.ComponentName;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
import android.os.UserHandle;
|
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
import com.android.launcher3.BaseDraggingActivity;
|
import com.android.launcher3.BaseDraggingActivity;
|
||||||
import com.android.launcher3.DeviceProfile;
|
import com.android.launcher3.DeviceProfile;
|
||||||
import com.android.launcher3.R;
|
import com.android.launcher3.R;
|
||||||
import com.android.launcher3.logger.LauncherAtom;
|
|
||||||
import com.android.launcher3.logging.StatsLogManager.LauncherEvent;
|
import com.android.launcher3.logging.StatsLogManager.LauncherEvent;
|
||||||
import com.android.launcher3.model.WellbeingModel;
|
import com.android.launcher3.model.WellbeingModel;
|
||||||
import com.android.launcher3.model.data.WorkspaceItemInfo;
|
|
||||||
import com.android.launcher3.popup.SystemShortcut;
|
import com.android.launcher3.popup.SystemShortcut;
|
||||||
import com.android.launcher3.popup.SystemShortcut.AppInfo;
|
import com.android.launcher3.popup.SystemShortcut.AppInfo;
|
||||||
import com.android.launcher3.userevent.nano.LauncherLogProto;
|
import com.android.launcher3.userevent.nano.LauncherLogProto;
|
||||||
@@ -69,28 +66,7 @@ public interface TaskShortcutFactory {
|
|||||||
|
|
||||||
SystemShortcut getShortcut(BaseDraggingActivity activity, TaskView view);
|
SystemShortcut getShortcut(BaseDraggingActivity activity, TaskView view);
|
||||||
|
|
||||||
static WorkspaceItemInfo dummyInfo(TaskView view) {
|
TaskShortcutFactory APP_INFO = (activity, view) -> new AppInfo(activity, view.getItemInfo());
|
||||||
Task task = view.getTask();
|
|
||||||
|
|
||||||
WorkspaceItemInfo dummyInfo = new WorkspaceItemInfo(){
|
|
||||||
/**
|
|
||||||
* Helps to log events as {@link LauncherAtom.Task}
|
|
||||||
* instead of {@link LauncherAtom.ItemInfo}.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public LauncherAtom.ItemInfo buildProto() {
|
|
||||||
return view.buildProto();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
dummyInfo.intent = new Intent();
|
|
||||||
ComponentName component = task.getTopComponent();
|
|
||||||
dummyInfo.getIntent().setComponent(component);
|
|
||||||
dummyInfo.user = UserHandle.of(task.key.userId);
|
|
||||||
dummyInfo.title = TaskUtils.getTitle(view.getContext(), task);
|
|
||||||
return dummyInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
TaskShortcutFactory APP_INFO = (activity, view) -> new AppInfo(activity, dummyInfo(view));
|
|
||||||
|
|
||||||
abstract class MultiWindowFactory implements TaskShortcutFactory {
|
abstract class MultiWindowFactory implements TaskShortcutFactory {
|
||||||
|
|
||||||
@@ -134,7 +110,7 @@ public interface TaskShortcutFactory {
|
|||||||
|
|
||||||
public MultiWindowSystemShortcut(int iconRes, int textRes, BaseDraggingActivity activity,
|
public MultiWindowSystemShortcut(int iconRes, int textRes, BaseDraggingActivity activity,
|
||||||
TaskView taskView, MultiWindowFactory factory, LauncherEvent launcherEvent) {
|
TaskView taskView, MultiWindowFactory factory, LauncherEvent launcherEvent) {
|
||||||
super(iconRes, textRes, activity, dummyInfo(taskView));
|
super(iconRes, textRes, activity, taskView.getItemInfo());
|
||||||
mLauncherEvent = launcherEvent;
|
mLauncherEvent = launcherEvent;
|
||||||
mHandler = new Handler(Looper.getMainLooper());
|
mHandler = new Handler(Looper.getMainLooper());
|
||||||
mTaskView = taskView;
|
mTaskView = taskView;
|
||||||
@@ -220,7 +196,7 @@ public interface TaskShortcutFactory {
|
|||||||
WindowManagerWrapper.getInstance().overridePendingAppTransitionMultiThumbFuture(
|
WindowManagerWrapper.getInstance().overridePendingAppTransitionMultiThumbFuture(
|
||||||
future, animStartedListener, mHandler, true /* scaleUp */,
|
future, animStartedListener, mHandler, true /* scaleUp */,
|
||||||
taskKey.displayId);
|
taskKey.displayId);
|
||||||
mTarget.getStatsLogManager().log(mLauncherEvent, mTaskView.buildProto());
|
mTarget.getStatsLogManager().log(mLauncherEvent, mTaskView.getItemInfo());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -304,7 +280,7 @@ public interface TaskShortcutFactory {
|
|||||||
private final TaskView mTaskView;
|
private final TaskView mTaskView;
|
||||||
|
|
||||||
public PinSystemShortcut(BaseDraggingActivity target, TaskView tv) {
|
public PinSystemShortcut(BaseDraggingActivity target, TaskView tv) {
|
||||||
super(R.drawable.ic_pin, R.string.recent_task_option_pin, target, dummyInfo(tv));
|
super(R.drawable.ic_pin, R.string.recent_task_option_pin, target, tv.getItemInfo());
|
||||||
mTaskView = tv;
|
mTaskView = tv;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -321,15 +297,30 @@ public interface TaskShortcutFactory {
|
|||||||
mTaskView.launchTask(true, resultCallback, Executors.MAIN_EXECUTOR.getHandler());
|
mTaskView.launchTask(true, resultCallback, Executors.MAIN_EXECUTOR.getHandler());
|
||||||
dismissTaskMenuView(mTarget);
|
dismissTaskMenuView(mTarget);
|
||||||
mTarget.getStatsLogManager().log(LauncherEvent.LAUNCHER_SYSTEM_SHORTCUT_PIN_TAP,
|
mTarget.getStatsLogManager().log(LauncherEvent.LAUNCHER_SYSTEM_SHORTCUT_PIN_TAP,
|
||||||
mTaskView.buildProto());
|
mTaskView.getItemInfo());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TaskShortcutFactory INSTALL = (activity, view) ->
|
TaskShortcutFactory INSTALL = (activity, view) ->
|
||||||
InstantAppResolver.newInstance(activity).isInstantApp(activity,
|
InstantAppResolver.newInstance(activity).isInstantApp(activity,
|
||||||
view.getTask().getTopComponent().getPackageName())
|
view.getTask().getTopComponent().getPackageName())
|
||||||
? new SystemShortcut.Install(activity, dummyInfo(view)) : null;
|
? new SystemShortcut.Install(activity, view.getItemInfo()) : null;
|
||||||
|
|
||||||
TaskShortcutFactory WELLBEING = (activity, view) ->
|
TaskShortcutFactory WELLBEING = (activity, view) ->
|
||||||
WellbeingModel.SHORTCUT_FACTORY.getShortcut(activity, dummyInfo(view));
|
WellbeingModel.SHORTCUT_FACTORY.getShortcut(activity, view.getItemInfo());
|
||||||
|
|
||||||
|
TaskShortcutFactory SCREENSHOT = (activity, tv) -> {
|
||||||
|
if (ENABLE_OVERVIEW_ACTIONS.get()) {
|
||||||
|
return tv.getThumbnail().getTaskOverlay()
|
||||||
|
.getScreenshotShortcut(activity, tv.getItemInfo());
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
TaskShortcutFactory MODAL = (activity, tv) -> {
|
||||||
|
if (ENABLE_OVERVIEW_ACTIONS.get() && ENABLE_OVERVIEW_SELECTIONS.get()) {
|
||||||
|
return tv.getThumbnail().getTaskOverlay().getModalStateSystemShortcut(tv.getItemInfo());
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -539,6 +539,8 @@ public class TouchInteractionService extends Service implements PluginListener<O
|
|||||||
if (mTaskAnimationManager.isRecentsAnimationRunning()) {
|
if (mTaskAnimationManager.isRecentsAnimationRunning()) {
|
||||||
gestureState.updateRunningTask(mGestureState.getRunningTask());
|
gestureState.updateRunningTask(mGestureState.getRunningTask());
|
||||||
gestureState.updateLastStartedTaskId(mGestureState.getLastStartedTaskId());
|
gestureState.updateLastStartedTaskId(mGestureState.getLastStartedTaskId());
|
||||||
|
gestureState.updatePreviouslyAppearedTaskIds(
|
||||||
|
mGestureState.getPreviouslyAppearedTaskIds());
|
||||||
} else {
|
} else {
|
||||||
gestureState.updateRunningTask(TraceHelper.whitelistIpcs("getRunningTask.0",
|
gestureState.updateRunningTask(TraceHelper.whitelistIpcs("getRunningTask.0",
|
||||||
() -> mAM.getRunningTask(false /* filterOnlyVisibleRecents */)));
|
() -> mAM.getRunningTask(false /* filterOnlyVisibleRecents */)));
|
||||||
|
|||||||
+7
-4
@@ -267,10 +267,6 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC
|
|||||||
if (!mPassedSlopOnThisGesture && passedSlop) {
|
if (!mPassedSlopOnThisGesture && passedSlop) {
|
||||||
mPassedSlopOnThisGesture = true;
|
mPassedSlopOnThisGesture = true;
|
||||||
}
|
}
|
||||||
// Until passing slop, we don't know what direction we're going, so assume we might
|
|
||||||
// be quick switching to avoid translating recents away when continuing the gesture.
|
|
||||||
boolean isLikelyToStartNewTask = !mPassedSlopOnThisGesture
|
|
||||||
|| horizontalDist > upDist;
|
|
||||||
|
|
||||||
if (!mPassedPilferInputSlop) {
|
if (!mPassedPilferInputSlop) {
|
||||||
if (passedSlop) {
|
if (passedSlop) {
|
||||||
@@ -304,6 +300,13 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (mDeviceState.isFullyGesturalNavMode()) {
|
if (mDeviceState.isFullyGesturalNavMode()) {
|
||||||
|
// Until passing slop, we don't know what direction we're going, so assume
|
||||||
|
// we're quick switching to avoid translating recents away when continuing
|
||||||
|
// the gesture.
|
||||||
|
boolean haveNotPassedSlopOnContinuedGesture =
|
||||||
|
!mPassedSlopOnThisGesture && mPassedPilferInputSlop;
|
||||||
|
boolean isLikelyToStartNewTask = haveNotPassedSlopOnContinuedGesture
|
||||||
|
|| horizontalDist > upDist;
|
||||||
mMotionPauseDetector.setDisallowPause(upDist < mMotionPauseMinDisplacement
|
mMotionPauseDetector.setDisallowPause(upDist < mMotionPauseMinDisplacement
|
||||||
|| isLikelyToStartNewTask);
|
|| isLikelyToStartNewTask);
|
||||||
mMotionPauseDetector.addPosition(ev);
|
mMotionPauseDetector.addPosition(ev);
|
||||||
|
|||||||
+2
-18
@@ -36,8 +36,6 @@ import com.android.quickstep.util.ActiveGestureLog;
|
|||||||
import com.android.systemui.shared.system.ActivityManagerWrapper;
|
import com.android.systemui.shared.system.ActivityManagerWrapper;
|
||||||
import com.android.systemui.shared.system.InputMonitorCompat;
|
import com.android.systemui.shared.system.InputMonitorCompat;
|
||||||
|
|
||||||
import java.util.function.Predicate;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Input consumer for handling touch on the recents/Launcher activity.
|
* Input consumer for handling touch on the recents/Launcher activity.
|
||||||
*/
|
*/
|
||||||
@@ -50,8 +48,6 @@ public class OverviewInputConsumer<T extends StatefulActivity<?>>
|
|||||||
private final InputMonitorCompat mInputMonitor;
|
private final InputMonitorCompat mInputMonitor;
|
||||||
|
|
||||||
private final int[] mLocationOnScreen = new int[2];
|
private final int[] mLocationOnScreen = new int[2];
|
||||||
private final boolean mProxyTouch;
|
|
||||||
private final Predicate<MotionEvent> mEventReceiver;
|
|
||||||
|
|
||||||
private final boolean mStartingInActivityBounds;
|
private final boolean mStartingInActivityBounds;
|
||||||
private boolean mTargetHandledTouch;
|
private boolean mTargetHandledTouch;
|
||||||
@@ -64,15 +60,7 @@ public class OverviewInputConsumer<T extends StatefulActivity<?>>
|
|||||||
mActivityInterface = gestureState.getActivityInterface();
|
mActivityInterface = gestureState.getActivityInterface();
|
||||||
|
|
||||||
mTarget = activity.getDragLayer();
|
mTarget = activity.getDragLayer();
|
||||||
if (startingInActivityBounds) {
|
mTarget.getLocationOnScreen(mLocationOnScreen);
|
||||||
mEventReceiver = mTarget::dispatchTouchEvent;
|
|
||||||
mProxyTouch = true;
|
|
||||||
} else {
|
|
||||||
// Only proxy touches to controllers if we are starting touch from nav bar.
|
|
||||||
mEventReceiver = mTarget::proxyTouchEvent;
|
|
||||||
mTarget.getLocationOnScreen(mLocationOnScreen);
|
|
||||||
mProxyTouch = mTarget.prepareProxyEventStarting();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -87,10 +75,6 @@ public class OverviewInputConsumer<T extends StatefulActivity<?>>
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onMotionEvent(MotionEvent ev) {
|
public void onMotionEvent(MotionEvent ev) {
|
||||||
if (!mProxyTouch) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int flags = ev.getEdgeFlags();
|
int flags = ev.getEdgeFlags();
|
||||||
if (!mStartingInActivityBounds) {
|
if (!mStartingInActivityBounds) {
|
||||||
ev.setEdgeFlags(flags | Utilities.EDGE_NAV_BAR);
|
ev.setEdgeFlags(flags | Utilities.EDGE_NAV_BAR);
|
||||||
@@ -99,7 +83,7 @@ public class OverviewInputConsumer<T extends StatefulActivity<?>>
|
|||||||
if (TestProtocol.sDebugTracing) {
|
if (TestProtocol.sDebugTracing) {
|
||||||
Log.d(TestProtocol.PAUSE_NOT_DETECTED, "OverviewInputConsumer");
|
Log.d(TestProtocol.PAUSE_NOT_DETECTED, "OverviewInputConsumer");
|
||||||
}
|
}
|
||||||
boolean handled = mEventReceiver.test(ev);
|
boolean handled = mTarget.proxyTouchEvent(ev, mStartingInActivityBounds);
|
||||||
ev.offsetLocation(mLocationOnScreen[0], mLocationOnScreen[1]);
|
ev.offsetLocation(mLocationOnScreen[0], mLocationOnScreen[1]);
|
||||||
ev.setEdgeFlags(flags);
|
ev.setEdgeFlags(flags);
|
||||||
|
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ import static com.android.launcher3.Utilities.mapToRange;
|
|||||||
import static com.android.launcher3.Utilities.squaredHypot;
|
import static com.android.launcher3.Utilities.squaredHypot;
|
||||||
import static com.android.launcher3.Utilities.squaredTouchSlop;
|
import static com.android.launcher3.Utilities.squaredTouchSlop;
|
||||||
import static com.android.launcher3.anim.Interpolators.ACCEL;
|
import static com.android.launcher3.anim.Interpolators.ACCEL;
|
||||||
|
import static com.android.launcher3.anim.Interpolators.ACCEL_0_75;
|
||||||
import static com.android.launcher3.anim.Interpolators.ACCEL_2;
|
import static com.android.launcher3.anim.Interpolators.ACCEL_2;
|
||||||
import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
|
import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
|
||||||
import static com.android.launcher3.anim.Interpolators.LINEAR;
|
import static com.android.launcher3.anim.Interpolators.LINEAR;
|
||||||
@@ -607,6 +608,17 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the Clear All button is hidden or fully visible. Used to determine if center
|
||||||
|
* displayed page is a task or the Clear All button.
|
||||||
|
*
|
||||||
|
* @return True = Clear All button not fully visible, center page is a task. False = Clear All
|
||||||
|
* button fully visible, center page is Clear All button.
|
||||||
|
*/
|
||||||
|
public boolean isClearAllHidden() {
|
||||||
|
return mClearAllButton.getAlpha() != 1f;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onPageBeginTransition() {
|
protected void onPageBeginTransition() {
|
||||||
super.onPageBeginTransition();
|
super.onPageBeginTransition();
|
||||||
@@ -616,7 +628,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
|||||||
@Override
|
@Override
|
||||||
protected void onPageEndTransition() {
|
protected void onPageEndTransition() {
|
||||||
super.onPageEndTransition();
|
super.onPageEndTransition();
|
||||||
if (getScrollX() == getScrollForPage(getPageNearestToCenterOfScreen())) {
|
if (isClearAllHidden()) {
|
||||||
LayoutUtils.setViewEnabled(mActionsView, true);
|
LayoutUtils.setViewEnabled(mActionsView, true);
|
||||||
}
|
}
|
||||||
if (getNextPage() > 0) {
|
if (getNextPage() > 0) {
|
||||||
@@ -1336,7 +1348,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
|||||||
mActivity.getUserEventDispatcher().logTaskLaunchOrDismiss(
|
mActivity.getUserEventDispatcher().logTaskLaunchOrDismiss(
|
||||||
endState.logAction, Direction.UP, index, compKey);
|
endState.logAction, Direction.UP, index, compKey);
|
||||||
mActivity.getStatsLogManager().log(
|
mActivity.getStatsLogManager().log(
|
||||||
LAUNCHER_TASK_DISMISS_SWIPE_UP, taskView.buildProto());
|
LAUNCHER_TASK_DISMISS_SWIPE_UP, taskView.getItemInfo());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1720,7 +1732,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
|||||||
|
|
||||||
private void updatePageOffsets() {
|
private void updatePageOffsets() {
|
||||||
float offset = mAdjacentPageOffset * getWidth();
|
float offset = mAdjacentPageOffset * getWidth();
|
||||||
float modalOffset = mTaskModalness * getWidth();
|
float modalOffset = ACCEL_0_75.getInterpolation(mTaskModalness) * getWidth();
|
||||||
if (mIsRtl) {
|
if (mIsRtl) {
|
||||||
offset = -offset;
|
offset = -offset;
|
||||||
modalOffset = -modalOffset;
|
modalOffset = -modalOffset;
|
||||||
@@ -1748,6 +1760,16 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
|||||||
return Math.max(getWidth(), 1);
|
return Math.max(getWidth(), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resets the visuals when exit modal state.
|
||||||
|
*/
|
||||||
|
public void resetModalVisuals() {
|
||||||
|
TaskView taskView = getCurrentPageTaskView();
|
||||||
|
if (taskView != null) {
|
||||||
|
taskView.getThumbnail().getTaskOverlay().resetModalVisuals();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void updateDeadZoneRects() {
|
private void updateDeadZoneRects() {
|
||||||
// Get the deadzone rect surrounding the clear all button to not dismiss overview to home
|
// Get the deadzone rect surrounding the clear all button to not dismiss overview to home
|
||||||
mClearAllButtonDeadZoneRect.setEmpty();
|
mClearAllButtonDeadZoneRect.setEmpty();
|
||||||
@@ -1919,7 +1941,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
|||||||
endState.logAction, Direction.DOWN, indexOfChild(tv),
|
endState.logAction, Direction.DOWN, indexOfChild(tv),
|
||||||
TaskUtils.getLaunchComponentKeyForTask(task.key));
|
TaskUtils.getLaunchComponentKeyForTask(task.key));
|
||||||
mActivity.getStatsLogManager().log(
|
mActivity.getStatsLogManager().log(
|
||||||
LAUNCHER_TASK_LAUNCH_SWIPE_DOWN, tv.buildProto());
|
LAUNCHER_TASK_LAUNCH_SWIPE_DOWN, tv.getItemInfo());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
onTaskLaunched(false);
|
onTaskLaunched(false);
|
||||||
@@ -2089,6 +2111,12 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
|||||||
return mClearAllButton;
|
return mClearAllButton;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean onOverscroll(int amount) {
|
||||||
|
// overscroll should only be accepted on -1 direction (for clear all button)
|
||||||
|
if ((amount > 0 && !mIsRtl) || (amount < 0 && mIsRtl)) return false;
|
||||||
|
return super.onOverscroll(amount);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return How many pixels the running task is offset on the currently laid out dominant axis.
|
* @return How many pixels the running task is offset on the currently laid out dominant axis.
|
||||||
@@ -2182,6 +2210,11 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
|||||||
if (getCurrentPageTaskView() != null) {
|
if (getCurrentPageTaskView() != null) {
|
||||||
getCurrentPageTaskView().setModalness(modalness);
|
getCurrentPageTaskView().setModalness(modalness);
|
||||||
}
|
}
|
||||||
|
// Only show actions view when it's modal for in-place landscape mode.
|
||||||
|
boolean inPlaceLandscape = !mOrientationState.canLauncherRotate()
|
||||||
|
&& mOrientationState.getTouchRotation() != ROTATION_0;
|
||||||
|
mActionsView.updateHiddenFlags(HIDDEN_NON_ZERO_ROTATION, modalness < 1 && inPlaceLandscape);
|
||||||
|
LayoutUtils.setViewEnabled(mActionsView, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
|
|||||||
@@ -447,6 +447,16 @@ public class TaskThumbnailView extends View implements PluginListener<OverviewSc
|
|||||||
return mThumbnailData.thumbnail;
|
return mThumbnailData.thumbnail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the snapshot is real.
|
||||||
|
*/
|
||||||
|
public boolean isRealSnapshot() {
|
||||||
|
if (mThumbnailData == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return mThumbnailData.isRealSnapshot;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utility class to position the thumbnail in the TaskView
|
* Utility class to position the thumbnail in the TaskView
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ import android.animation.TimeInterpolator;
|
|||||||
import android.animation.ValueAnimator;
|
import android.animation.ValueAnimator;
|
||||||
import android.app.ActivityOptions;
|
import android.app.ActivityOptions;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
import android.graphics.Outline;
|
import android.graphics.Outline;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.graphics.RectF;
|
import android.graphics.RectF;
|
||||||
@@ -48,7 +49,6 @@ import android.graphics.drawable.GradientDrawable;
|
|||||||
import android.graphics.drawable.InsetDrawable;
|
import android.graphics.drawable.InsetDrawable;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.Process;
|
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.util.FloatProperty;
|
import android.util.FloatProperty;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
@@ -61,13 +61,14 @@ import android.widget.Toast;
|
|||||||
|
|
||||||
import com.android.launcher3.BaseDraggingActivity;
|
import com.android.launcher3.BaseDraggingActivity;
|
||||||
import com.android.launcher3.DeviceProfile;
|
import com.android.launcher3.DeviceProfile;
|
||||||
|
import com.android.launcher3.LauncherSettings;
|
||||||
import com.android.launcher3.R;
|
import com.android.launcher3.R;
|
||||||
import com.android.launcher3.Utilities;
|
import com.android.launcher3.Utilities;
|
||||||
import com.android.launcher3.anim.AnimatorPlaybackController;
|
import com.android.launcher3.anim.AnimatorPlaybackController;
|
||||||
import com.android.launcher3.anim.Interpolators;
|
import com.android.launcher3.anim.Interpolators;
|
||||||
import com.android.launcher3.anim.PendingAnimation;
|
import com.android.launcher3.anim.PendingAnimation;
|
||||||
import com.android.launcher3.logger.LauncherAtom;
|
|
||||||
import com.android.launcher3.logging.UserEventDispatcher;
|
import com.android.launcher3.logging.UserEventDispatcher;
|
||||||
|
import com.android.launcher3.model.data.WorkspaceItemInfo;
|
||||||
import com.android.launcher3.popup.SystemShortcut;
|
import com.android.launcher3.popup.SystemShortcut;
|
||||||
import com.android.launcher3.testing.TestLogging;
|
import com.android.launcher3.testing.TestLogging;
|
||||||
import com.android.launcher3.testing.TestProtocol;
|
import com.android.launcher3.testing.TestProtocol;
|
||||||
@@ -213,7 +214,7 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
|
|||||||
mActivity.getUserEventDispatcher().logTaskLaunchOrDismiss(
|
mActivity.getUserEventDispatcher().logTaskLaunchOrDismiss(
|
||||||
Touch.TAP, Direction.NONE, getRecentsView().indexOfChild(this),
|
Touch.TAP, Direction.NONE, getRecentsView().indexOfChild(this),
|
||||||
TaskUtils.getLaunchComponentKeyForTask(getTask().key));
|
TaskUtils.getLaunchComponentKeyForTask(getTask().key));
|
||||||
mActivity.getStatsLogManager().log(LAUNCHER_TASK_LAUNCH_TAP, buildProto());
|
mActivity.getStatsLogManager().log(LAUNCHER_TASK_LAUNCH_TAP, getItemInfo());
|
||||||
});
|
});
|
||||||
|
|
||||||
mCurrentFullscreenParams = new FullscreenDrawParams(context);
|
mCurrentFullscreenParams = new FullscreenDrawParams(context);
|
||||||
@@ -226,14 +227,16 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
|
|||||||
/**
|
/**
|
||||||
* Builds proto for logging
|
* Builds proto for logging
|
||||||
*/
|
*/
|
||||||
public LauncherAtom.ItemInfo buildProto() {
|
public WorkspaceItemInfo getItemInfo() {
|
||||||
ComponentKey componentKey = TaskUtils.getLaunchComponentKeyForTask(getTask().key);
|
ComponentKey componentKey = TaskUtils.getLaunchComponentKeyForTask(getTask().key);
|
||||||
LauncherAtom.ItemInfo.Builder itemBuilder = LauncherAtom.ItemInfo.newBuilder();
|
WorkspaceItemInfo dummyInfo = new WorkspaceItemInfo();
|
||||||
itemBuilder.setIsWork(componentKey.user != Process.myUserHandle());
|
dummyInfo.itemType = LauncherSettings.Favorites.ITEM_TYPE_TASK;
|
||||||
itemBuilder.setTask(LauncherAtom.Task.newBuilder()
|
dummyInfo.container = LauncherSettings.Favorites.CONTAINER_TASKSWITCHER;
|
||||||
.setComponentName(componentKey.componentName.flattenToShortString())
|
dummyInfo.user = componentKey.user;
|
||||||
.setIndex(getRecentsView().indexOfChild(this)));
|
dummyInfo.intent = new Intent().setComponent(componentKey.componentName);
|
||||||
return itemBuilder.build();
|
dummyInfo.title = TaskUtils.getTitle(getContext(), getTask());
|
||||||
|
dummyInfo.screenId = getRecentsView().indexOfChild(this);
|
||||||
|
return dummyInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -425,13 +428,16 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean showTaskMenu(int action) {
|
private boolean showTaskMenu(int action) {
|
||||||
getRecentsView().snapToPage(getRecentsView().indexOfChild(this));
|
if (!getRecentsView().isClearAllHidden()) {
|
||||||
mMenuView = TaskMenuView.showForTask(this);
|
getRecentsView().snapToPage(getRecentsView().indexOfChild(this));
|
||||||
mActivity.getStatsLogManager().log(LAUNCHER_TASK_ICON_TAP_OR_LONGPRESS, buildProto());
|
} else {
|
||||||
UserEventDispatcher.newInstance(getContext()).logActionOnItem(action, Direction.NONE,
|
mMenuView = TaskMenuView.showForTask(this);
|
||||||
LauncherLogProto.ItemType.TASK_ICON);
|
mActivity.getStatsLogManager().log(LAUNCHER_TASK_ICON_TAP_OR_LONGPRESS, getItemInfo());
|
||||||
if (mMenuView != null) {
|
UserEventDispatcher.newInstance(getContext()).logActionOnItem(action, Direction.NONE,
|
||||||
mMenuView.addOnAttachStateChangeListener(mTaskMenuStateListener);
|
LauncherLogProto.ItemType.TASK_ICON);
|
||||||
|
if (mMenuView != null) {
|
||||||
|
mMenuView.addOnAttachStateChangeListener(mTaskMenuStateListener);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return mMenuView != null;
|
return mMenuView != null;
|
||||||
}
|
}
|
||||||
@@ -969,6 +975,9 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void updateCurrentFullscreenParams(PreviewPositionHelper previewPositionHelper) {
|
void updateCurrentFullscreenParams(PreviewPositionHelper previewPositionHelper) {
|
||||||
|
if (getRecentsView() == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
mCurrentFullscreenParams.setProgress(
|
mCurrentFullscreenParams.setProgress(
|
||||||
mFullscreenProgress,
|
mFullscreenProgress,
|
||||||
getRecentsView().getScaleX(),
|
getRecentsView().getScaleX(),
|
||||||
|
|||||||
@@ -76,8 +76,8 @@
|
|||||||
<!-- Button text to dismiss opt in for fully predicted hotseat -->
|
<!-- Button text to dismiss opt in for fully predicted hotseat -->
|
||||||
<string name="hotseat_edu_dismiss">No thanks</string>
|
<string name="hotseat_edu_dismiss">No thanks</string>
|
||||||
|
|
||||||
<!-- action shown to turn off predictions after onboarding -->
|
<!-- action shown to toggle predictions after onboarding -->
|
||||||
<string name="hotseat_turn_off">Settings</string>
|
<string name="hotseat_prediction_settings">Settings</string>
|
||||||
|
|
||||||
<!-- tip shown if user has no items in hotseat to migrate -->
|
<!-- tip shown if user has no items in hotseat to migrate -->
|
||||||
<string name="hotseat_auto_enrolled">Most-used apps appear here, and change based on routines</string>
|
<string name="hotseat_auto_enrolled">Most-used apps appear here, and change based on routines</string>
|
||||||
@@ -86,7 +86,9 @@
|
|||||||
<!-- tip shown if user declines migration and has some open spots for prediction -->
|
<!-- tip shown if user declines migration and has some open spots for prediction -->
|
||||||
<string name="hotseat_tip_gaps_filled">App suggestions added to empty space</string>
|
<string name="hotseat_tip_gaps_filled">App suggestions added to empty space</string>
|
||||||
<!-- tip shown when user migrates and predictions are enabled in hotseat -->
|
<!-- tip shown when user migrates and predictions are enabled in hotseat -->
|
||||||
<string name="hotsaet_tip_prediction_enabled">App suggestions Enabled</string>
|
<string name="hotsaet_tip_prediction_enabled">App suggestions enabled</string>
|
||||||
|
<!-- tip shown when hotseat edu is requested while predicions are disabled -->
|
||||||
|
<string name="hotsaet_tip_prediction_disabled">App suggestions are disabled</string>
|
||||||
|
|
||||||
<!-- content description for hotseat items -->
|
<!-- content description for hotseat items -->
|
||||||
<string name="hotseat_prediction_content_description">Predicted app: <xliff:g id="title" example="Chrome">%1$s</xliff:g></string>
|
<string name="hotseat_prediction_content_description">Predicted app: <xliff:g id="title" example="Chrome">%1$s</xliff:g></string>
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ import android.os.Bundle;
|
|||||||
import android.os.CancellationSignal;
|
import android.os.CancellationSignal;
|
||||||
|
|
||||||
import com.android.launcher3.config.FeatureFlags;
|
import com.android.launcher3.config.FeatureFlags;
|
||||||
|
import com.android.launcher3.hybridhotseat.HotseatPredictionController;
|
||||||
import com.android.launcher3.model.WellbeingModel;
|
import com.android.launcher3.model.WellbeingModel;
|
||||||
import com.android.launcher3.popup.SystemShortcut;
|
import com.android.launcher3.popup.SystemShortcut;
|
||||||
import com.android.launcher3.proxy.ProxyActivityStarter;
|
import com.android.launcher3.proxy.ProxyActivityStarter;
|
||||||
@@ -75,6 +76,7 @@ public abstract class BaseQuickstepLauncher extends Launcher
|
|||||||
private final ShelfPeekAnim mShelfPeekAnim = new ShelfPeekAnim(this);
|
private final ShelfPeekAnim mShelfPeekAnim = new ShelfPeekAnim(this);
|
||||||
|
|
||||||
private OverviewActionsView mActionsView;
|
private OverviewActionsView mActionsView;
|
||||||
|
protected HotseatPredictionController mHotseatPredictionController;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
@@ -305,6 +307,13 @@ public abstract class BaseQuickstepLauncher extends Launcher
|
|||||||
return mShelfPeekAnim;
|
return mShelfPeekAnim;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns Prediction controller for hybrid hotseat
|
||||||
|
*/
|
||||||
|
public HotseatPredictionController getHotseatPredictionController() {
|
||||||
|
return mHotseatPredictionController;
|
||||||
|
}
|
||||||
|
|
||||||
public void setHintUserWillBeActive() {
|
public void setHintUserWillBeActive() {
|
||||||
addActivityFlags(ACTIVITY_STATE_USER_WILL_BE_ACTIVE);
|
addActivityFlags(ACTIVITY_STATE_USER_WILL_BE_ACTIVE);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ import com.android.launcher3.Utilities;
|
|||||||
import com.android.launcher3.anim.PendingAnimation;
|
import com.android.launcher3.anim.PendingAnimation;
|
||||||
import com.android.launcher3.statemanager.StateManager.StateHandler;
|
import com.android.launcher3.statemanager.StateManager.StateHandler;
|
||||||
import com.android.launcher3.states.StateAnimationConfig;
|
import com.android.launcher3.states.StateAnimationConfig;
|
||||||
|
import com.android.systemui.shared.system.BlurUtils;
|
||||||
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
|
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
|
||||||
import com.android.systemui.shared.system.SurfaceControlCompat;
|
import com.android.systemui.shared.system.SurfaceControlCompat;
|
||||||
import com.android.systemui.shared.system.TransactionCompat;
|
import com.android.systemui.shared.system.TransactionCompat;
|
||||||
@@ -110,6 +111,10 @@ public class DepthController implements StateHandler<LauncherState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void ensureDependencies() {
|
private void ensureDependencies() {
|
||||||
|
if (mWallpaperManager == null) {
|
||||||
|
mMaxBlurRadius = mLauncher.getResources().getInteger(R.integer.max_depth_blur_radius);
|
||||||
|
mWallpaperManager = new WallpaperManagerCompat(mLauncher);
|
||||||
|
}
|
||||||
if (mLauncher.getRootView() != null && mOnAttachListener == null) {
|
if (mLauncher.getRootView() != null && mOnAttachListener == null) {
|
||||||
mOnAttachListener = new View.OnAttachStateChangeListener() {
|
mOnAttachListener = new View.OnAttachStateChangeListener() {
|
||||||
@Override
|
@Override
|
||||||
@@ -127,11 +132,6 @@ public class DepthController implements StateHandler<LauncherState> {
|
|||||||
};
|
};
|
||||||
mLauncher.getRootView().addOnAttachStateChangeListener(mOnAttachListener);
|
mLauncher.getRootView().addOnAttachStateChangeListener(mOnAttachListener);
|
||||||
}
|
}
|
||||||
if (mWallpaperManager != null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
mMaxBlurRadius = mLauncher.getResources().getInteger(R.integer.max_depth_blur_radius);
|
|
||||||
mWallpaperManager = new WallpaperManagerCompat(mLauncher);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -205,7 +205,8 @@ public class DepthController implements StateHandler<LauncherState> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mSurface == null || !mSurface.isValid()) {
|
boolean supportsBlur = BlurUtils.supportsBlursOnWindows();
|
||||||
|
if (supportsBlur && (mSurface == null || !mSurface.isValid())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mDepth = depthF;
|
mDepth = depthF;
|
||||||
@@ -214,17 +215,20 @@ public class DepthController implements StateHandler<LauncherState> {
|
|||||||
if (windowToken != null) {
|
if (windowToken != null) {
|
||||||
mWallpaperManager.setWallpaperZoomOut(windowToken, mDepth);
|
mWallpaperManager.setWallpaperZoomOut(windowToken, mDepth);
|
||||||
}
|
}
|
||||||
final int blur;
|
|
||||||
if (mLauncher.isInState(LauncherState.ALL_APPS) && mDepth == 1) {
|
if (supportsBlur) {
|
||||||
// All apps has a solid background. We don't need to draw blurs after it's fully
|
final int blur;
|
||||||
// visible. This will take us out of GPU composition, saving battery and increasing
|
if (mLauncher.isInState(LauncherState.ALL_APPS) && mDepth == 1) {
|
||||||
// performance.
|
// All apps has a solid background. We don't need to draw blurs after it's fully
|
||||||
blur = 0;
|
// visible. This will take us out of GPU composition, saving battery and increasing
|
||||||
} else {
|
// performance.
|
||||||
blur = (int) (mDepth * mMaxBlurRadius);
|
blur = 0;
|
||||||
|
} else {
|
||||||
|
blur = (int) (mDepth * mMaxBlurRadius);
|
||||||
|
}
|
||||||
|
new TransactionCompat()
|
||||||
|
.setBackgroundBlurRadius(mSurface, blur)
|
||||||
|
.apply();
|
||||||
}
|
}
|
||||||
new TransactionCompat()
|
|
||||||
.setBackgroundBlurRadius(mSurface, blur)
|
|
||||||
.apply();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,8 @@ import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
|
|||||||
|
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manages the state for an active system gesture, listens for events from the system and Launcher,
|
* Manages the state for an active system gesture, listens for events from the system and Launcher,
|
||||||
@@ -128,6 +130,7 @@ public class GestureState implements RecentsAnimationCallbacks.RecentsAnimationL
|
|||||||
private ActivityManager.RunningTaskInfo mRunningTask;
|
private ActivityManager.RunningTaskInfo mRunningTask;
|
||||||
private GestureEndTarget mEndTarget;
|
private GestureEndTarget mEndTarget;
|
||||||
private RemoteAnimationTargetCompat mLastAppearedTaskTarget;
|
private RemoteAnimationTargetCompat mLastAppearedTaskTarget;
|
||||||
|
private Set<Integer> mPreviouslyAppearedTaskIds = new HashSet<>();
|
||||||
private int mLastStartedTaskId = -1;
|
private int mLastStartedTaskId = -1;
|
||||||
|
|
||||||
public GestureState(OverviewComponentObserver componentObserver, int gestureId) {
|
public GestureState(OverviewComponentObserver componentObserver, int gestureId) {
|
||||||
@@ -147,6 +150,7 @@ public class GestureState implements RecentsAnimationCallbacks.RecentsAnimationL
|
|||||||
mRunningTask = other.mRunningTask;
|
mRunningTask = other.mRunningTask;
|
||||||
mEndTarget = other.mEndTarget;
|
mEndTarget = other.mEndTarget;
|
||||||
mLastAppearedTaskTarget = other.mLastAppearedTaskTarget;
|
mLastAppearedTaskTarget = other.mLastAppearedTaskTarget;
|
||||||
|
mPreviouslyAppearedTaskIds = other.mPreviouslyAppearedTaskIds;
|
||||||
mLastStartedTaskId = other.mLastStartedTaskId;
|
mLastStartedTaskId = other.mLastStartedTaskId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -234,6 +238,9 @@ public class GestureState implements RecentsAnimationCallbacks.RecentsAnimationL
|
|||||||
*/
|
*/
|
||||||
public void updateLastAppearedTaskTarget(RemoteAnimationTargetCompat lastAppearedTaskTarget) {
|
public void updateLastAppearedTaskTarget(RemoteAnimationTargetCompat lastAppearedTaskTarget) {
|
||||||
mLastAppearedTaskTarget = lastAppearedTaskTarget;
|
mLastAppearedTaskTarget = lastAppearedTaskTarget;
|
||||||
|
if (lastAppearedTaskTarget != null) {
|
||||||
|
mPreviouslyAppearedTaskIds.add(lastAppearedTaskTarget.taskId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -243,6 +250,14 @@ public class GestureState implements RecentsAnimationCallbacks.RecentsAnimationL
|
|||||||
return mLastAppearedTaskTarget != null ? mLastAppearedTaskTarget.taskId : -1;
|
return mLastAppearedTaskTarget != null ? mLastAppearedTaskTarget.taskId : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void updatePreviouslyAppearedTaskIds(Set<Integer> previouslyAppearedTaskIds) {
|
||||||
|
mPreviouslyAppearedTaskIds = previouslyAppearedTaskIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<Integer> getPreviouslyAppearedTaskIds() {
|
||||||
|
return mPreviouslyAppearedTaskIds;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the last task that we started via startActivityFromRecents() during this gesture.
|
* Updates the last task that we started via startActivityFromRecents() during this gesture.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -64,6 +64,9 @@ public class StatsLogCompatManager extends StatsLogManager {
|
|||||||
private static Context sContext;
|
private static Context sContext;
|
||||||
|
|
||||||
private static final InstanceId DEFAULT_INSTANCE_ID = InstanceId.fakeInstanceId(0);
|
private static final InstanceId DEFAULT_INSTANCE_ID = InstanceId.fakeInstanceId(0);
|
||||||
|
// LauncherAtom.ItemInfo.getDefaultInstance() should be used but until launcher proto migrates
|
||||||
|
// from nano to lite, bake constant to prevent robo test failure.
|
||||||
|
private static final int DEFAULT_PAGE_INDEX = -2;
|
||||||
private static final int FOLDER_HIERARCHY_OFFSET = 100;
|
private static final int FOLDER_HIERARCHY_OFFSET = 100;
|
||||||
|
|
||||||
public StatsLogCompatManager(Context context) {
|
public StatsLogCompatManager(Context context) {
|
||||||
@@ -75,7 +78,7 @@ public class StatsLogCompatManager extends StatsLogManager {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void log(EventEnum event) {
|
public void log(EventEnum event) {
|
||||||
log(event, DEFAULT_INSTANCE_ID, LauncherAtom.ItemInfo.getDefaultInstance());
|
log(event, DEFAULT_INSTANCE_ID, (ItemInfo) null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -83,26 +86,62 @@ public class StatsLogCompatManager extends StatsLogManager {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void log(EventEnum event, InstanceId instanceId) {
|
public void log(EventEnum event, InstanceId instanceId) {
|
||||||
log(event, instanceId, LauncherAtom.ItemInfo.getDefaultInstance());
|
log(event, instanceId, (ItemInfo) null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Logs an event and accompanying {@link ItemInfo}.
|
* Logs an event and accompanying {@link ItemInfo}.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void log(EventEnum event, @Nullable LauncherAtom.ItemInfo info) {
|
public void log(EventEnum event, @Nullable ItemInfo info) {
|
||||||
log(event, DEFAULT_INSTANCE_ID, info);
|
log(event, DEFAULT_INSTANCE_ID, info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logs an event.
|
||||||
|
*
|
||||||
|
* @param event an enum implementing EventEnum interface.
|
||||||
|
* @param atomInfo item typically containing app or task launch related information.
|
||||||
|
*/
|
||||||
|
public void log(EventEnum event, InstanceId instanceId, LauncherAtom.ItemInfo atomInfo) {
|
||||||
|
LauncherAppState.getInstance(sContext).getModel().enqueueModelUpdateTask(
|
||||||
|
new BaseModelUpdateTask() {
|
||||||
|
@Override
|
||||||
|
public void execute(LauncherAppState app, BgDataModel dataModel,
|
||||||
|
AllAppsList apps) {
|
||||||
|
write(event, instanceId, atomInfo, null,
|
||||||
|
LAUNCHER_UICHANGED__DST_STATE__HOME,
|
||||||
|
LAUNCHER_UICHANGED__DST_STATE__BACKGROUND);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logs an event.
|
||||||
|
*
|
||||||
|
* @param event an enum implementing EventEnum interface.
|
||||||
|
* @param atomItemInfo item typically containing app or task launch related information.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void log(EventEnum event, @Nullable LauncherAtom.ItemInfo atomItemInfo, int srcState,
|
||||||
|
int dstState) {
|
||||||
|
write(event, DEFAULT_INSTANCE_ID,
|
||||||
|
atomItemInfo == null ? LauncherAtom.ItemInfo.getDefaultInstance() : atomItemInfo,
|
||||||
|
null,
|
||||||
|
srcState,
|
||||||
|
dstState);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Logs an event and accompanying {@link InstanceId} and {@link LauncherAtom.ItemInfo}.
|
* Logs an event and accompanying {@link InstanceId} and {@link LauncherAtom.ItemInfo}.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void log(EventEnum event, InstanceId instanceId,
|
public void log(EventEnum event, InstanceId instanceId,
|
||||||
@Nullable LauncherAtom.ItemInfo info) {
|
@Nullable ItemInfo info) {
|
||||||
logInternal(event, instanceId, info,
|
logInternal(event, instanceId, info,
|
||||||
LAUNCHER_UICHANGED__DST_STATE__HOME,
|
LAUNCHER_UICHANGED__DST_STATE__HOME,
|
||||||
LAUNCHER_UICHANGED__DST_STATE__BACKGROUND);
|
LAUNCHER_UICHANGED__DST_STATE__BACKGROUND,
|
||||||
|
DEFAULT_PAGE_INDEX);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -124,38 +163,67 @@ public class StatsLogCompatManager extends StatsLogManager {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void log(EventEnum event, int srcState, int dstState, int pageIndex) {
|
public void log(EventEnum event, int srcState, int dstState, int pageIndex) {
|
||||||
LauncherAtom.ItemInfo info = LauncherAtom.ItemInfo.getDefaultInstance();
|
logInternal(event, DEFAULT_INSTANCE_ID, null, srcState, dstState, pageIndex);
|
||||||
if (srcState == LAUNCHER_UICHANGED__DST_STATE__HOME
|
|
||||||
|| dstState == LAUNCHER_UICHANGED__SRC_STATE__HOME) {
|
|
||||||
info = LauncherAtom.ItemInfo.newBuilder().setContainerInfo(
|
|
||||||
LauncherAtom.ContainerInfo.newBuilder().setWorkspace(
|
|
||||||
LauncherAtom.WorkspaceContainer.newBuilder().setPageIndex(pageIndex)
|
|
||||||
)).build();
|
|
||||||
}
|
|
||||||
logInternal(event, DEFAULT_INSTANCE_ID, info, srcState, dstState);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Logs an event and accompanying {@link InstanceId} and {@link LauncherAtom.ItemInfo}.
|
* Logs an event and accompanying {@link InstanceId} and {@link ItemInfo}.
|
||||||
*/
|
*/
|
||||||
private void logInternal(EventEnum event, InstanceId instanceId,
|
private void logInternal(EventEnum event, InstanceId instanceId,
|
||||||
@Nullable LauncherAtom.ItemInfo info, int srcState, int dstState) {
|
@Nullable ItemInfo info, int srcState, int dstState, int pageIndex) {
|
||||||
info = info == null ? LauncherAtom.ItemInfo.getDefaultInstance() : info;
|
|
||||||
|
|
||||||
if (IS_VERBOSE) {
|
LauncherAppState.getInstance(sContext).getModel().enqueueModelUpdateTask(
|
||||||
String name = (event instanceof LauncherEvent) ? ((LauncherEvent) event).name() :
|
new BaseModelUpdateTask() {
|
||||||
event.getId() + "";
|
@Override
|
||||||
|
public void execute(LauncherAppState app, BgDataModel dataModel,
|
||||||
|
AllAppsList apps) {
|
||||||
|
writeEvent(event, instanceId, info, srcState, dstState, pageIndex,
|
||||||
|
dataModel.folders);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
Log.d(TAG, instanceId == DEFAULT_INSTANCE_ID
|
private static void writeEvent(EventEnum event, InstanceId instanceId,
|
||||||
? String.format("\n%s (State:%s->%s) \n%s", name, getStateString(srcState),
|
@Nullable ItemInfo info, int srcState, int dstState, int pageIndex,
|
||||||
getStateString(dstState), info)
|
IntSparseArrayMap<FolderInfo> folders) {
|
||||||
: String.format("\n%s (State:%s->%s) (InstanceId:%s)\n%s", name, instanceId,
|
|
||||||
getStateString(srcState), getStateString(dstState), info));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Utilities.ATLEAST_R) {
|
if (!Utilities.ATLEAST_R) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
LauncherAtom.ItemInfo atomInfo = LauncherAtom.ItemInfo.getDefaultInstance();
|
||||||
|
if (info != null) {
|
||||||
|
if (info.container >= 0) {
|
||||||
|
atomInfo = info.buildProto(folders.get(info.container));
|
||||||
|
} else {
|
||||||
|
atomInfo = info.buildProto();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (srcState == LAUNCHER_UICHANGED__DST_STATE__HOME
|
||||||
|
|| dstState == LAUNCHER_UICHANGED__SRC_STATE__HOME) {
|
||||||
|
atomInfo = LauncherAtom.ItemInfo.newBuilder().setContainerInfo(
|
||||||
|
LauncherAtom.ContainerInfo.newBuilder().setWorkspace(
|
||||||
|
LauncherAtom.WorkspaceContainer.newBuilder().setPageIndex(pageIndex)
|
||||||
|
)).build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
write(event, instanceId, atomInfo, info, srcState, dstState);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void write(EventEnum event, InstanceId instanceId,
|
||||||
|
LauncherAtom.ItemInfo atomInfo,
|
||||||
|
@Nullable ItemInfo info,
|
||||||
|
int srcState, int dstState) {
|
||||||
|
if (IS_VERBOSE) {
|
||||||
|
String name = (event instanceof Enum) ? ((Enum) event).name() :
|
||||||
|
event.getId() + "";
|
||||||
|
|
||||||
|
Log.d(TAG, instanceId == DEFAULT_INSTANCE_ID
|
||||||
|
? String.format("\n%s (State:%s->%s) \n%s\n%s", name, getStateString(srcState),
|
||||||
|
getStateString(dstState), info, atomInfo)
|
||||||
|
: String.format("\n%s (State:%s->%s) (InstanceId:%s)\n%s\n%s", name,
|
||||||
|
getStateString(srcState), getStateString(dstState), instanceId, info,
|
||||||
|
atomInfo));
|
||||||
|
}
|
||||||
|
|
||||||
SysUiStatsLog.write(
|
SysUiStatsLog.write(
|
||||||
SysUiStatsLog.LAUNCHER_EVENT,
|
SysUiStatsLog.LAUNCHER_EVENT,
|
||||||
@@ -165,24 +233,24 @@ public class StatsLogCompatManager extends StatsLogManager {
|
|||||||
null /* launcher extensions, deprecated */,
|
null /* launcher extensions, deprecated */,
|
||||||
false /* quickstep_enabled, deprecated */,
|
false /* quickstep_enabled, deprecated */,
|
||||||
event.getId() /* event_id */,
|
event.getId() /* event_id */,
|
||||||
info.getItemCase().getNumber() /* target_id */,
|
atomInfo.getItemCase().getNumber() /* target_id */,
|
||||||
instanceId.getId() /* instance_id TODO */,
|
instanceId.getId() /* instance_id TODO */,
|
||||||
0 /* uid TODO */,
|
0 /* uid TODO */,
|
||||||
getPackageName(info) /* package_name */,
|
getPackageName(atomInfo) /* package_name */,
|
||||||
getComponentName(info) /* component_name */,
|
getComponentName(atomInfo) /* component_name */,
|
||||||
getGridX(info, false) /* grid_x */,
|
getGridX(atomInfo, false) /* grid_x */,
|
||||||
getGridY(info, false) /* grid_y */,
|
getGridY(atomInfo, false) /* grid_y */,
|
||||||
getPageId(info, false) /* page_id */,
|
getPageId(atomInfo, false) /* page_id */,
|
||||||
getGridX(info, true) /* grid_x_parent */,
|
getGridX(atomInfo, true) /* grid_x_parent */,
|
||||||
getGridY(info, true) /* grid_y_parent */,
|
getGridY(atomInfo, true) /* grid_y_parent */,
|
||||||
getPageId(info, true) /* page_id_parent */,
|
getPageId(atomInfo, true) /* page_id_parent */,
|
||||||
getHierarchy(info) /* hierarchy */,
|
getHierarchy(atomInfo) /* hierarchy */,
|
||||||
info.getIsWork() /* is_work_profile */,
|
atomInfo.getIsWork() /* is_work_profile */,
|
||||||
info.getRank() /* rank */,
|
atomInfo.getRank() /* rank */,
|
||||||
info.getFolderIcon().getFromLabelState().getNumber() /* fromState */,
|
atomInfo.getFolderIcon().getFromLabelState().getNumber() /* fromState */,
|
||||||
info.getFolderIcon().getToLabelState().getNumber() /* toState */,
|
atomInfo.getFolderIcon().getToLabelState().getNumber() /* toState */,
|
||||||
info.getFolderIcon().getLabelInfo() /* edittext */,
|
atomInfo.getFolderIcon().getLabelInfo() /* edittext */,
|
||||||
getCardinality(info) /* cardinality */);
|
getCardinality(atomInfo) /* cardinality */);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -333,7 +401,7 @@ public class StatsLogCompatManager extends StatsLogManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static String getStateString(int state) {
|
private static String getStateString(int state) {
|
||||||
switch(state) {
|
switch (state) {
|
||||||
case LAUNCHER_UICHANGED__DST_STATE__BACKGROUND:
|
case LAUNCHER_UICHANGED__DST_STATE__BACKGROUND:
|
||||||
return "BACKGROUND";
|
return "BACKGROUND";
|
||||||
case LAUNCHER_UICHANGED__DST_STATE__HOME:
|
case LAUNCHER_UICHANGED__DST_STATE__HOME:
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ import com.android.launcher3.BaseQuickstepLauncher;
|
|||||||
import com.android.launcher3.LauncherState;
|
import com.android.launcher3.LauncherState;
|
||||||
import com.android.launcher3.Workspace;
|
import com.android.launcher3.Workspace;
|
||||||
import com.android.launcher3.config.FeatureFlags;
|
import com.android.launcher3.config.FeatureFlags;
|
||||||
|
import com.android.launcher3.hybridhotseat.HotseatPredictionController;
|
||||||
import com.android.launcher3.statemanager.StateManager;
|
import com.android.launcher3.statemanager.StateManager;
|
||||||
import com.android.launcher3.statemanager.StateManager.StateListener;
|
import com.android.launcher3.statemanager.StateManager.StateListener;
|
||||||
import com.android.launcher3.util.OnboardingPrefs;
|
import com.android.launcher3.util.OnboardingPrefs;
|
||||||
@@ -100,6 +101,28 @@ public class QuickstepOnboardingPrefs extends OnboardingPrefs<BaseQuickstepLaunc
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!hasReachedMaxCount(HOTSEAT_DISCOVERY_TIP_COUNT)) {
|
||||||
|
stateManager.addStateListener(new StateListener<LauncherState>() {
|
||||||
|
boolean mFromAllApps = false;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStateTransitionStart(LauncherState toState) {
|
||||||
|
mFromAllApps = mLauncher.getStateManager().getCurrentStableState() == ALL_APPS;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStateTransitionComplete(LauncherState finalState) {
|
||||||
|
HotseatPredictionController client = mLauncher.getHotseatPredictionController();
|
||||||
|
if (mFromAllApps && finalState == NORMAL && client.hasPredictions()) {
|
||||||
|
if (incrementEventCount(HOTSEAT_DISCOVERY_TIP_COUNT)) {
|
||||||
|
client.showDiscoveryTip();
|
||||||
|
stateManager.removeStateListener(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (SysUINavigationMode.getMode(launcher) == NO_BUTTON
|
if (SysUINavigationMode.getMode(launcher) == NO_BUTTON
|
||||||
&& FeatureFlags.ENABLE_ALL_APPS_EDU.get()) {
|
&& FeatureFlags.ENABLE_ALL_APPS_EDU.get()) {
|
||||||
stateManager.addStateListener(new StateListener<LauncherState>() {
|
stateManager.addStateListener(new StateListener<LauncherState>() {
|
||||||
|
|||||||
@@ -26,8 +26,8 @@ import static android.view.Surface.ROTATION_90;
|
|||||||
import static com.android.launcher3.logging.LoggerUtils.extractObjectNameAndAddress;
|
import static com.android.launcher3.logging.LoggerUtils.extractObjectNameAndAddress;
|
||||||
import static com.android.launcher3.states.RotationHelper.ALLOW_ROTATION_PREFERENCE_KEY;
|
import static com.android.launcher3.states.RotationHelper.ALLOW_ROTATION_PREFERENCE_KEY;
|
||||||
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
|
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
|
||||||
|
|
||||||
import static com.android.quickstep.SysUINavigationMode.Mode.TWO_BUTTONS;
|
import static com.android.quickstep.SysUINavigationMode.Mode.TWO_BUTTONS;
|
||||||
|
|
||||||
import static java.lang.annotation.RetentionPolicy.SOURCE;
|
import static java.lang.annotation.RetentionPolicy.SOURCE;
|
||||||
|
|
||||||
import android.content.ContentResolver;
|
import android.content.ContentResolver;
|
||||||
@@ -49,6 +49,7 @@ import androidx.annotation.IntDef;
|
|||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
import com.android.launcher3.DeviceProfile;
|
import com.android.launcher3.DeviceProfile;
|
||||||
|
import com.android.launcher3.InvariantDeviceProfile;
|
||||||
import com.android.launcher3.Utilities;
|
import com.android.launcher3.Utilities;
|
||||||
import com.android.launcher3.testing.TestProtocol;
|
import com.android.launcher3.testing.TestProtocol;
|
||||||
import com.android.launcher3.touch.PagedOrientationHandler;
|
import com.android.launcher3.touch.PagedOrientationHandler;
|
||||||
@@ -197,7 +198,7 @@ public final class RecentsOrientedState implements SharedPreferences.OnSharedPre
|
|||||||
mPreviousRotation = touchRotation;
|
mPreviousRotation = touchRotation;
|
||||||
|
|
||||||
if (mLauncherRotation == mTouchRotation || canLauncherRotate()) {
|
if (mLauncherRotation == mTouchRotation || canLauncherRotate()) {
|
||||||
mOrientationHandler = PagedOrientationHandler.HOME_ROTATED;
|
mOrientationHandler = PagedOrientationHandler.PORTRAIT;
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Log.d(TAG, "current RecentsOrientedState: " + this);
|
Log.d(TAG, "current RecentsOrientedState: " + this);
|
||||||
}
|
}
|
||||||
@@ -526,4 +527,15 @@ public final class RecentsOrientedState implements SharedPreferences.OnSharedPre
|
|||||||
+ " mFlags=" + mFlags
|
+ " mFlags=" + mFlags
|
||||||
+ "]";
|
+ "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the device profile based on expected launcher rotation
|
||||||
|
*/
|
||||||
|
public DeviceProfile getLauncherDeviceProfile() {
|
||||||
|
InvariantDeviceProfile idp = InvariantDeviceProfile.INSTANCE.get(mContext);
|
||||||
|
// TODO also check the natural orientation is landscape or portrait
|
||||||
|
return (mLauncherRotation == ROTATION_90 || mLauncherRotation == ROTATION_270)
|
||||||
|
? idp.landscapeProfile
|
||||||
|
: idp.portraitProfile;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import static com.android.launcher3.anim.Interpolators.ACCEL;
|
|||||||
import static com.android.launcher3.anim.Interpolators.ACCEL_2;
|
import static com.android.launcher3.anim.Interpolators.ACCEL_2;
|
||||||
import static com.android.launcher3.anim.Interpolators.LINEAR;
|
import static com.android.launcher3.anim.Interpolators.LINEAR;
|
||||||
import static com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound;
|
import static com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound;
|
||||||
|
import static com.android.launcher3.util.SystemUiController.UI_STATE_SCRIM_VIEW;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
@@ -187,6 +188,7 @@ public class ShelfScrimView extends ScrimView<BaseQuickstepLauncher>
|
|||||||
mShelfTopAtThreshold = mShiftRange * SCRIM_CATCHUP_THRESHOLD + mTopOffset;
|
mShelfTopAtThreshold = mShiftRange * SCRIM_CATCHUP_THRESHOLD + mTopOffset;
|
||||||
}
|
}
|
||||||
updateColors();
|
updateColors();
|
||||||
|
updateSysUiColors();
|
||||||
updateDragHandleAlpha();
|
updateDragHandleAlpha();
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
@@ -240,6 +242,18 @@ public class ShelfScrimView extends ScrimView<BaseQuickstepLauncher>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void updateSysUiColors() {
|
||||||
|
// Use a light system UI (dark icons) if all apps is behind at least half of the
|
||||||
|
// status bar.
|
||||||
|
boolean forceChange = mShelfTop <= mLauncher.getDeviceProfile().getInsets().top / 2f;
|
||||||
|
if (forceChange) {
|
||||||
|
mLauncher.getSystemUiController().updateUiState(UI_STATE_SCRIM_VIEW, !mIsScrimDark);
|
||||||
|
} else {
|
||||||
|
mLauncher.getSystemUiController().updateUiState(UI_STATE_SCRIM_VIEW, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean shouldDragHandleBeVisible() {
|
protected boolean shouldDragHandleBeVisible() {
|
||||||
boolean needsAllAppsEdu = mIsTwoZoneSwipeModel
|
boolean needsAllAppsEdu = mIsTwoZoneSwipeModel
|
||||||
|
|||||||
@@ -37,7 +37,6 @@ import static org.junit.Assert.assertNotNull;
|
|||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
import android.app.Instrumentation;
|
import android.app.Instrumentation;
|
||||||
import android.content.ComponentName;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.pm.ActivityInfo;
|
import android.content.pm.ActivityInfo;
|
||||||
@@ -58,10 +57,8 @@ import com.android.launcher3.testcomponent.TestCommandReceiver;
|
|||||||
import com.android.launcher3.util.Wait;
|
import com.android.launcher3.util.Wait;
|
||||||
import com.android.launcher3.util.rule.FailureRewriterRule;
|
import com.android.launcher3.util.rule.FailureRewriterRule;
|
||||||
import com.android.launcher3.util.rule.FailureWatcher;
|
import com.android.launcher3.util.rule.FailureWatcher;
|
||||||
import com.android.quickstep.NavigationModeSwitchRule.NavigationModeSwitch;
|
|
||||||
import com.android.quickstep.views.RecentsView;
|
import com.android.quickstep.views.RecentsView;
|
||||||
|
|
||||||
import org.junit.Ignore;
|
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.rules.RuleChain;
|
import org.junit.rules.RuleChain;
|
||||||
@@ -95,7 +92,8 @@ public class FallbackRecentsTest {
|
|||||||
mDevice = UiDevice.getInstance(instrumentation);
|
mDevice = UiDevice.getInstance(instrumentation);
|
||||||
mDevice.setOrientationNatural();
|
mDevice.setOrientationNatural();
|
||||||
mLauncher = new LauncherInstrumentation();
|
mLauncher = new LauncherInstrumentation();
|
||||||
mLauncher.enableCheckEventsForSuccessfulGestures();
|
// b/143488140
|
||||||
|
//mLauncher.enableCheckEventsForSuccessfulGestures();
|
||||||
|
|
||||||
if (TestHelpers.isInLauncherProcess()) {
|
if (TestHelpers.isInLauncherProcess()) {
|
||||||
Utilities.enableRunningInTestHarnessForTests();
|
Utilities.enableRunningInTestHarnessForTests();
|
||||||
@@ -132,9 +130,9 @@ public class FallbackRecentsTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@NavigationModeSwitch
|
// b/143488140
|
||||||
|
//@NavigationModeSwitch
|
||||||
@Test
|
@Test
|
||||||
@Ignore // b/143488140
|
|
||||||
public void goToOverviewFromHome() {
|
public void goToOverviewFromHome() {
|
||||||
mDevice.pressHome();
|
mDevice.pressHome();
|
||||||
assertTrue("Fallback Launcher not visible", mDevice.wait(Until.hasObject(By.pkg(
|
assertTrue("Fallback Launcher not visible", mDevice.wait(Until.hasObject(By.pkg(
|
||||||
@@ -143,9 +141,9 @@ public class FallbackRecentsTest {
|
|||||||
mLauncher.getBackground().switchToOverview();
|
mLauncher.getBackground().switchToOverview();
|
||||||
}
|
}
|
||||||
|
|
||||||
@NavigationModeSwitch
|
// b/143488140
|
||||||
|
//@NavigationModeSwitch
|
||||||
@Test
|
@Test
|
||||||
@Ignore // b/143488140
|
|
||||||
public void goToOverviewFromApp() {
|
public void goToOverviewFromApp() {
|
||||||
startAppFast(resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR));
|
startAppFast(resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR));
|
||||||
|
|
||||||
@@ -178,9 +176,9 @@ public class FallbackRecentsTest {
|
|||||||
return mLauncher.getBackground().switchToOverview();
|
return mLauncher.getBackground().switchToOverview();
|
||||||
}
|
}
|
||||||
|
|
||||||
@NavigationModeSwitch
|
// b/143488140
|
||||||
|
//@NavigationModeSwitch
|
||||||
@Test
|
@Test
|
||||||
@Ignore // b/143488140
|
|
||||||
public void testOverview() {
|
public void testOverview() {
|
||||||
startAppFast(getAppPackageName());
|
startAppFast(getAppPackageName());
|
||||||
startAppFast(resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR));
|
startAppFast(resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR));
|
||||||
|
|||||||
@@ -45,6 +45,8 @@ public class StartLauncherViaGestureTests extends AbstractQuickStepTest {
|
|||||||
@Before
|
@Before
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
super.setUp();
|
super.setUp();
|
||||||
|
// b/143488140
|
||||||
|
mLauncher.pressHome();
|
||||||
// Start an activity where the gestures start.
|
// Start an activity where the gestures start.
|
||||||
startAppFast(resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR));
|
startAppFast(resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR));
|
||||||
}
|
}
|
||||||
@@ -98,7 +100,6 @@ public class StartLauncherViaGestureTests extends AbstractQuickStepTest {
|
|||||||
// The test action.
|
// The test action.
|
||||||
mLauncher.getBackground().switchToOverview();
|
mLauncher.getBackground().switchToOverview();
|
||||||
}
|
}
|
||||||
// Workaround for b/157099707
|
|
||||||
mLauncher.pressHome();
|
mLauncher.pressHome();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,6 +34,8 @@
|
|||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
|
android:paddingTop="5dp"
|
||||||
|
android:paddingBottom="5dp"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:layout_gravity="center_vertical"
|
android:layout_gravity="center_vertical"
|
||||||
android:textColor="@android:color/white"
|
android:textColor="@android:color/white"
|
||||||
@@ -58,6 +60,5 @@
|
|||||||
android:elevation="2dp"
|
android:elevation="2dp"
|
||||||
android:layout_width="10dp"
|
android:layout_width="10dp"
|
||||||
android:layout_height="8dp"
|
android:layout_height="8dp"
|
||||||
android:layout_marginTop="-2dp"
|
android:layout_marginTop="-2dp"/>
|
||||||
android:layout_gravity="center_horizontal"/>
|
|
||||||
</merge>
|
</merge>
|
||||||
|
|||||||
@@ -172,8 +172,10 @@
|
|||||||
<string name="folder_closed">Folder closed</string>
|
<string name="folder_closed">Folder closed</string>
|
||||||
<!-- Folder renamed format -->
|
<!-- Folder renamed format -->
|
||||||
<string name="folder_renamed">Folder renamed to <xliff:g id="name" example="Games">%1$s</xliff:g></string>
|
<string name="folder_renamed">Folder renamed to <xliff:g id="name" example="Games">%1$s</xliff:g></string>
|
||||||
<!-- Folder name format -->
|
<!-- Folder name format when folder has less than 4 items -->
|
||||||
<string name="folder_name_format">Folder: <xliff:g id="name" example="Games">%1$s</xliff:g></string>
|
<string name="folder_name_format_exact">Folder: <xliff:g id="name" example="Games">%1$s</xliff:g>, <xliff:g id="size" example="2">%2$d</xliff:g> items</string>
|
||||||
|
<!-- Folder name format when folder has 4 or more items shown in preview-->
|
||||||
|
<string name="folder_name_format_overflow">Folder: <xliff:g id="name" example="Games">%1$s</xliff:g>, <xliff:g id="size" example="2">%2$d</xliff:g> or more items</string>
|
||||||
|
|
||||||
<!-- Strings for the customization mode -->
|
<!-- Strings for the customization mode -->
|
||||||
<!-- Text for widget add button -->
|
<!-- Text for widget add button -->
|
||||||
|
|||||||
@@ -89,6 +89,22 @@ public class DefaultLayoutProviderTest {
|
|||||||
assertEquals(3, ((FolderInfo) info).contents.size());
|
assertEquals(3, ((FolderInfo) info).contents.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCustomProfileLoaded_with_folder_custom_title() throws Exception {
|
||||||
|
writeLayoutAndLoad(new LauncherLayoutBuilder().atHotseat(0).putFolder("CustomFolder")
|
||||||
|
.addApp(TEST_PACKAGE, TEST_PACKAGE)
|
||||||
|
.addApp(TEST_PACKAGE, TEST_PACKAGE)
|
||||||
|
.addApp(TEST_PACKAGE, TEST_PACKAGE)
|
||||||
|
.build());
|
||||||
|
|
||||||
|
// Verify folder
|
||||||
|
assertEquals(1, mModelHelper.getBgDataModel().workspaceItems.size());
|
||||||
|
ItemInfo info = mModelHelper.getBgDataModel().workspaceItems.get(0);
|
||||||
|
assertEquals(LauncherSettings.Favorites.ITEM_TYPE_FOLDER, info.itemType);
|
||||||
|
assertEquals(3, ((FolderInfo) info).contents.size());
|
||||||
|
assertEquals("CustomFolder", info.title.toString());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCustomProfileLoaded_with_widget() throws Exception {
|
public void testCustomProfileLoaded_with_widget() throws Exception {
|
||||||
String pendingAppPkg = "com.test.pending";
|
String pendingAppPkg = "com.test.pending";
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ public class LauncherLayoutBuilder {
|
|||||||
private static final String ATTR_PACKAGE_NAME = "packageName";
|
private static final String ATTR_PACKAGE_NAME = "packageName";
|
||||||
private static final String ATTR_CLASS_NAME = "className";
|
private static final String ATTR_CLASS_NAME = "className";
|
||||||
private static final String ATTR_TITLE = "title";
|
private static final String ATTR_TITLE = "title";
|
||||||
|
private static final String ATTR_TITLE_TEXT = "titleText";
|
||||||
private static final String ATTR_SCREEN = "screen";
|
private static final String ATTR_SCREEN = "screen";
|
||||||
|
|
||||||
// x and y can be specified as negative integers, in which case -1 represents the
|
// x and y can be specified as negative integers, in which case -1 represents the
|
||||||
@@ -145,8 +146,17 @@ public class LauncherLayoutBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public FolderBuilder putFolder(int titleResId) {
|
public FolderBuilder putFolder(int titleResId) {
|
||||||
FolderBuilder folderBuilder = new FolderBuilder();
|
|
||||||
items.put(ATTR_TITLE, Integer.toString(titleResId));
|
items.put(ATTR_TITLE, Integer.toString(titleResId));
|
||||||
|
return putFolder();
|
||||||
|
}
|
||||||
|
|
||||||
|
public FolderBuilder putFolder(String title) {
|
||||||
|
items.put(ATTR_TITLE_TEXT, title);
|
||||||
|
return putFolder();
|
||||||
|
}
|
||||||
|
|
||||||
|
private FolderBuilder putFolder() {
|
||||||
|
FolderBuilder folderBuilder = new FolderBuilder();
|
||||||
items.put(ATTR_CHILDREN, folderBuilder.mChildren);
|
items.put(ATTR_CHILDREN, folderBuilder.mChildren);
|
||||||
mNodes.add(Pair.create(TAG_FOLDER, items));
|
mNodes.add(Pair.create(TAG_FOLDER, items));
|
||||||
return folderBuilder;
|
return folderBuilder;
|
||||||
|
|||||||
@@ -174,7 +174,8 @@ public abstract class AbstractFloatingView extends LinearLayout implements Touch
|
|||||||
targetInfo.first, TYPE_WINDOW_STATE_CHANGED, targetInfo.second);
|
targetInfo.first, TYPE_WINDOW_STATE_CHANGED, targetInfo.second);
|
||||||
|
|
||||||
if (mIsOpen) {
|
if (mIsOpen) {
|
||||||
performAccessibilityAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null);
|
getAccessibilityInitialFocusView().performAccessibilityAction(
|
||||||
|
AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null);
|
||||||
}
|
}
|
||||||
ActivityContext.lookupContext(getContext()).getDragLayer()
|
ActivityContext.lookupContext(getContext()).getDragLayer()
|
||||||
.sendAccessibilityEvent(TYPE_WINDOW_CONTENT_CHANGED);
|
.sendAccessibilityEvent(TYPE_WINDOW_CONTENT_CHANGED);
|
||||||
@@ -184,6 +185,11 @@ public abstract class AbstractFloatingView extends LinearLayout implements Touch
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Returns the View that Accessibility services should focus on first. */
|
||||||
|
protected View getAccessibilityInitialFocusView() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a view matching FloatingViewType
|
* Returns a view matching FloatingViewType
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -132,6 +132,7 @@ public class AutoInstallsLayout {
|
|||||||
private static final String ATTR_PACKAGE_NAME = "packageName";
|
private static final String ATTR_PACKAGE_NAME = "packageName";
|
||||||
private static final String ATTR_CLASS_NAME = "className";
|
private static final String ATTR_CLASS_NAME = "className";
|
||||||
private static final String ATTR_TITLE = "title";
|
private static final String ATTR_TITLE = "title";
|
||||||
|
private static final String ATTR_TITLE_TEXT = "titleText";
|
||||||
private static final String ATTR_SCREEN = "screen";
|
private static final String ATTR_SCREEN = "screen";
|
||||||
|
|
||||||
// x and y can be specified as negative integers, in which case -1 represents the
|
// x and y can be specified as negative integers, in which case -1 represents the
|
||||||
@@ -585,7 +586,8 @@ public class AutoInstallsLayout {
|
|||||||
if (titleResId != 0) {
|
if (titleResId != 0) {
|
||||||
title = mSourceRes.getString(titleResId);
|
title = mSourceRes.getString(titleResId);
|
||||||
} else {
|
} else {
|
||||||
title = "";
|
String titleText = getAttributeValue(parser, ATTR_TITLE_TEXT);
|
||||||
|
title = TextUtils.isEmpty(titleText) ? "" : titleText;
|
||||||
}
|
}
|
||||||
|
|
||||||
mValues.put(Favorites.TITLE, title);
|
mValues.put(Favorites.TITLE, title);
|
||||||
|
|||||||
@@ -43,6 +43,8 @@ import android.widget.Toast;
|
|||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
import com.android.launcher3.LauncherSettings.Favorites;
|
import com.android.launcher3.LauncherSettings.Favorites;
|
||||||
|
import com.android.launcher3.logging.InstanceId;
|
||||||
|
import com.android.launcher3.logging.InstanceIdSequence;
|
||||||
import com.android.launcher3.model.AppLaunchTracker;
|
import com.android.launcher3.model.AppLaunchTracker;
|
||||||
import com.android.launcher3.model.data.ItemInfo;
|
import com.android.launcher3.model.data.ItemInfo;
|
||||||
import com.android.launcher3.model.data.WorkspaceItemInfo;
|
import com.android.launcher3.model.data.WorkspaceItemInfo;
|
||||||
@@ -188,7 +190,8 @@ public abstract class BaseDraggingActivity extends BaseActivity
|
|||||||
}
|
}
|
||||||
getUserEventDispatcher().logAppLaunch(v, intent, user);
|
getUserEventDispatcher().logAppLaunch(v, intent, user);
|
||||||
if (item != null) {
|
if (item != null) {
|
||||||
getStatsLogManager().log(LAUNCHER_APP_LAUNCH_TAP, item.buildProto());
|
InstanceId instanceId = new InstanceIdSequence().newInstanceId();
|
||||||
|
logAppLaunch(item, instanceId);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
} catch (NullPointerException|ActivityNotFoundException|SecurityException e) {
|
} catch (NullPointerException|ActivityNotFoundException|SecurityException e) {
|
||||||
@@ -198,6 +201,10 @@ public abstract class BaseDraggingActivity extends BaseActivity
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void logAppLaunch(ItemInfo info, InstanceId instanceId) {
|
||||||
|
getStatsLogManager().log(LAUNCHER_APP_LAUNCH_TAP, instanceId, info);
|
||||||
|
}
|
||||||
|
|
||||||
private void startShortcutIntentSafely(Intent intent, Bundle optsBundle, ItemInfo info,
|
private void startShortcutIntentSafely(Intent intent, Bundle optsBundle, ItemInfo info,
|
||||||
@Nullable String sourceContainer) {
|
@Nullable String sourceContainer) {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -163,6 +163,7 @@ public class LauncherSettings {
|
|||||||
public static final int CONTAINER_SEARCH_RESULTS = -106;
|
public static final int CONTAINER_SEARCH_RESULTS = -106;
|
||||||
public static final int CONTAINER_SHORTCUTS = -107;
|
public static final int CONTAINER_SHORTCUTS = -107;
|
||||||
public static final int CONTAINER_SETTINGS = -108;
|
public static final int CONTAINER_SETTINGS = -108;
|
||||||
|
public static final int CONTAINER_TASKSWITCHER = -109;
|
||||||
|
|
||||||
public static final String containerToString(int container) {
|
public static final String containerToString(int container) {
|
||||||
switch (container) {
|
switch (container) {
|
||||||
@@ -249,6 +250,12 @@ public class LauncherSettings {
|
|||||||
*/
|
*/
|
||||||
public static final int ITEM_TYPE_DEEP_SHORTCUT = 6;
|
public static final int ITEM_TYPE_DEEP_SHORTCUT = 6;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type of the item is recents task.
|
||||||
|
* TODO(hyunyoungs): move constants not related to Favorites DB to a better location.
|
||||||
|
*/
|
||||||
|
public static final int ITEM_TYPE_TASK = 7;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The appWidgetId of the widget
|
* The appWidgetId of the widget
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -606,6 +606,7 @@ public final class Utilities {
|
|||||||
outObj[0] = activityInfo;
|
outObj[0] = activityInfo;
|
||||||
return activityInfo.getFullResIcon(appState.getIconCache());
|
return activityInfo.getFullResIcon(appState.getIconCache());
|
||||||
}
|
}
|
||||||
|
if (info.getIntent() == null || info.getIntent().getPackage() == null) return null;
|
||||||
List<ShortcutInfo> si = ShortcutKey.fromItemInfo(info)
|
List<ShortcutInfo> si = ShortcutKey.fromItemInfo(info)
|
||||||
.buildRequest(launcher)
|
.buildRequest(launcher)
|
||||||
.query(ShortcutRequest.ALL);
|
.query(ShortcutRequest.ALL);
|
||||||
|
|||||||
@@ -418,10 +418,7 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
|
|||||||
mStatsLogManager.log(
|
mStatsLogManager.log(
|
||||||
LauncherEvent.LAUNCHER_ITEM_DRAG_STARTED,
|
LauncherEvent.LAUNCHER_ITEM_DRAG_STARTED,
|
||||||
dragObject.logInstanceId,
|
dragObject.logInstanceId,
|
||||||
dragObject.dragSource instanceof Folder
|
dragObject.originalDragInfo
|
||||||
? dragObject.originalDragInfo
|
|
||||||
.buildProto(((Folder) dragObject.dragSource).mInfo)
|
|
||||||
: dragObject.originalDragInfo.buildProto()
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1652,7 +1649,7 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
|
|||||||
mStatsLogManager.log(
|
mStatsLogManager.log(
|
||||||
LauncherEvent.LAUNCHER_ITEM_DROP_FOLDER_CREATED,
|
LauncherEvent.LAUNCHER_ITEM_DROP_FOLDER_CREATED,
|
||||||
d.logInstanceId,
|
d.logInstanceId,
|
||||||
destInfo.buildProto(null));
|
destInfo);
|
||||||
FolderIcon fi = mLauncher.addFolder(target, container, screenId, targetCell[0],
|
FolderIcon fi = mLauncher.addFolder(target, container, screenId, targetCell[0],
|
||||||
targetCell[1]);
|
targetCell[1]);
|
||||||
destInfo.cellX = -1;
|
destInfo.cellX = -1;
|
||||||
@@ -1693,7 +1690,7 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
|
|||||||
mStatsLogManager.log(
|
mStatsLogManager.log(
|
||||||
LauncherEvent.LAUNCHER_ITEM_DROP_COMPLETED,
|
LauncherEvent.LAUNCHER_ITEM_DROP_COMPLETED,
|
||||||
d.logInstanceId,
|
d.logInstanceId,
|
||||||
fi.mInfo.buildProto(null));
|
fi.mInfo);
|
||||||
fi.onDrop(d, false /* itemReturnedOnFailedDrop */);
|
fi.onDrop(d, false /* itemReturnedOnFailedDrop */);
|
||||||
|
|
||||||
// if the drag started here, we need to remove it from the workspace
|
// if the drag started here, we need to remove it from the workspace
|
||||||
@@ -1899,7 +1896,7 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
|
|||||||
mStatsLogManager.log(
|
mStatsLogManager.log(
|
||||||
LauncherEvent.LAUNCHER_ITEM_DROP_COMPLETED,
|
LauncherEvent.LAUNCHER_ITEM_DROP_COMPLETED,
|
||||||
d.logInstanceId,
|
d.logInstanceId,
|
||||||
d.dragInfo.buildProto(null));
|
d.dragInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (d.stateAnnouncer != null && !droppedOnOriginalCell) {
|
if (d.stateAnnouncer != null && !droppedOnOriginalCell) {
|
||||||
@@ -2440,7 +2437,7 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
|
|||||||
mStatsLogManager.log(
|
mStatsLogManager.log(
|
||||||
LauncherEvent.LAUNCHER_ITEM_DROP_COMPLETED,
|
LauncherEvent.LAUNCHER_ITEM_DROP_COMPLETED,
|
||||||
d.logInstanceId,
|
d.logInstanceId,
|
||||||
d.dragInfo.buildProto(null));
|
d.dragInfo);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
boolean isWidget = pendingInfo.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET
|
boolean isWidget = pendingInfo.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET
|
||||||
@@ -2532,7 +2529,7 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
|
|||||||
mStatsLogManager.log(
|
mStatsLogManager.log(
|
||||||
LauncherEvent.LAUNCHER_ITEM_DROP_COMPLETED,
|
LauncherEvent.LAUNCHER_ITEM_DROP_COMPLETED,
|
||||||
d.logInstanceId,
|
d.logInstanceId,
|
||||||
d.dragInfo.buildProto(null));
|
d.dragInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_APPS_FA
|
|||||||
import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_APPS_HEADER_FADE;
|
import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_APPS_HEADER_FADE;
|
||||||
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_SCALE;
|
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_SCALE;
|
||||||
import static com.android.launcher3.states.StateAnimationConfig.ANIM_VERTICAL_PROGRESS;
|
import static com.android.launcher3.states.StateAnimationConfig.ANIM_VERTICAL_PROGRESS;
|
||||||
import static com.android.launcher3.util.SystemUiController.UI_STATE_ALL_APPS;
|
|
||||||
|
|
||||||
import android.animation.Animator;
|
import android.animation.Animator;
|
||||||
import android.animation.AnimatorListenerAdapter;
|
import android.animation.AnimatorListenerAdapter;
|
||||||
@@ -37,7 +36,6 @@ import com.android.launcher3.anim.PropertySetter;
|
|||||||
import com.android.launcher3.statemanager.StateManager.StateHandler;
|
import com.android.launcher3.statemanager.StateManager.StateHandler;
|
||||||
import com.android.launcher3.states.StateAnimationConfig;
|
import com.android.launcher3.states.StateAnimationConfig;
|
||||||
import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
|
import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
|
||||||
import com.android.launcher3.util.Themes;
|
|
||||||
import com.android.launcher3.views.ScrimView;
|
import com.android.launcher3.views.ScrimView;
|
||||||
import com.android.systemui.plugins.AllAppsSearchPlugin;
|
import com.android.systemui.plugins.AllAppsSearchPlugin;
|
||||||
import com.android.systemui.plugins.PluginListener;
|
import com.android.systemui.plugins.PluginListener;
|
||||||
@@ -75,7 +73,6 @@ public class AllAppsTransitionController implements StateHandler<LauncherState>,
|
|||||||
private ScrimView mScrimView;
|
private ScrimView mScrimView;
|
||||||
|
|
||||||
private final Launcher mLauncher;
|
private final Launcher mLauncher;
|
||||||
private final boolean mIsDarkTheme;
|
|
||||||
private boolean mIsVerticalLayout;
|
private boolean mIsVerticalLayout;
|
||||||
|
|
||||||
// Animation in this class is controlled by a single variable {@link mProgress}.
|
// Animation in this class is controlled by a single variable {@link mProgress}.
|
||||||
@@ -98,7 +95,6 @@ public class AllAppsTransitionController implements StateHandler<LauncherState>,
|
|||||||
mShiftRange = mLauncher.getDeviceProfile().heightPx;
|
mShiftRange = mLauncher.getDeviceProfile().heightPx;
|
||||||
mProgress = 1f;
|
mProgress = 1f;
|
||||||
|
|
||||||
mIsDarkTheme = Themes.getAttrBoolean(mLauncher, R.attr.isMainColorDark);
|
|
||||||
mIsVerticalLayout = mLauncher.getDeviceProfile().isVerticalBarLayout();
|
mIsVerticalLayout = mLauncher.getDeviceProfile().isVerticalBarLayout();
|
||||||
mLauncher.addOnDeviceProfileChangeListener(this);
|
mLauncher.addOnDeviceProfileChangeListener(this);
|
||||||
}
|
}
|
||||||
@@ -137,16 +133,6 @@ public class AllAppsTransitionController implements StateHandler<LauncherState>,
|
|||||||
if (mPlugin != null) {
|
if (mPlugin != null) {
|
||||||
mPlugin.setProgress(progress);
|
mPlugin.setProgress(progress);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use a light system UI (dark icons) if all apps is behind at least half of the
|
|
||||||
// status bar.
|
|
||||||
boolean forceChange = Math.min(shiftCurrent, mScrimView.getVisualTop())
|
|
||||||
<= mLauncher.getDeviceProfile().getInsets().top / 2f;
|
|
||||||
if (forceChange) {
|
|
||||||
mLauncher.getSystemUiController().updateUiState(UI_STATE_ALL_APPS, !mIsDarkTheme);
|
|
||||||
} else {
|
|
||||||
mLauncher.getSystemUiController().updateUiState(UI_STATE_ALL_APPS, 0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public float getProgress() {
|
public float getProgress() {
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ public class FlingSpringAnim {
|
|||||||
|
|
||||||
private final FlingAnimation mFlingAnim;
|
private final FlingAnimation mFlingAnim;
|
||||||
private SpringAnimation mSpringAnim;
|
private SpringAnimation mSpringAnim;
|
||||||
|
private final boolean mSkipFlingAnim;
|
||||||
|
|
||||||
private float mTargetPosition;
|
private float mTargetPosition;
|
||||||
|
|
||||||
@@ -57,6 +58,10 @@ public class FlingSpringAnim {
|
|||||||
.setMaxValue(maxValue);
|
.setMaxValue(maxValue);
|
||||||
mTargetPosition = targetPosition;
|
mTargetPosition = targetPosition;
|
||||||
|
|
||||||
|
// We are already past the fling target, so skip it to avoid losing a frame of the spring.
|
||||||
|
mSkipFlingAnim = startPosition <= minValue && startVelocity < 0
|
||||||
|
|| startPosition >= maxValue && startVelocity > 0;
|
||||||
|
|
||||||
mFlingAnim.addEndListener(((animation, canceled, value, velocity) -> {
|
mFlingAnim.addEndListener(((animation, canceled, value, velocity) -> {
|
||||||
mSpringAnim = new SpringAnimation(object, property)
|
mSpringAnim = new SpringAnimation(object, property)
|
||||||
.setStartValue(value)
|
.setStartValue(value)
|
||||||
@@ -84,6 +89,9 @@ public class FlingSpringAnim {
|
|||||||
|
|
||||||
public void start() {
|
public void start() {
|
||||||
mFlingAnim.start();
|
mFlingAnim.start();
|
||||||
|
if (mSkipFlingAnim) {
|
||||||
|
mFlingAnim.cancel();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void end() {
|
public void end() {
|
||||||
|
|||||||
@@ -745,6 +745,11 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
|
|||||||
: getContext().getString(R.string.folder_closed));
|
: getContext().getString(R.string.folder_closed));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected View getAccessibilityInitialFocusView() {
|
||||||
|
return mContent.getFirstItem();
|
||||||
|
}
|
||||||
|
|
||||||
private void closeComplete(boolean wasAnimated) {
|
private void closeComplete(boolean wasAnimated) {
|
||||||
// TODO: Clear all active animations.
|
// TODO: Clear all active animations.
|
||||||
DragLayer parent = (DragLayer) getParent();
|
DragLayer parent = (DragLayer) getParent();
|
||||||
@@ -1333,7 +1338,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
|
|||||||
d.stateAnnouncer.completeAction(R.string.item_moved);
|
d.stateAnnouncer.completeAction(R.string.item_moved);
|
||||||
}
|
}
|
||||||
mStatsLogManager
|
mStatsLogManager
|
||||||
.log(LAUNCHER_ITEM_DROP_COMPLETED, d.logInstanceId, d.dragInfo.buildProto(mInfo));
|
.log(LAUNCHER_ITEM_DROP_COMPLETED, d.logInstanceId, d.dragInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is used so the item doesn't immediately appear in the folder when added. In one case
|
// This is used so the item doesn't immediately appear in the folder when added. In one case
|
||||||
@@ -1438,7 +1443,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
|
|||||||
if (hasFocus) {
|
if (hasFocus) {
|
||||||
startEditingFolderName();
|
startEditingFolderName();
|
||||||
} else {
|
} else {
|
||||||
mStatsLogManager.log(LAUNCHER_FOLDER_LABEL_UPDATED, mInfo.buildProto());
|
mStatsLogManager.log(LAUNCHER_FOLDER_LABEL_UPDATED, mInfo);
|
||||||
logFolderLabelState();
|
logFolderLabelState();
|
||||||
mFolderName.dispatchBackKey();
|
mFolderName.dispatchBackKey();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -201,8 +201,7 @@ public class FolderIcon extends FrameLayout implements FolderListener, IconLabel
|
|||||||
icon.mActivity = activity;
|
icon.mActivity = activity;
|
||||||
icon.mDotRenderer = grid.mDotRendererWorkSpace;
|
icon.mDotRenderer = grid.mDotRendererWorkSpace;
|
||||||
|
|
||||||
icon.setContentDescription(
|
icon.setContentDescription(icon.getAccessiblityTitle(folderInfo.title));
|
||||||
group.getContext().getString(R.string.folder_name_format, folderInfo.title));
|
|
||||||
|
|
||||||
// Keep the notification dot up to date with the sum of all the content's dots.
|
// Keep the notification dot up to date with the sum of all the content's dots.
|
||||||
FolderDotInfo folderDotInfo = new FolderDotInfo();
|
FolderDotInfo folderDotInfo = new FolderDotInfo();
|
||||||
@@ -450,7 +449,7 @@ public class FolderIcon extends FrameLayout implements FolderListener, IconLabel
|
|||||||
}
|
}
|
||||||
mInfo.setTitle(nameInfos[0].getLabel());
|
mInfo.setTitle(nameInfos[0].getLabel());
|
||||||
StatsLogManager.newInstance(getContext())
|
StatsLogManager.newInstance(getContext())
|
||||||
.log(LAUNCHER_FOLDER_LABEL_UPDATED, instanceId, mInfo.buildProto());
|
.log(LAUNCHER_FOLDER_LABEL_UPDATED, instanceId, mInfo);
|
||||||
onTitleChanged(mInfo.title);
|
onTitleChanged(mInfo.title);
|
||||||
mFolder.mFolderName.setText(mInfo.title);
|
mFolder.mFolderName.setText(mInfo.title);
|
||||||
mFolder.mLauncher.getModelWriter().updateItemInDatabase(mInfo);
|
mFolder.mLauncher.getModelWriter().updateItemInDatabase(mInfo);
|
||||||
@@ -665,6 +664,7 @@ public class FolderIcon extends FrameLayout implements FolderListener, IconLabel
|
|||||||
mDotInfo.addDotInfo(mActivity.getDotInfoForItem(item));
|
mDotInfo.addDotInfo(mActivity.getDotInfoForItem(item));
|
||||||
boolean isDotted = mDotInfo.hasDot();
|
boolean isDotted = mDotInfo.hasDot();
|
||||||
updateDotScale(wasDotted, isDotted);
|
updateDotScale(wasDotted, isDotted);
|
||||||
|
setContentDescription(getAccessiblityTitle(mInfo.title));
|
||||||
invalidate();
|
invalidate();
|
||||||
requestLayout();
|
requestLayout();
|
||||||
}
|
}
|
||||||
@@ -675,13 +675,14 @@ public class FolderIcon extends FrameLayout implements FolderListener, IconLabel
|
|||||||
mDotInfo.subtractDotInfo(mActivity.getDotInfoForItem(item));
|
mDotInfo.subtractDotInfo(mActivity.getDotInfoForItem(item));
|
||||||
boolean isDotted = mDotInfo.hasDot();
|
boolean isDotted = mDotInfo.hasDot();
|
||||||
updateDotScale(wasDotted, isDotted);
|
updateDotScale(wasDotted, isDotted);
|
||||||
|
setContentDescription(getAccessiblityTitle(mInfo.title));
|
||||||
invalidate();
|
invalidate();
|
||||||
requestLayout();
|
requestLayout();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onTitleChanged(CharSequence title) {
|
public void onTitleChanged(CharSequence title) {
|
||||||
mFolderName.setText(title);
|
mFolderName.setText(title);
|
||||||
setContentDescription(getContext().getString(R.string.folder_name_format, title));
|
setContentDescription(getAccessiblityTitle(title));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -775,4 +776,17 @@ public class FolderIcon extends FrameLayout implements FolderListener, IconLabel
|
|||||||
public void getWorkspaceVisualDragBounds(Rect bounds) {
|
public void getWorkspaceVisualDragBounds(Rect bounds) {
|
||||||
getPreviewBounds(bounds);
|
getPreviewBounds(bounds);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a formatted accessibility title for folder
|
||||||
|
*/
|
||||||
|
public String getAccessiblityTitle(CharSequence title) {
|
||||||
|
int size = mInfo.contents.size();
|
||||||
|
if (size < MAX_NUM_ITEMS_IN_PREVIEW) {
|
||||||
|
return getContext().getString(R.string.folder_name_format_exact, title, size);
|
||||||
|
} else {
|
||||||
|
return getContext().getString(R.string.folder_name_format_overflow, title,
|
||||||
|
MAX_NUM_ITEMS_IN_PREVIEW);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -70,8 +70,11 @@ public class FolderNameEditText extends ExtendedEditText {
|
|||||||
for (int i = 0; i < cnt; i++) {
|
for (int i = 0; i < cnt; i++) {
|
||||||
cInfo[i] = new CompletionInfo(i, i, suggestList.get(i));
|
cInfo[i] = new CompletionInfo(i, i, suggestList.get(i));
|
||||||
}
|
}
|
||||||
post(() -> getContext().getSystemService(InputMethodManager.class)
|
// post it to future frame so that onSelectionChanged, onFocusChanged, all other
|
||||||
.displayCompletions(this, cInfo));
|
// TextView flag change and IME animation has settled. Ideally, there should be IMM
|
||||||
|
// callback to notify when the IME animation and state handling is finished.
|
||||||
|
postDelayed(() -> getContext().getSystemService(InputMethodManager.class)
|
||||||
|
.displayCompletions(this, cInfo), 40 /* 2~3 frame delay */);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -44,6 +44,13 @@ public class InstanceIdSequence {
|
|||||||
mInstanceIdMax = min(max(1, instanceIdMax), InstanceId.INSTANCE_ID_MAX);
|
mInstanceIdMax = min(max(1, instanceIdMax), InstanceId.INSTANCE_ID_MAX);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a sequence with identifiers [1, InstanceId.INSTANCE_ID_MAX].
|
||||||
|
*/
|
||||||
|
public InstanceIdSequence() {
|
||||||
|
this(InstanceId.INSTANCE_ID_MAX);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the next instance from the sequence. Safe for concurrent use.
|
* Gets the next instance from the sequence. Safe for concurrent use.
|
||||||
* @return new InstanceId
|
* @return new InstanceId
|
||||||
|
|||||||
@@ -21,8 +21,9 @@ import androidx.annotation.Nullable;
|
|||||||
|
|
||||||
import com.android.launcher3.LauncherState;
|
import com.android.launcher3.LauncherState;
|
||||||
import com.android.launcher3.R;
|
import com.android.launcher3.R;
|
||||||
import com.android.launcher3.logger.LauncherAtom.ItemInfo;
|
import com.android.launcher3.logger.LauncherAtom;
|
||||||
import com.android.launcher3.logging.StatsLogUtils.LogStateProvider;
|
import com.android.launcher3.logging.StatsLogUtils.LogStateProvider;
|
||||||
|
import com.android.launcher3.model.data.ItemInfo;
|
||||||
import com.android.launcher3.util.ResourceBasedOverride;
|
import com.android.launcher3.util.ResourceBasedOverride;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -127,9 +128,29 @@ public class StatsLogManager implements ResourceBasedOverride {
|
|||||||
LAUNCHER_SYSTEM_SHORTCUT_PIN_TAP(522),
|
LAUNCHER_SYSTEM_SHORTCUT_PIN_TAP(522),
|
||||||
|
|
||||||
@UiEvent(doc = "User is shown All Apps education view.")
|
@UiEvent(doc = "User is shown All Apps education view.")
|
||||||
LAUNCHER_ALL_APPS_EDU_SHOWN(523);
|
LAUNCHER_ALL_APPS_EDU_SHOWN(523),
|
||||||
// ADD MORE
|
|
||||||
|
|
||||||
|
@UiEvent(doc = "User opened a folder.")
|
||||||
|
LAUNCHER_FOLDER_OPEN(551),
|
||||||
|
|
||||||
|
@UiEvent(doc = "Hotseat education half sheet seen")
|
||||||
|
LAUNCHER_HOTSEAT_EDU_SEEN(479),
|
||||||
|
|
||||||
|
@UiEvent(doc = "Hotseat migration accepted")
|
||||||
|
LAUNCHER_HOTSEAT_EDU_ACCEPT(480),
|
||||||
|
|
||||||
|
@UiEvent(doc = "Hotseat migration denied")
|
||||||
|
LAUNCHER_HOTSEAT_EDU_DENY(481),
|
||||||
|
|
||||||
|
@UiEvent(doc = "Hotseat education tip shown")
|
||||||
|
LAUNCHER_HOTSEAT_EDU_ONLY_TIP(482),
|
||||||
|
|
||||||
|
@UiEvent(doc = "App launch ranking logged for all apps predictions")
|
||||||
|
LAUNCHER_ALL_APPS_RANKED(552),
|
||||||
|
|
||||||
|
@UiEvent(doc = "App launch ranking logged for hotseat predictions)")
|
||||||
|
LAUNCHER_HOTSEAT_RANKED(553);
|
||||||
|
// ADD MORE
|
||||||
private final int mId;
|
private final int mId;
|
||||||
|
|
||||||
LauncherEvent(int id) {
|
LauncherEvent(int id) {
|
||||||
@@ -177,25 +198,56 @@ public class StatsLogManager implements ResourceBasedOverride {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Logs a {@link EventEnum}.
|
* Logs an event.
|
||||||
|
*
|
||||||
|
* @param event an enum implementing EventEnum interface.
|
||||||
*/
|
*/
|
||||||
public void log(EventEnum event) {
|
public void log(EventEnum event) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Logs an event and accompanying {@link InstanceId}.
|
* Logs an event.
|
||||||
|
*
|
||||||
|
* @param event an enum implementing EventEnum interface.
|
||||||
|
* @param instanceId an identifier obtained from an InstanceIdSequence.
|
||||||
*/
|
*/
|
||||||
public void log(EventEnum event, InstanceId instanceId) {
|
public void log(EventEnum event, InstanceId instanceId) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Logs an event and accompanying {@link ItemInfo}.
|
* Logs an event.
|
||||||
|
*
|
||||||
|
* @param event an enum implementing EventEnum interface.
|
||||||
|
* @param itemInfo item typically containing app or task launch related information.
|
||||||
*/
|
*/
|
||||||
public void log(EventEnum event, @Nullable ItemInfo itemInfo) {
|
public void log(EventEnum event, @Nullable ItemInfo itemInfo) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Logs an event and accompanying {@link InstanceId} and {@link ItemInfo}.
|
* Logs an event.
|
||||||
|
*
|
||||||
|
* @param event an enum implementing EventEnum interface.
|
||||||
|
* @param atomInfo item typically containing app or task launch related information.
|
||||||
|
*/
|
||||||
|
public void log(EventEnum event, InstanceId instanceId, LauncherAtom.ItemInfo atomInfo) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logs an event and accompanying {@link LauncherState}s.
|
||||||
|
*
|
||||||
|
* @param event an enum implementing EventEnum interface.
|
||||||
|
* @param launcherAtomItemInfo item typically containing app or task launch related information.
|
||||||
|
*/
|
||||||
|
public void log(EventEnum event, @Nullable LauncherAtom.ItemInfo launcherAtomItemInfo,
|
||||||
|
int srcState, int dstState) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logs an event.
|
||||||
|
*
|
||||||
|
* @param event an enum implementing EventEnum interface.
|
||||||
|
* @param instanceId an identifier obtained from an InstanceIdSequence.
|
||||||
|
* @param itemInfo item typically containing app or task launch related information.
|
||||||
*/
|
*/
|
||||||
public void log(EventEnum event, InstanceId instanceId, @Nullable ItemInfo itemInfo) {
|
public void log(EventEnum event, InstanceId instanceId, @Nullable ItemInfo itemInfo) {
|
||||||
}
|
}
|
||||||
@@ -204,7 +256,7 @@ public class StatsLogManager implements ResourceBasedOverride {
|
|||||||
* Log an event with ranked-choice information along with package. Does nothing if event.getId()
|
* Log an event with ranked-choice information along with package. Does nothing if event.getId()
|
||||||
* <= 0.
|
* <= 0.
|
||||||
*
|
*
|
||||||
* @param rankingEvent an enum implementing UiEventEnum interface.
|
* @param rankingEvent an enum implementing EventEnum interface.
|
||||||
* @param instanceId An identifier obtained from an InstanceIdSequence.
|
* @param instanceId An identifier obtained from an InstanceIdSequence.
|
||||||
* @param packageName the package name of the relevant app, if known (null otherwise).
|
* @param packageName the package name of the relevant app, if known (null otherwise).
|
||||||
* @param position the position picked.
|
* @param position the position picked.
|
||||||
|
|||||||
@@ -48,7 +48,6 @@ import androidx.annotation.Nullable;
|
|||||||
import com.android.launcher3.DropTarget;
|
import com.android.launcher3.DropTarget;
|
||||||
import com.android.launcher3.R;
|
import com.android.launcher3.R;
|
||||||
import com.android.launcher3.Utilities;
|
import com.android.launcher3.Utilities;
|
||||||
import com.android.launcher3.config.FeatureFlags;
|
|
||||||
import com.android.launcher3.logging.StatsLogUtils.LogContainerProvider;
|
import com.android.launcher3.logging.StatsLogUtils.LogContainerProvider;
|
||||||
import com.android.launcher3.model.data.ItemInfo;
|
import com.android.launcher3.model.data.ItemInfo;
|
||||||
import com.android.launcher3.userevent.LauncherLogProto;
|
import com.android.launcher3.userevent.LauncherLogProto;
|
||||||
@@ -143,14 +142,6 @@ public class UserEventDispatcher implements ResourceBasedOverride {
|
|||||||
fillIntentInfo(itemTarget, intent, userHandle);
|
fillIntentInfo(itemTarget, intent, userHandle);
|
||||||
}
|
}
|
||||||
LauncherEvent event = newLauncherEvent(action, targets);
|
LauncherEvent event = newLauncherEvent(action, targets);
|
||||||
ItemInfo info = v == null ? null : (ItemInfo) v.getTag();
|
|
||||||
if (info != null && Utilities.IS_DEBUG_DEVICE && FeatureFlags.ENABLE_HYBRID_HOTSEAT.get()) {
|
|
||||||
final String pkg = info.getTargetComponent() != null
|
|
||||||
? info.getTargetComponent().getPackageName() : "unknown";
|
|
||||||
FileLog.d(TAG, "appLaunch: packageName:" + pkg
|
|
||||||
+ ",isWorkApp:" + (info.user != null && !Process.myUserHandle().equals(
|
|
||||||
userHandle)) + ",launchLocation:" + info.container);
|
|
||||||
}
|
|
||||||
dispatchUserEvent(event, intent);
|
dispatchUserEvent(event, intent);
|
||||||
mAppOrTaskLaunch = true;
|
mAppOrTaskLaunch = true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,7 +59,6 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class takes care of shrinking the workspace (by maximum of one row and one column), as a
|
* This class takes care of shrinking the workspace (by maximum of one row and one column), as a
|
||||||
@@ -248,12 +247,25 @@ public class GridSizeMigrationTaskV2 {
|
|||||||
|
|
||||||
/** Return what's in the src but not in the dest */
|
/** Return what's in the src but not in the dest */
|
||||||
private static List<DbEntry> calcDiff(List<DbEntry> src, List<DbEntry> dest) {
|
private static List<DbEntry> calcDiff(List<DbEntry> src, List<DbEntry> dest) {
|
||||||
Set<String> destSet = dest.parallelStream().map(DbEntry::getIntentStr).collect(
|
Set<String> destIntentSet = new HashSet<>();
|
||||||
Collectors.toSet());
|
Set<Set<String>> destFolderIntentSet = new HashSet<>();
|
||||||
|
for (DbEntry entry : dest) {
|
||||||
|
if (entry.itemType == LauncherSettings.Favorites.ITEM_TYPE_FOLDER) {
|
||||||
|
destFolderIntentSet.add(entry.mFolderItems.keySet());
|
||||||
|
} else {
|
||||||
|
destIntentSet.add(entry.mIntent);
|
||||||
|
}
|
||||||
|
}
|
||||||
List<DbEntry> diff = new ArrayList<>();
|
List<DbEntry> diff = new ArrayList<>();
|
||||||
for (DbEntry entry : src) {
|
for (DbEntry entry : src) {
|
||||||
if (!destSet.contains(entry.mIntent)) {
|
if (entry.itemType == LauncherSettings.Favorites.ITEM_TYPE_FOLDER) {
|
||||||
diff.add(entry);
|
if (!destFolderIntentSet.contains(entry.mFolderItems.keySet())) {
|
||||||
|
diff.add(entry);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!destIntentSet.contains(entry.mIntent)) {
|
||||||
|
diff.add(entry);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return diff;
|
return diff;
|
||||||
|
|||||||
@@ -24,11 +24,13 @@ import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_PREDICT
|
|||||||
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_SEARCH_RESULTS;
|
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_SEARCH_RESULTS;
|
||||||
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_SETTINGS;
|
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_SETTINGS;
|
||||||
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_SHORTCUTS;
|
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_SHORTCUTS;
|
||||||
|
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_TASKSWITCHER;
|
||||||
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_WIDGETS_TRAY;
|
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_WIDGETS_TRAY;
|
||||||
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
|
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
|
||||||
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET;
|
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET;
|
||||||
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT;
|
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT;
|
||||||
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;
|
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;
|
||||||
|
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_TASK;
|
||||||
import static com.android.launcher3.logger.LauncherAtom.ContainerInfo.ContainerCase.CONTAINER_NOT_SET;
|
import static com.android.launcher3.logger.LauncherAtom.ContainerInfo.ContainerCase.CONTAINER_NOT_SET;
|
||||||
|
|
||||||
import android.content.ComponentName;
|
import android.content.ComponentName;
|
||||||
@@ -49,6 +51,7 @@ import com.android.launcher3.logger.LauncherAtom.PredictionContainer;
|
|||||||
import com.android.launcher3.logger.LauncherAtom.SearchResultContainer;
|
import com.android.launcher3.logger.LauncherAtom.SearchResultContainer;
|
||||||
import com.android.launcher3.logger.LauncherAtom.SettingsContainer;
|
import com.android.launcher3.logger.LauncherAtom.SettingsContainer;
|
||||||
import com.android.launcher3.logger.LauncherAtom.ShortcutsContainer;
|
import com.android.launcher3.logger.LauncherAtom.ShortcutsContainer;
|
||||||
|
import com.android.launcher3.logger.LauncherAtom.TaskSwitcherContainer;
|
||||||
import com.android.launcher3.util.ContentWriter;
|
import com.android.launcher3.util.ContentWriter;
|
||||||
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
@@ -298,6 +301,12 @@ public class ItemInfo {
|
|||||||
.setSpanX(spanX)
|
.setSpanX(spanX)
|
||||||
.setSpanY(spanY));
|
.setSpanY(spanY));
|
||||||
break;
|
break;
|
||||||
|
case ITEM_TYPE_TASK:
|
||||||
|
itemBuilder
|
||||||
|
.setTask(LauncherAtom.Task.newBuilder()
|
||||||
|
.setComponentName(getTargetComponent().flattenToShortString())
|
||||||
|
.setIndex(screenId));
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -378,6 +387,11 @@ public class ItemInfo {
|
|||||||
return ContainerInfo.newBuilder()
|
return ContainerInfo.newBuilder()
|
||||||
.setSettingsContainer(SettingsContainer.getDefaultInstance())
|
.setSettingsContainer(SettingsContainer.getDefaultInstance())
|
||||||
.build();
|
.build();
|
||||||
|
case CONTAINER_TASKSWITCHER:
|
||||||
|
return ContainerInfo.newBuilder()
|
||||||
|
.setTaskSwitcherContainer(TaskSwitcherContainer.getDefaultInstance())
|
||||||
|
.build();
|
||||||
|
|
||||||
}
|
}
|
||||||
return ContainerInfo.getDefaultInstance();
|
return ContainerInfo.getDefaultInstance();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ public class NotificationInfo implements View.OnClickListener {
|
|||||||
intent.send(null, 0, null, null, null, null, activityOptions);
|
intent.send(null, 0, null, null, null, null, activityOptions);
|
||||||
launcher.getUserEventDispatcher().logNotificationLaunch(view, intent);
|
launcher.getUserEventDispatcher().logNotificationLaunch(view, intent);
|
||||||
launcher.getStatsLogManager()
|
launcher.getStatsLogManager()
|
||||||
.log(LAUNCHER_NOTIFICATION_LAUNCH_TAP, mItemInfo.buildProto());
|
.log(LAUNCHER_NOTIFICATION_LAUNCH_TAP, mItemInfo);
|
||||||
} catch (PendingIntent.CanceledException e) {
|
} catch (PendingIntent.CanceledException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -389,6 +389,11 @@ public abstract class ArrowPopup<T extends BaseDraggingActivity> extends Abstrac
|
|||||||
return Pair.create(this, "");
|
return Pair.create(this, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected View getAccessibilityInitialFocusView() {
|
||||||
|
return getChildCount() > 0 ? getChildAt(0) : this;
|
||||||
|
}
|
||||||
|
|
||||||
private void animateOpen() {
|
private void animateOpen() {
|
||||||
setVisibility(View.VISIBLE);
|
setVisibility(View.VISIBLE);
|
||||||
|
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ public class RemoteActionShortcut extends SystemShortcut<BaseDraggingActivity> {
|
|||||||
public void onClick(View view) {
|
public void onClick(View view) {
|
||||||
AbstractFloatingView.closeAllOpenViews(mTarget);
|
AbstractFloatingView.closeAllOpenViews(mTarget);
|
||||||
mTarget.getStatsLogManager()
|
mTarget.getStatsLogManager()
|
||||||
.log(LAUNCHER_SYSTEM_SHORTCUT_PAUSE_TAP, mItemInfo.buildProto());
|
.log(LAUNCHER_SYSTEM_SHORTCUT_PAUSE_TAP, mItemInfo);
|
||||||
|
|
||||||
final String actionIdentity = mAction.getTitle() + ", "
|
final String actionIdentity = mAction.getTitle() + ", "
|
||||||
+ mItemInfo.getTargetComponent().getPackageName();
|
+ mItemInfo.getTargetComponent().getPackageName();
|
||||||
|
|||||||
@@ -119,9 +119,7 @@ public abstract class SystemShortcut<T extends BaseDraggingActivity> extends Ite
|
|||||||
widgetsBottomSheet.populateAndShow(mItemInfo);
|
widgetsBottomSheet.populateAndShow(mItemInfo);
|
||||||
mTarget.getUserEventDispatcher().logActionOnControl(Action.Touch.TAP,
|
mTarget.getUserEventDispatcher().logActionOnControl(Action.Touch.TAP,
|
||||||
ControlType.WIDGETS_BUTTON, view);
|
ControlType.WIDGETS_BUTTON, view);
|
||||||
// TODO(thiruram): Fix missing container info when item is inside folder.
|
mTarget.getStatsLogManager().log(LAUNCHER_SYSTEM_SHORTCUT_WIDGETS_TAP, mItemInfo);
|
||||||
mTarget.getStatsLogManager().log(LAUNCHER_SYSTEM_SHORTCUT_WIDGETS_TAP,
|
|
||||||
mItemInfo.buildProto());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -142,9 +140,8 @@ public abstract class SystemShortcut<T extends BaseDraggingActivity> extends Ite
|
|||||||
mItemInfo, sourceBounds, ActivityOptions.makeBasic().toBundle());
|
mItemInfo, sourceBounds, ActivityOptions.makeBasic().toBundle());
|
||||||
mTarget.getUserEventDispatcher().logActionOnControl(Action.Touch.TAP,
|
mTarget.getUserEventDispatcher().logActionOnControl(Action.Touch.TAP,
|
||||||
ControlType.APPINFO_TARGET, view);
|
ControlType.APPINFO_TARGET, view);
|
||||||
// TODO(thiruram): Fix missing container info when item is inside folder.
|
|
||||||
mTarget.getStatsLogManager()
|
mTarget.getStatsLogManager()
|
||||||
.log(LAUNCHER_SYSTEM_SHORTCUT_APP_INFO_TAP, mItemInfo.buildProto());
|
.log(LAUNCHER_SYSTEM_SHORTCUT_APP_INFO_TAP, mItemInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -310,6 +310,9 @@ public abstract class AbstractStateChangeTouchController
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void updateProgress(float fraction) {
|
protected void updateProgress(float fraction) {
|
||||||
|
if (mCurrentAnimation == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
mCurrentAnimation.setPlayFraction(fraction);
|
mCurrentAnimation.setPlayFraction(fraction);
|
||||||
if (mAtomicComponentsController != null) {
|
if (mAtomicComponentsController != null) {
|
||||||
// Make sure we don't divide by 0, and have at least a small runway.
|
// Make sure we don't divide by 0, and have at least a small runway.
|
||||||
|
|||||||
@@ -1,55 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.touch;
|
|
||||||
|
|
||||||
import android.graphics.RectF;
|
|
||||||
import android.view.Surface;
|
|
||||||
import android.widget.LinearLayout;
|
|
||||||
|
|
||||||
public class HomeRotatedPageHandler extends PortraitPagedViewHandler {
|
|
||||||
@Override
|
|
||||||
public void offsetTaskRect(RectF rect, float value, int displayRotation, int launcherRotation) {
|
|
||||||
if (launcherRotation == Surface.ROTATION_0) {
|
|
||||||
super.offsetTaskRect(rect, value, displayRotation, launcherRotation);
|
|
||||||
} else if (launcherRotation == Surface.ROTATION_90) {
|
|
||||||
if (displayRotation == Surface.ROTATION_0) {
|
|
||||||
rect.offset(0, value);
|
|
||||||
} else if (displayRotation == Surface.ROTATION_90) {
|
|
||||||
rect.offset(value, 0);
|
|
||||||
} else if (displayRotation == Surface.ROTATION_180) {
|
|
||||||
rect.offset(-value, 0);
|
|
||||||
} else {
|
|
||||||
rect.offset(-value, 0);
|
|
||||||
}
|
|
||||||
} else if (launcherRotation == Surface.ROTATION_270) {
|
|
||||||
if (displayRotation == Surface.ROTATION_0) {
|
|
||||||
rect.offset(0, -value);
|
|
||||||
} else if (displayRotation == Surface.ROTATION_90) {
|
|
||||||
rect.offset(value, 0);
|
|
||||||
} else if (displayRotation == Surface.ROTATION_180) {
|
|
||||||
rect.offset(0, -value);
|
|
||||||
} else {
|
|
||||||
rect.offset(value, 0);
|
|
||||||
}
|
|
||||||
} // TODO (b/149609488) handle 180 case as well
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getTaskMenuLayoutOrientation(LinearLayout taskMenuLayout) {
|
|
||||||
return taskMenuLayout.getOrientation();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -17,6 +17,7 @@ package com.android.launcher3.touch;
|
|||||||
|
|
||||||
import static com.android.launcher3.Launcher.REQUEST_BIND_PENDING_APPWIDGET;
|
import static com.android.launcher3.Launcher.REQUEST_BIND_PENDING_APPWIDGET;
|
||||||
import static com.android.launcher3.Launcher.REQUEST_RECONFIGURE_APPWIDGET;
|
import static com.android.launcher3.Launcher.REQUEST_RECONFIGURE_APPWIDGET;
|
||||||
|
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_FOLDER_OPEN;
|
||||||
import static com.android.launcher3.model.AppLaunchTracker.CONTAINER_ALL_APPS;
|
import static com.android.launcher3.model.AppLaunchTracker.CONTAINER_ALL_APPS;
|
||||||
import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_DISABLED_BY_PUBLISHER;
|
import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_DISABLED_BY_PUBLISHER;
|
||||||
import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_DISABLED_LOCKED_USER;
|
import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_DISABLED_LOCKED_USER;
|
||||||
@@ -45,6 +46,7 @@ import com.android.launcher3.R;
|
|||||||
import com.android.launcher3.Utilities;
|
import com.android.launcher3.Utilities;
|
||||||
import com.android.launcher3.folder.Folder;
|
import com.android.launcher3.folder.Folder;
|
||||||
import com.android.launcher3.folder.FolderIcon;
|
import com.android.launcher3.folder.FolderIcon;
|
||||||
|
import com.android.launcher3.logging.StatsLogManager;
|
||||||
import com.android.launcher3.model.data.AppInfo;
|
import com.android.launcher3.model.data.AppInfo;
|
||||||
import com.android.launcher3.model.data.FolderInfo;
|
import com.android.launcher3.model.data.FolderInfo;
|
||||||
import com.android.launcher3.model.data.ItemInfo;
|
import com.android.launcher3.model.data.ItemInfo;
|
||||||
@@ -111,6 +113,7 @@ public class ItemClickHandler {
|
|||||||
if (!folder.isOpen() && !folder.isDestroyed()) {
|
if (!folder.isOpen() && !folder.isDestroyed()) {
|
||||||
// Open the requested folder
|
// Open the requested folder
|
||||||
folder.animateOpen();
|
folder.animateOpen();
|
||||||
|
StatsLogManager.newInstance(v.getContext()).log(LAUNCHER_FOLDER_OPEN, folder.mInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -180,19 +180,6 @@ public class LandscapePagedViewHandler implements PagedOrientationHandler {
|
|||||||
return Surface.ROTATION_90;
|
return Surface.ROTATION_90;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void offsetTaskRect(RectF rect, float value, int displayRotation, int launcherRotation) {
|
|
||||||
if (displayRotation == Surface.ROTATION_0) {
|
|
||||||
rect.offset(0, value);
|
|
||||||
} else if (displayRotation == Surface.ROTATION_90) {
|
|
||||||
rect.offset(value, 0);
|
|
||||||
} else if (displayRotation == Surface.ROTATION_180) {
|
|
||||||
rect.offset(0, -value);
|
|
||||||
} else {
|
|
||||||
rect.offset(-value, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getChildStart(View view) {
|
public int getChildStart(View view) {
|
||||||
return view.getTop();
|
return view.getTop();
|
||||||
|
|||||||
@@ -43,7 +43,6 @@ public interface PagedOrientationHandler {
|
|||||||
PagedOrientationHandler PORTRAIT = new PortraitPagedViewHandler();
|
PagedOrientationHandler PORTRAIT = new PortraitPagedViewHandler();
|
||||||
PagedOrientationHandler LANDSCAPE = new LandscapePagedViewHandler();
|
PagedOrientationHandler LANDSCAPE = new LandscapePagedViewHandler();
|
||||||
PagedOrientationHandler SEASCAPE = new SeascapePagedViewHandler();
|
PagedOrientationHandler SEASCAPE = new SeascapePagedViewHandler();
|
||||||
PagedOrientationHandler HOME_ROTATED = new HomeRotatedPageHandler();
|
|
||||||
|
|
||||||
interface Int2DAction<T> {
|
interface Int2DAction<T> {
|
||||||
void call(T target, int x, int y);
|
void call(T target, int x, int y);
|
||||||
@@ -82,7 +81,6 @@ public interface PagedOrientationHandler {
|
|||||||
boolean getRecentsRtlSetting(Resources resources);
|
boolean getRecentsRtlSetting(Resources resources);
|
||||||
float getDegreesRotated();
|
float getDegreesRotated();
|
||||||
int getRotation();
|
int getRotation();
|
||||||
void offsetTaskRect(RectF rect, float value, int delta, int launcherRotation);
|
|
||||||
int getPrimaryValue(int x, int y);
|
int getPrimaryValue(int x, int y);
|
||||||
int getSecondaryValue(int x, int y);
|
int getSecondaryValue(int x, int y);
|
||||||
void delegateScrollTo(PagedView pagedView, int secondaryScroll, int primaryScroll);
|
void delegateScrollTo(PagedView pagedView, int secondaryScroll, int primaryScroll);
|
||||||
|
|||||||
@@ -178,19 +178,6 @@ public class PortraitPagedViewHandler implements PagedOrientationHandler {
|
|||||||
return Surface.ROTATION_0;
|
return Surface.ROTATION_0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void offsetTaskRect(RectF rect, float value, int displayRotation, int launcherRotation) {
|
|
||||||
if (displayRotation == Surface.ROTATION_0) {
|
|
||||||
rect.offset(value, 0);
|
|
||||||
} else if (displayRotation == Surface.ROTATION_90) {
|
|
||||||
rect.offset(0, -value);
|
|
||||||
} else if (displayRotation == Surface.ROTATION_180) {
|
|
||||||
rect.offset(-value, 0);
|
|
||||||
} else {
|
|
||||||
rect.offset(0, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getChildStart(View view) {
|
public int getChildStart(View view) {
|
||||||
return view.getLeft();
|
return view.getLeft();
|
||||||
@@ -250,7 +237,7 @@ public class PortraitPagedViewHandler implements PagedOrientationHandler {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getTaskMenuLayoutOrientation(LinearLayout taskMenuLayout) {
|
public int getTaskMenuLayoutOrientation(LinearLayout taskMenuLayout) {
|
||||||
return LinearLayout.VERTICAL;
|
return taskMenuLayout.getOrientation();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ package com.android.launcher3.touch;
|
|||||||
|
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
import android.graphics.PointF;
|
import android.graphics.PointF;
|
||||||
import android.graphics.RectF;
|
|
||||||
import android.view.Surface;
|
import android.view.Surface;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
@@ -41,19 +40,6 @@ public class SeascapePagedViewHandler extends LandscapePagedViewHandler {
|
|||||||
return Utilities.isRtl(resources);
|
return Utilities.isRtl(resources);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void offsetTaskRect(RectF rect, float value, int displayRotation, int launcherRotation) {
|
|
||||||
if (displayRotation == Surface.ROTATION_0) {
|
|
||||||
rect.offset(0, value);
|
|
||||||
} else if (displayRotation == Surface.ROTATION_90) {
|
|
||||||
rect.offset(value, 0);
|
|
||||||
} else if (displayRotation == Surface.ROTATION_180) {
|
|
||||||
rect.offset(0, -value);
|
|
||||||
} else {
|
|
||||||
rect.offset(-value, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public float getDegreesRotated() {
|
public float getDegreesRotated() {
|
||||||
return 270;
|
return 270;
|
||||||
|
|||||||
@@ -37,13 +37,14 @@ public class OnboardingPrefs<T extends Launcher> {
|
|||||||
public static final String HOME_BOUNCE_COUNT = "launcher.home_bounce_count";
|
public static final String HOME_BOUNCE_COUNT = "launcher.home_bounce_count";
|
||||||
public static final String SHELF_BOUNCE_COUNT = "launcher.shelf_bounce_count";
|
public static final String SHELF_BOUNCE_COUNT = "launcher.shelf_bounce_count";
|
||||||
public static final String ALL_APPS_COUNT = "launcher.all_apps_count";
|
public static final String ALL_APPS_COUNT = "launcher.all_apps_count";
|
||||||
|
public static final String HOTSEAT_DISCOVERY_TIP_COUNT = "launcher.hotseat_discovery_tip_count";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Events that either have happened or have not (booleans).
|
* Events that either have happened or have not (booleans).
|
||||||
*/
|
*/
|
||||||
@StringDef(value = {
|
@StringDef(value = {
|
||||||
HOME_BOUNCE_SEEN,
|
HOME_BOUNCE_SEEN,
|
||||||
SHELF_BOUNCE_SEEN,
|
SHELF_BOUNCE_SEEN
|
||||||
})
|
})
|
||||||
@Retention(RetentionPolicy.SOURCE)
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
public @interface EventBoolKey {}
|
public @interface EventBoolKey {}
|
||||||
@@ -55,6 +56,7 @@ public class OnboardingPrefs<T extends Launcher> {
|
|||||||
HOME_BOUNCE_COUNT,
|
HOME_BOUNCE_COUNT,
|
||||||
SHELF_BOUNCE_COUNT,
|
SHELF_BOUNCE_COUNT,
|
||||||
ALL_APPS_COUNT,
|
ALL_APPS_COUNT,
|
||||||
|
HOTSEAT_DISCOVERY_TIP_COUNT
|
||||||
})
|
})
|
||||||
@Retention(RetentionPolicy.SOURCE)
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
public @interface EventCountKey {}
|
public @interface EventCountKey {}
|
||||||
@@ -65,6 +67,7 @@ public class OnboardingPrefs<T extends Launcher> {
|
|||||||
maxCounts.put(HOME_BOUNCE_COUNT, 3);
|
maxCounts.put(HOME_BOUNCE_COUNT, 3);
|
||||||
maxCounts.put(SHELF_BOUNCE_COUNT, 3);
|
maxCounts.put(SHELF_BOUNCE_COUNT, 3);
|
||||||
maxCounts.put(ALL_APPS_COUNT, 5);
|
maxCounts.put(ALL_APPS_COUNT, 5);
|
||||||
|
maxCounts.put(HOTSEAT_DISCOVERY_TIP_COUNT, 5);
|
||||||
MAX_COUNTS = Collections.unmodifiableMap(maxCounts);
|
MAX_COUNTS = Collections.unmodifiableMap(maxCounts);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ public class SystemUiController {
|
|||||||
|
|
||||||
// Various UI states in increasing order of priority
|
// Various UI states in increasing order of priority
|
||||||
public static final int UI_STATE_BASE_WINDOW = 0;
|
public static final int UI_STATE_BASE_WINDOW = 0;
|
||||||
public static final int UI_STATE_ALL_APPS = 1;
|
public static final int UI_STATE_SCRIM_VIEW = 1;
|
||||||
public static final int UI_STATE_WIDGET_BOTTOM_SHEET = 2;
|
public static final int UI_STATE_WIDGET_BOTTOM_SHEET = 2;
|
||||||
public static final int UI_STATE_OVERVIEW = 3;
|
public static final int UI_STATE_OVERVIEW = 3;
|
||||||
|
|
||||||
@@ -61,25 +61,38 @@ public class SystemUiController {
|
|||||||
// Apply the state flags in priority order
|
// Apply the state flags in priority order
|
||||||
int newFlags = oldFlags;
|
int newFlags = oldFlags;
|
||||||
for (int stateFlag : mStates) {
|
for (int stateFlag : mStates) {
|
||||||
if (Utilities.ATLEAST_OREO) {
|
newFlags = getSysUiVisibilityFlags(stateFlag, newFlags);
|
||||||
if ((stateFlag & FLAG_LIGHT_NAV) != 0) {
|
|
||||||
newFlags |= View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
|
|
||||||
} else if ((stateFlag & FLAG_DARK_NAV) != 0) {
|
|
||||||
newFlags &= ~(View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((stateFlag & FLAG_LIGHT_STATUS) != 0) {
|
|
||||||
newFlags |= View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
|
|
||||||
} else if ((stateFlag & FLAG_DARK_STATUS) != 0) {
|
|
||||||
newFlags &= ~(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (newFlags != oldFlags) {
|
if (newFlags != oldFlags) {
|
||||||
mWindow.getDecorView().setSystemUiVisibility(newFlags);
|
mWindow.getDecorView().setSystemUiVisibility(newFlags);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the sysui visibility for the base layer
|
||||||
|
*/
|
||||||
|
public int getBaseSysuiVisibility() {
|
||||||
|
return getSysUiVisibilityFlags(
|
||||||
|
mStates[UI_STATE_BASE_WINDOW], mWindow.getDecorView().getSystemUiVisibility());
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getSysUiVisibilityFlags(int stateFlag, int currentVisibility) {
|
||||||
|
if (Utilities.ATLEAST_OREO) {
|
||||||
|
if ((stateFlag & FLAG_LIGHT_NAV) != 0) {
|
||||||
|
currentVisibility |= View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
|
||||||
|
} else if ((stateFlag & FLAG_DARK_NAV) != 0) {
|
||||||
|
currentVisibility &= ~(View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((stateFlag & FLAG_LIGHT_STATUS) != 0) {
|
||||||
|
currentVisibility |= View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
|
||||||
|
} else if ((stateFlag & FLAG_DARK_STATUS) != 0) {
|
||||||
|
currentVisibility &= ~(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
|
||||||
|
}
|
||||||
|
return currentVisibility;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "mStates=" + Arrays.toString(mStates);
|
return "mStates=" + Arrays.toString(mStates);
|
||||||
|
|||||||
@@ -125,11 +125,35 @@ public class ArrowTipView extends AbstractFloatingView {
|
|||||||
* Show Tip with specified string and Y location
|
* Show Tip with specified string and Y location
|
||||||
*/
|
*/
|
||||||
public ArrowTipView show(String text, int top) {
|
public ArrowTipView show(String text, int top) {
|
||||||
|
return show(text, Gravity.CENTER_HORIZONTAL, 0, top);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the ArrowTipView (tooltip) center, start, or end aligned.
|
||||||
|
*
|
||||||
|
* @param text The text to be shown in the tooltip.
|
||||||
|
* @param gravity The gravity aligns the tooltip center, start, or end.
|
||||||
|
* @param arrowMarginStart The margin from start to place arrow (ignored if center)
|
||||||
|
* @param top The Y coordinate of the bottom of tooltip.
|
||||||
|
* @return The tooltip.
|
||||||
|
*/
|
||||||
|
public ArrowTipView show(String text, int gravity, int arrowMarginStart, int top) {
|
||||||
((TextView) findViewById(R.id.text)).setText(text);
|
((TextView) findViewById(R.id.text)).setText(text);
|
||||||
mActivity.getDragLayer().addView(this);
|
ViewGroup parent = mActivity.getDragLayer();
|
||||||
|
parent.addView(this);
|
||||||
|
|
||||||
DragLayer.LayoutParams params = (DragLayer.LayoutParams) getLayoutParams();
|
DragLayer.LayoutParams params = (DragLayer.LayoutParams) getLayoutParams();
|
||||||
params.gravity = Gravity.CENTER_HORIZONTAL;
|
params.gravity = gravity;
|
||||||
|
LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) findViewById(
|
||||||
|
R.id.arrow).getLayoutParams();
|
||||||
|
lp.gravity = gravity;
|
||||||
|
if (gravity == Gravity.END) {
|
||||||
|
lp.setMarginEnd(parent.getMeasuredWidth() - arrowMarginStart);
|
||||||
|
} else if (gravity == Gravity.START) {
|
||||||
|
lp.setMarginStart(arrowMarginStart);
|
||||||
|
}
|
||||||
|
requestLayout();
|
||||||
|
|
||||||
params.leftMargin = mActivity.getDeviceProfile().workspacePadding.left;
|
params.leftMargin = mActivity.getDeviceProfile().workspacePadding.left;
|
||||||
params.rightMargin = mActivity.getDeviceProfile().workspacePadding.right;
|
params.rightMargin = mActivity.getDeviceProfile().workspacePadding.right;
|
||||||
post(() -> setY(top - getHeight()));
|
post(() -> setY(top - getHeight()));
|
||||||
|
|||||||
@@ -90,13 +90,23 @@ public abstract class BaseDragLayer<T extends Context & ActivityContext>
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Touch is being dispatched through the normal view dispatch system
|
// Touch coming from normal view system is being dispatched.
|
||||||
private static final int TOUCH_DISPATCHING_VIEW = 1 << 0;
|
private static final int TOUCH_DISPATCHING_FROM_VIEW = 1 << 0;
|
||||||
// Touch is being dispatched through the normal view dispatch system, and started at the
|
// Touch is being dispatched through the normal view dispatch system, and started at the
|
||||||
// system gesture region
|
// system gesture region. In this case we prevent internal gesture handling and only allow
|
||||||
private static final int TOUCH_DISPATCHING_GESTURE = 1 << 1;
|
// normal view event handling.
|
||||||
// Touch is being dispatched through a proxy from InputMonitor
|
private static final int TOUCH_DISPATCHING_FROM_VIEW_GESTURE_REGION = 1 << 1;
|
||||||
private static final int TOUCH_DISPATCHING_PROXY = 1 << 2;
|
// Touch coming from InputMonitor proxy is being dispatched 'only to gestures'. Note that both
|
||||||
|
// this and view-system can be active at the same time where view-system would go to the views,
|
||||||
|
// and this would go to the gestures.
|
||||||
|
// Note that this is not set when events are coming from proxy, but going through full dispatch
|
||||||
|
// process (both views and gestures) to allow view-system to easily take over in case it
|
||||||
|
// comes later.
|
||||||
|
private static final int TOUCH_DISPATCHING_FROM_PROXY = 1 << 2;
|
||||||
|
// ACTION_DOWN has been dispatched to child views and ACTION_UP or ACTION_CANCEL is pending.
|
||||||
|
// Note that the event source can either be view-dispatching or proxy-dispatching based on if
|
||||||
|
// TOUCH_DISPATCHING_VIEW is present or not.
|
||||||
|
private static final int TOUCH_DISPATCHING_TO_VIEW_IN_PROGRESS = 1 << 3;
|
||||||
|
|
||||||
protected final float[] mTmpXY = new float[2];
|
protected final float[] mTmpXY = new float[2];
|
||||||
protected final float[] mTmpRectPoints = new float[4];
|
protected final float[] mTmpRectPoints = new float[4];
|
||||||
@@ -204,7 +214,8 @@ public abstract class BaseDragLayer<T extends Context & ActivityContext>
|
|||||||
|
|
||||||
protected boolean findActiveController(MotionEvent ev) {
|
protected boolean findActiveController(MotionEvent ev) {
|
||||||
mActiveController = null;
|
mActiveController = null;
|
||||||
if ((mTouchDispatchState & (TOUCH_DISPATCHING_GESTURE | TOUCH_DISPATCHING_PROXY)) == 0) {
|
if ((mTouchDispatchState & (TOUCH_DISPATCHING_FROM_VIEW_GESTURE_REGION
|
||||||
|
| TOUCH_DISPATCHING_FROM_PROXY)) == 0) {
|
||||||
// Only look for controllers if we are not dispatching from gesture area and proxy is
|
// Only look for controllers if we are not dispatching from gesture area and proxy is
|
||||||
// not active
|
// not active
|
||||||
mActiveController = findControllerToHandleTouch(ev);
|
mActiveController = findControllerToHandleTouch(ev);
|
||||||
@@ -283,19 +294,28 @@ public abstract class BaseDragLayer<T extends Context & ActivityContext>
|
|||||||
public boolean dispatchTouchEvent(MotionEvent ev) {
|
public boolean dispatchTouchEvent(MotionEvent ev) {
|
||||||
switch (ev.getAction()) {
|
switch (ev.getAction()) {
|
||||||
case ACTION_DOWN: {
|
case ACTION_DOWN: {
|
||||||
mTouchDispatchState |= TOUCH_DISPATCHING_VIEW;
|
if ((mTouchDispatchState & TOUCH_DISPATCHING_TO_VIEW_IN_PROGRESS) != 0) {
|
||||||
|
// Cancel the previous touch
|
||||||
|
int action = ev.getAction();
|
||||||
|
ev.setAction(ACTION_CANCEL);
|
||||||
|
super.dispatchTouchEvent(ev);
|
||||||
|
ev.setAction(action);
|
||||||
|
}
|
||||||
|
mTouchDispatchState |= TOUCH_DISPATCHING_FROM_VIEW
|
||||||
|
| TOUCH_DISPATCHING_TO_VIEW_IN_PROGRESS;
|
||||||
|
|
||||||
if (isEventInLauncher(ev)) {
|
if (isEventInLauncher(ev)) {
|
||||||
mTouchDispatchState &= ~TOUCH_DISPATCHING_GESTURE;
|
mTouchDispatchState &= ~TOUCH_DISPATCHING_FROM_VIEW_GESTURE_REGION;
|
||||||
} else {
|
} else {
|
||||||
mTouchDispatchState |= TOUCH_DISPATCHING_GESTURE;
|
mTouchDispatchState |= TOUCH_DISPATCHING_FROM_VIEW_GESTURE_REGION;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ACTION_CANCEL:
|
case ACTION_CANCEL:
|
||||||
case ACTION_UP:
|
case ACTION_UP:
|
||||||
mTouchDispatchState &= ~TOUCH_DISPATCHING_GESTURE;
|
mTouchDispatchState &= ~TOUCH_DISPATCHING_FROM_VIEW_GESTURE_REGION;
|
||||||
mTouchDispatchState &= ~TOUCH_DISPATCHING_VIEW;
|
mTouchDispatchState &= ~TOUCH_DISPATCHING_FROM_VIEW;
|
||||||
|
mTouchDispatchState &= ~TOUCH_DISPATCHING_TO_VIEW_IN_PROGRESS;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
super.dispatchTouchEvent(ev);
|
super.dispatchTouchEvent(ev);
|
||||||
@@ -304,44 +324,54 @@ public abstract class BaseDragLayer<T extends Context & ActivityContext>
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Called before we are about to receive proxy events.
|
|
||||||
*
|
|
||||||
* @return false if we can't handle proxy at this time
|
|
||||||
*/
|
|
||||||
public boolean prepareProxyEventStarting() {
|
|
||||||
mProxyTouchController = null;
|
|
||||||
if ((mTouchDispatchState & TOUCH_DISPATCHING_VIEW) != 0 && mActiveController != null) {
|
|
||||||
// We are already dispatching using view system and have an active controller, we can't
|
|
||||||
// handle another controller.
|
|
||||||
|
|
||||||
// This flag was already cleared in proxy ACTION_UP or ACTION_CANCEL. Added here just
|
|
||||||
// to be safe
|
|
||||||
mTouchDispatchState &= ~TOUCH_DISPATCHING_PROXY;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
mTouchDispatchState |= TOUCH_DISPATCHING_PROXY;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Proxies the touch events to the gesture handlers
|
* Proxies the touch events to the gesture handlers
|
||||||
*/
|
*/
|
||||||
public boolean proxyTouchEvent(MotionEvent ev) {
|
public boolean proxyTouchEvent(MotionEvent ev, boolean allowViewDispatch) {
|
||||||
boolean handled;
|
int actionMasked = ev.getActionMasked();
|
||||||
if (mProxyTouchController != null) {
|
boolean isViewDispatching = (mTouchDispatchState & TOUCH_DISPATCHING_FROM_VIEW) != 0;
|
||||||
handled = mProxyTouchController.onControllerTouchEvent(ev);
|
|
||||||
|
// Only do view dispatch if another view-dispatching is not running, or we already started
|
||||||
|
// proxy-dispatching before. Note that view-dispatching can always take over the proxy
|
||||||
|
// dispatching at anytime, but not vice-versa.
|
||||||
|
allowViewDispatch = allowViewDispatch && !isViewDispatching
|
||||||
|
&& (actionMasked == ACTION_DOWN
|
||||||
|
|| ((mTouchDispatchState & TOUCH_DISPATCHING_TO_VIEW_IN_PROGRESS) != 0));
|
||||||
|
|
||||||
|
if (allowViewDispatch) {
|
||||||
|
mTouchDispatchState |= TOUCH_DISPATCHING_TO_VIEW_IN_PROGRESS;
|
||||||
|
super.dispatchTouchEvent(ev);
|
||||||
|
|
||||||
|
if (actionMasked == ACTION_UP || actionMasked == ACTION_CANCEL) {
|
||||||
|
mTouchDispatchState &= ~TOUCH_DISPATCHING_TO_VIEW_IN_PROGRESS;
|
||||||
|
mTouchDispatchState &= ~TOUCH_DISPATCHING_FROM_PROXY;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
} else {
|
} else {
|
||||||
mProxyTouchController = findControllerToHandleTouch(ev);
|
boolean handled;
|
||||||
handled = mProxyTouchController != null;
|
if (mProxyTouchController != null) {
|
||||||
|
handled = mProxyTouchController.onControllerTouchEvent(ev);
|
||||||
|
} else {
|
||||||
|
if (actionMasked == ACTION_DOWN) {
|
||||||
|
if (isViewDispatching && mActiveController != null) {
|
||||||
|
// A controller is already active, we can't initiate our own controller
|
||||||
|
mTouchDispatchState &= ~TOUCH_DISPATCHING_FROM_PROXY;
|
||||||
|
} else {
|
||||||
|
// We will control the handler via proxy
|
||||||
|
mTouchDispatchState |= TOUCH_DISPATCHING_FROM_PROXY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((mTouchDispatchState & TOUCH_DISPATCHING_FROM_PROXY) != 0) {
|
||||||
|
mProxyTouchController = findControllerToHandleTouch(ev);
|
||||||
|
}
|
||||||
|
handled = mProxyTouchController != null;
|
||||||
|
}
|
||||||
|
if (actionMasked == ACTION_UP || actionMasked == ACTION_CANCEL) {
|
||||||
|
mProxyTouchController = null;
|
||||||
|
mTouchDispatchState &= ~TOUCH_DISPATCHING_FROM_PROXY;
|
||||||
|
}
|
||||||
|
return handled;
|
||||||
}
|
}
|
||||||
int action = ev.getAction();
|
|
||||||
if (action == ACTION_UP || action == ACTION_CANCEL) {
|
|
||||||
mProxyTouchController = null;
|
|
||||||
mTouchDispatchState &= ~TOUCH_DISPATCHING_PROXY;
|
|
||||||
}
|
|
||||||
return handled;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import static com.android.launcher3.anim.Interpolators.DEACCEL;
|
|||||||
import static com.android.launcher3.anim.Interpolators.LINEAR;
|
import static com.android.launcher3.anim.Interpolators.LINEAR;
|
||||||
import static com.android.launcher3.anim.Interpolators.clampToProgress;
|
import static com.android.launcher3.anim.Interpolators.clampToProgress;
|
||||||
import static com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound;
|
import static com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound;
|
||||||
|
import static com.android.launcher3.util.SystemUiController.UI_STATE_SCRIM_VIEW;
|
||||||
|
|
||||||
import android.animation.Animator;
|
import android.animation.Animator;
|
||||||
import android.animation.AnimatorListenerAdapter;
|
import android.animation.AnimatorListenerAdapter;
|
||||||
@@ -53,6 +54,7 @@ import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeL
|
|||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.core.graphics.ColorUtils;
|
||||||
import androidx.core.view.ViewCompat;
|
import androidx.core.view.ViewCompat;
|
||||||
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
|
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
|
||||||
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat;
|
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat;
|
||||||
@@ -77,7 +79,6 @@ import com.android.launcher3.widget.WidgetsFullSheet;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simple scrim which draws a flat color
|
* Simple scrim which draws a flat color
|
||||||
*/
|
*/
|
||||||
@@ -115,6 +116,7 @@ public class ScrimView<T extends Launcher> extends View implements Insettable, O
|
|||||||
private final WallpaperColorInfo mWallpaperColorInfo;
|
private final WallpaperColorInfo mWallpaperColorInfo;
|
||||||
private final AccessibilityManager mAM;
|
private final AccessibilityManager mAM;
|
||||||
protected final int mEndScrim;
|
protected final int mEndScrim;
|
||||||
|
protected final boolean mIsScrimDark;
|
||||||
|
|
||||||
private final StateListener<LauncherState> mAccessibilityLauncherStateListener =
|
private final StateListener<LauncherState> mAccessibilityLauncherStateListener =
|
||||||
new StateListener<LauncherState>() {
|
new StateListener<LauncherState>() {
|
||||||
@@ -156,6 +158,7 @@ public class ScrimView<T extends Launcher> extends View implements Insettable, O
|
|||||||
mLauncher = Launcher.cast(Launcher.getLauncher(context));
|
mLauncher = Launcher.cast(Launcher.getLauncher(context));
|
||||||
mWallpaperColorInfo = WallpaperColorInfo.INSTANCE.get(context);
|
mWallpaperColorInfo = WallpaperColorInfo.INSTANCE.get(context);
|
||||||
mEndScrim = Themes.getAttrColor(context, R.attr.allAppsScrimColor);
|
mEndScrim = Themes.getAttrColor(context, R.attr.allAppsScrimColor);
|
||||||
|
mIsScrimDark = ColorUtils.calculateLuminance(mEndScrim) < 0.5f;
|
||||||
|
|
||||||
mMaxScrimAlpha = 0.7f;
|
mMaxScrimAlpha = 0.7f;
|
||||||
|
|
||||||
@@ -233,6 +236,7 @@ public class ScrimView<T extends Launcher> extends View implements Insettable, O
|
|||||||
mProgress = progress;
|
mProgress = progress;
|
||||||
stopDragHandleEducationAnim();
|
stopDragHandleEducationAnim();
|
||||||
updateColors();
|
updateColors();
|
||||||
|
updateSysUiColors();
|
||||||
updateDragHandleAlpha();
|
updateDragHandleAlpha();
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
@@ -245,6 +249,17 @@ public class ScrimView<T extends Launcher> extends View implements Insettable, O
|
|||||||
mEndFlatColor, Math.round((1 - mProgress) * mEndFlatColorAlpha));
|
mEndFlatColor, Math.round((1 - mProgress) * mEndFlatColorAlpha));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void updateSysUiColors() {
|
||||||
|
// Use a light system UI (dark icons) if all apps is behind at least half of the
|
||||||
|
// status bar.
|
||||||
|
boolean forceChange = mProgress <= 0.1f;
|
||||||
|
if (forceChange) {
|
||||||
|
mLauncher.getSystemUiController().updateUiState(UI_STATE_SCRIM_VIEW, !mIsScrimDark);
|
||||||
|
} else {
|
||||||
|
mLauncher.getSystemUiController().updateUiState(UI_STATE_SCRIM_VIEW, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected void updateDragHandleAlpha() {
|
protected void updateDragHandleAlpha() {
|
||||||
if (mDragHandle != null) {
|
if (mDragHandle != null) {
|
||||||
mDragHandle.setAlpha(mDragHandleAlpha);
|
mDragHandle.setAlpha(mDragHandleAlpha);
|
||||||
|
|||||||
Reference in New Issue
Block a user