Merging from ub-launcher3-master @ build 6356169
Bug:150504032 Test: manual, presubmit on the source branch x20/teams/android-launcher/merge/ub-launcher3-master_6356169.html Change-Id: Ife6c578d9a1e212eccdf3cf9a0cd838132eb90f5
This commit is contained in:
@@ -137,14 +137,6 @@
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<!--
|
||||
Should point to the content provider which can be used to dump Launcher3 compatible
|
||||
worspace configuration to the dump's file descriptor by using launcher_dump.proto
|
||||
-->
|
||||
<meta-data
|
||||
android:name="com.android.launcher3.launcher_dump_provider"
|
||||
android:value="com.android.launcher3.LauncherProvider" />
|
||||
|
||||
<!--
|
||||
The settings provider contains Home's data, like the workspace favorites. The permissions
|
||||
should be changed to what is defined above. The authorities should also be changed to
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
syntax = "proto2";
|
||||
|
||||
option java_package = "com.android.launcher3.logger";
|
||||
option java_outer_classname = "LauncherAtom";
|
||||
|
||||
//
|
||||
// ItemInfos
|
||||
message ItemInfo {
|
||||
oneof Item {
|
||||
Application application = 1;
|
||||
Task task= 2;
|
||||
Shortcut shortcut = 3;
|
||||
Widget widget = 4;
|
||||
}
|
||||
// When used for launch event, stores the global predictive rank
|
||||
optional int32 rank = 5;
|
||||
|
||||
// Stores whether the Item belows to non primary user
|
||||
optional bool is_work = 6;
|
||||
|
||||
// Item can be child node to parent container or parent containers (nested)
|
||||
oneof Container {
|
||||
WorkspaceContainer workspace = 7;
|
||||
HotseatContainer hotseat = 8;
|
||||
FolderContainer folder = 9;
|
||||
}
|
||||
// Stores the origin of the Item
|
||||
optional Origin source = 10;
|
||||
}
|
||||
|
||||
enum Origin {
|
||||
UNKNOWN = 0;
|
||||
DEFAULT_LAYOUT = 1; // icon automatically placed in workspace, folder, hotseat
|
||||
BACKUP_RESTORE = 2; // icon layout restored from backup
|
||||
PINITEM = 3; // from another app (e.g., Chrome's "Add to Home screen")
|
||||
ALLAPPS_ATOZ = 4; // within launcher surface, all aps a-z
|
||||
WIDGETS = 5; // within launcher, widgets tray
|
||||
ADD_TO_HOMESCREEN = 6; // play install + launcher home setting
|
||||
ALLAPPS_PREDICTION = 7; // from prediction bar in all apps container
|
||||
HOTSEAT_PREDICTION = 8; // from prediction bar in hotseat container
|
||||
}
|
||||
|
||||
// Main app icons
|
||||
message Application {
|
||||
optional string package_name = 1;
|
||||
optional string component_name = 2;
|
||||
}
|
||||
|
||||
// Legacy shortcuts and shortcuts handled by ShortcutManager
|
||||
message Shortcut {
|
||||
optional string shortcut_name = 1;
|
||||
}
|
||||
|
||||
// AppWidgets handled by AppWidgetManager
|
||||
message Widget {
|
||||
optional int32 span_x = 1;
|
||||
optional int32 span_y = 2;
|
||||
optional int32 app_widget_id = 3;
|
||||
optional string package_name = 4; // only populated during snapshot if from workspace
|
||||
optional string component_name = 5; // only populated during snapshot if from workspace
|
||||
}
|
||||
|
||||
// Tasks handled by PackageManager
|
||||
message Task {
|
||||
optional string package_name = 1;
|
||||
optional string component_name = 2;
|
||||
optional int32 index = 3;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////
|
||||
// Containers
|
||||
|
||||
message WorkspaceContainer {
|
||||
optional int32 page_index = 1; // range [-1, l], 0 is the index of the main homescreen
|
||||
optional int32 grid_x = 2; // [0, m], m varies based on the display density and resolution
|
||||
optional int32 grid_y = 3; // [0, n], n varies based on the display density and resolution
|
||||
}
|
||||
|
||||
message HotseatContainer {
|
||||
optional int32 index = 1;
|
||||
}
|
||||
|
||||
message FolderContainer {
|
||||
optional int32 page_index = 1;
|
||||
optional int32 grid_x = 2;
|
||||
optional int32 grid_y = 3;
|
||||
oneof Container {
|
||||
WorkspaceContainer workspace = 4;
|
||||
HotseatContainer hotseat = 5;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2017 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.
|
||||
*/
|
||||
syntax = "proto2";
|
||||
|
||||
option java_package = "com.android.launcher3.model";
|
||||
option java_outer_classname = "LauncherDumpProto";
|
||||
|
||||
package model;
|
||||
|
||||
message DumpTarget {
|
||||
enum Type {
|
||||
NONE = 0;
|
||||
ITEM = 1;
|
||||
CONTAINER = 2;
|
||||
}
|
||||
|
||||
optional Type type = 1;
|
||||
optional int32 page_id = 2;
|
||||
optional int32 grid_x = 3;
|
||||
optional int32 grid_y = 4;
|
||||
|
||||
// For container types only
|
||||
optional ContainerType container_type = 5;
|
||||
|
||||
// For item types only
|
||||
optional ItemType item_type = 6;
|
||||
|
||||
optional string package_name = 7; // All ItemTypes except UNKNOWN type
|
||||
optional string component = 8; // All ItemTypes except UNKNOWN type
|
||||
optional string item_id = 9; // For Pinned Shortcuts and appWidgetId
|
||||
|
||||
optional int32 span_x = 10 [default = 1];// Used for ItemType.WIDGET
|
||||
optional int32 span_y = 11 [default = 1];// Used for ItemType.WIDGET
|
||||
optional UserType user_type = 12;
|
||||
}
|
||||
|
||||
// Used to define what type of item a Target would represent.
|
||||
enum ItemType {
|
||||
UNKNOWN_ITEMTYPE = 0; // Launcher specific items
|
||||
APP_ICON = 1; // Regular app icons
|
||||
WIDGET = 2; // Elements from AppWidgetManager
|
||||
SHORTCUT = 3; // ShortcutManager
|
||||
}
|
||||
|
||||
// Used to define what type of container a Target would represent.
|
||||
enum ContainerType {
|
||||
UNKNOWN_CONTAINERTYPE = 0;
|
||||
WORKSPACE = 1;
|
||||
HOTSEAT = 2;
|
||||
FOLDER = 3;
|
||||
}
|
||||
|
||||
// Used to define what type of control a Target would represent.
|
||||
enum UserType {
|
||||
DEFAULT = 0;
|
||||
WORK = 1;
|
||||
}
|
||||
|
||||
// Main message;
|
||||
message LauncherImpression {
|
||||
repeated DumpTarget targets = 1;
|
||||
}
|
||||
@@ -73,6 +73,17 @@
|
||||
</intent-filter>
|
||||
</provider>
|
||||
|
||||
<!-- FileProvider used for sharing images. -->
|
||||
<provider
|
||||
android:name="androidx.core.content.FileProvider"
|
||||
android:authorities="${packageName}.overview.fileprovider"
|
||||
android:exported="false"
|
||||
android:grantUriPermissions="true">
|
||||
<meta-data
|
||||
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||
android:resource="@xml/overview_file_provider_paths" />
|
||||
</provider>
|
||||
|
||||
<service
|
||||
android:name="com.android.launcher3.uioverrides.dynamicui.WallpaperManagerCompatVL$ColorExtractionService"
|
||||
tools:node="remove" />
|
||||
|
||||
@@ -31,9 +31,6 @@
|
||||
<dimen name="all_apps_label_top_padding">16dp</dimen>
|
||||
<dimen name="all_apps_label_bottom_padding">8dp</dimen>
|
||||
<dimen name="all_apps_label_text_size">14sp</dimen>
|
||||
<dimen name="all_apps_tip_bottom_margin">8dp</dimen>
|
||||
<!-- The size of corner radius of the arrow in the arrow toast. -->
|
||||
<dimen name="arrow_toast_corner_radius">2dp</dimen>
|
||||
|
||||
<!-- Minimum distance to swipe to trigger accessibility gesture -->
|
||||
<dimen name="accessibility_gesture_min_swipe_distance">80dp</dimen>
|
||||
|
||||
+1
-1
@@ -24,13 +24,13 @@ import static com.android.quickstep.logging.UserEventDispatcherExtension.ALL_APP
|
||||
import android.os.UserManager;
|
||||
|
||||
import com.android.launcher3.AbstractFloatingView;
|
||||
import com.android.launcher3.ArrowTipView;
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.LauncherState;
|
||||
import com.android.launcher3.LauncherStateManager;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.allapps.FloatingHeaderView;
|
||||
import com.android.launcher3.views.ArrowTipView;
|
||||
import com.android.systemui.shared.system.LauncherEventUtil;
|
||||
|
||||
/**
|
||||
|
||||
+1
-1
@@ -26,7 +26,6 @@ import android.view.View;
|
||||
|
||||
import androidx.core.app.NotificationCompat;
|
||||
|
||||
import com.android.launcher3.ArrowTipView;
|
||||
import com.android.launcher3.CellLayout;
|
||||
import com.android.launcher3.FolderInfo;
|
||||
import com.android.launcher3.Hotseat;
|
||||
@@ -43,6 +42,7 @@ import com.android.launcher3.util.ActivityTracker;
|
||||
import com.android.launcher3.util.GridOccupancy;
|
||||
import com.android.launcher3.util.IntArray;
|
||||
import com.android.launcher3.util.Themes;
|
||||
import com.android.launcher3.views.ArrowTipView;
|
||||
import com.android.launcher3.views.Snackbar;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
|
||||
+19
-8
@@ -15,18 +15,22 @@
|
||||
*/
|
||||
package com.android.launcher3.uioverrides;
|
||||
|
||||
import static com.android.launcher3.LauncherState.RECENTS_CLEAR_ALL_BUTTON;
|
||||
import static com.android.launcher3.LauncherState.OVERVIEW_BUTTONS;
|
||||
import static com.android.launcher3.anim.Interpolators.AGGRESSIVE_EASE_IN_OUT;
|
||||
import static com.android.launcher3.anim.Interpolators.LINEAR;
|
||||
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_FADE;
|
||||
import static com.android.quickstep.views.RecentsView.CONTENT_ALPHA;
|
||||
import static com.android.quickstep.views.RecentsView.FULLSCREEN_PROGRESS;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.os.Build;
|
||||
import android.util.FloatProperty;
|
||||
import android.view.View;
|
||||
import android.view.animation.Interpolator;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.BaseQuickstepLauncher;
|
||||
import com.android.launcher3.LauncherState;
|
||||
import com.android.launcher3.anim.AnimationSuccessListener;
|
||||
import com.android.launcher3.anim.PendingAnimation;
|
||||
@@ -44,7 +48,7 @@ import com.android.quickstep.views.RecentsView;
|
||||
public final class RecentsViewStateController extends
|
||||
BaseRecentsViewStateController<LauncherRecentsView> {
|
||||
|
||||
public RecentsViewStateController(Launcher launcher) {
|
||||
public RecentsViewStateController(BaseQuickstepLauncher launcher) {
|
||||
super(launcher);
|
||||
}
|
||||
|
||||
@@ -55,7 +59,7 @@ public final class RecentsViewStateController extends
|
||||
mRecentsView.updateEmptyMessage();
|
||||
mRecentsView.resetTaskVisuals();
|
||||
}
|
||||
setAlphas(PropertySetter.NO_ANIM_PROPERTY_SETTER, state.getVisibleElements(mLauncher));
|
||||
setAlphas(PropertySetter.NO_ANIM_PROPERTY_SETTER, state, LINEAR);
|
||||
mRecentsView.setFullscreenProgress(state.getOverviewFullscreenProgress());
|
||||
}
|
||||
|
||||
@@ -73,15 +77,22 @@ public final class RecentsViewStateController extends
|
||||
AnimationSuccessListener.forRunnable(mRecentsView::resetTaskVisuals));
|
||||
}
|
||||
|
||||
setAlphas(builder, toState.getVisibleElements(mLauncher));
|
||||
setAlphas(builder, toState,
|
||||
config.getInterpolator(ANIM_OVERVIEW_FADE, AGGRESSIVE_EASE_IN_OUT));
|
||||
builder.setFloat(mRecentsView, FULLSCREEN_PROGRESS,
|
||||
toState.getOverviewFullscreenProgress(), LINEAR);
|
||||
}
|
||||
|
||||
private void setAlphas(PropertySetter propertySetter, int visibleElements) {
|
||||
boolean hasClearAllButton = (visibleElements & RECENTS_CLEAR_ALL_BUTTON) != 0;
|
||||
private void setAlphas(PropertySetter propertySetter, LauncherState state,
|
||||
Interpolator actionInterpolator) {
|
||||
float buttonAlpha = (state.getVisibleElements(mLauncher) & OVERVIEW_BUTTONS) != 0 ? 1 : 0;
|
||||
propertySetter.setFloat(mRecentsView.getClearAllButton(), ClearAllButton.VISIBILITY_ALPHA,
|
||||
hasClearAllButton ? 1f : 0f, LINEAR);
|
||||
buttonAlpha, LINEAR);
|
||||
|
||||
View actionsView = mLauncher.getActionsView();
|
||||
if (actionsView != null) {
|
||||
propertySetter.setViewAlpha(actionsView, buttonAlpha, actionInterpolator);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+1
-1
@@ -90,7 +90,7 @@ public class BackgroundAppState extends OverviewState {
|
||||
@Override
|
||||
public int getVisibleElements(Launcher launcher) {
|
||||
return super.getVisibleElements(launcher)
|
||||
& ~RECENTS_CLEAR_ALL_BUTTON & ~VERTICAL_SWIPE_INDICATOR;
|
||||
& ~OVERVIEW_BUTTONS & ~VERTICAL_SWIPE_INDICATOR;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+4
@@ -25,6 +25,7 @@ import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TR
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.LauncherState;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.states.StateAnimationConfig;
|
||||
|
||||
public class OverviewPeekState extends OverviewState {
|
||||
@@ -37,6 +38,9 @@ public class OverviewPeekState extends OverviewState {
|
||||
ScaleAndTranslation result = super.getOverviewScaleAndTranslation(launcher);
|
||||
result.translationX = NORMAL.getOverviewScaleAndTranslation(launcher).translationX
|
||||
- launcher.getResources().getDimension(R.dimen.overview_peek_distance);
|
||||
if (Utilities.isRtl(launcher.getResources())) {
|
||||
result.translationX = -result.translationX;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
+6
-8
@@ -164,17 +164,15 @@ public class OverviewState extends LauncherState {
|
||||
|
||||
@Override
|
||||
public int getVisibleElements(Launcher launcher) {
|
||||
if (launcher.getDeviceProfile().isVerticalBarLayout()) {
|
||||
return VERTICAL_SWIPE_INDICATOR | RECENTS_CLEAR_ALL_BUTTON;
|
||||
if (ENABLE_OVERVIEW_ACTIONS.get() && removeShelfFromOverview(launcher)) {
|
||||
return OVERVIEW_BUTTONS;
|
||||
} else if (launcher.getDeviceProfile().isVerticalBarLayout()) {
|
||||
return VERTICAL_SWIPE_INDICATOR | OVERVIEW_BUTTONS;
|
||||
} else {
|
||||
if (ENABLE_OVERVIEW_ACTIONS.get() && removeShelfFromOverview(launcher)) {
|
||||
return VERTICAL_SWIPE_INDICATOR | RECENTS_CLEAR_ALL_BUTTON;
|
||||
}
|
||||
|
||||
boolean hasAllAppsHeaderExtra = launcher.getAppsView() != null
|
||||
&& launcher.getAppsView().getFloatingHeaderView().hasVisibleContent();
|
||||
return HOTSEAT_SEARCH_BOX | VERTICAL_SWIPE_INDICATOR | RECENTS_CLEAR_ALL_BUTTON |
|
||||
(hasAllAppsHeaderExtra ? ALL_APPS_HEADER_EXTRA : HOTSEAT_ICONS);
|
||||
return HOTSEAT_SEARCH_BOX | VERTICAL_SWIPE_INDICATOR | OVERVIEW_BUTTONS
|
||||
| (hasAllAppsHeaderExtra ? ALL_APPS_HEADER_EXTRA : HOTSEAT_ICONS);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+5
-1
@@ -73,7 +73,11 @@ public class FlingAndHoldTouchController extends PortraitStatesTouchController {
|
||||
super(l, false /* allowDragToOverview */);
|
||||
mMotionPauseDetector = new MotionPauseDetector(l);
|
||||
mMotionPauseMinDisplacement = ViewConfiguration.get(l).getScaledTouchSlop();
|
||||
mMotionPauseMaxDisplacement = getShiftRange() * MAX_DISPLACEMENT_PERCENT;
|
||||
mMotionPauseMaxDisplacement = getMotionPauseMaxDisplacement();
|
||||
}
|
||||
|
||||
protected float getMotionPauseMaxDisplacement() {
|
||||
return getShiftRange() * MAX_DISPLACEMENT_PERCENT;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+7
@@ -65,6 +65,13 @@ public class NoButtonNavbarToOverviewTouchController extends FlingAndHoldTouchCo
|
||||
mRecentsView = l.getOverviewPanel();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected float getMotionPauseMaxDisplacement() {
|
||||
// No need to disallow pause when swiping up all the way up the screen (unlike
|
||||
// FlingAndHoldTouchController where user is probably intending to go to all apps).
|
||||
return Float.MAX_VALUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean canInterceptTouch(MotionEvent ev) {
|
||||
mDidTouchStartInNavBar = (ev.getEdgeFlags() & EDGE_NAV_BAR) != 0;
|
||||
|
||||
+10
-25
@@ -19,7 +19,7 @@ import static com.android.launcher3.LauncherState.BACKGROUND_APP;
|
||||
import static com.android.launcher3.LauncherState.OVERVIEW;
|
||||
import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
|
||||
import static com.android.launcher3.anim.Interpolators.TOUCH_RESPONSE_INTERPOLATOR;
|
||||
import static com.android.launcher3.uioverrides.DepthController.DEPTH;
|
||||
import static com.android.launcher3.statehandlers.DepthController.DEPTH;
|
||||
import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING;
|
||||
import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_OPENING;
|
||||
|
||||
@@ -34,7 +34,7 @@ import android.view.View;
|
||||
import com.android.launcher3.AbstractFloatingView;
|
||||
import com.android.launcher3.BaseDraggingActivity;
|
||||
import com.android.launcher3.anim.AnimationSuccessListener;
|
||||
import com.android.launcher3.uioverrides.DepthController;
|
||||
import com.android.launcher3.statehandlers.DepthController;
|
||||
import com.android.quickstep.util.AppWindowAnimationHelper;
|
||||
import com.android.quickstep.util.AppWindowAnimationHelper.TransformParams;
|
||||
import com.android.quickstep.util.RemoteAnimationProvider;
|
||||
@@ -105,12 +105,6 @@ final class AppToOverviewAnimationProvider<T extends BaseDraggingActivity> exten
|
||||
mRecentsView.setRunningTaskIconScaledDown(true);
|
||||
}
|
||||
|
||||
DepthController depthController = mActivityInterface.getDepthController();
|
||||
if (depthController != null) {
|
||||
// Update the surface to be the lowest closing app surface
|
||||
depthController.setSurfaceToLauncher(mRecentsView);
|
||||
}
|
||||
|
||||
AnimatorSet anim = new AnimatorSet();
|
||||
anim.addListener(new AnimationSuccessListener() {
|
||||
@Override
|
||||
@@ -123,11 +117,17 @@ final class AppToOverviewAnimationProvider<T extends BaseDraggingActivity> exten
|
||||
});
|
||||
if (mActivity == null) {
|
||||
Log.e(TAG, "Animation created, before activity");
|
||||
anim.play(ValueAnimator.ofInt(0, 1).setDuration(RECENTS_LAUNCH_DURATION))
|
||||
.with(createDepthAnimator(depthController));
|
||||
return anim;
|
||||
}
|
||||
|
||||
DepthController depthController = mActivityInterface.getDepthController();
|
||||
if (depthController != null) {
|
||||
anim.play(ObjectAnimator.ofFloat(depthController, DEPTH,
|
||||
BACKGROUND_APP.getDepth(mActivity),
|
||||
OVERVIEW.getDepth(mActivity))
|
||||
.setDuration(RECENTS_LAUNCH_DURATION));
|
||||
}
|
||||
|
||||
RemoteAnimationTargets targets = new RemoteAnimationTargets(appTargets,
|
||||
wallpaperTargets, MODE_CLOSING);
|
||||
|
||||
@@ -135,8 +135,6 @@ final class AppToOverviewAnimationProvider<T extends BaseDraggingActivity> exten
|
||||
RemoteAnimationTargetCompat runningTaskTarget = targets.findTask(mTargetTaskId);
|
||||
if (runningTaskTarget == null) {
|
||||
Log.e(TAG, "No closing app");
|
||||
anim.play(ValueAnimator.ofInt(0, 1).setDuration(RECENTS_LAUNCH_DURATION))
|
||||
.with(createDepthAnimator(depthController));
|
||||
return anim;
|
||||
}
|
||||
|
||||
@@ -183,8 +181,6 @@ final class AppToOverviewAnimationProvider<T extends BaseDraggingActivity> exten
|
||||
transaction.apply();
|
||||
});
|
||||
}
|
||||
anim.play(valueAnimator)
|
||||
.with(createDepthAnimator(depthController));
|
||||
return anim;
|
||||
}
|
||||
|
||||
@@ -196,15 +192,4 @@ final class AppToOverviewAnimationProvider<T extends BaseDraggingActivity> exten
|
||||
long getRecentsLaunchDuration() {
|
||||
return RECENTS_LAUNCH_DURATION;
|
||||
}
|
||||
|
||||
private Animator createDepthAnimator(DepthController depthController) {
|
||||
if (depthController == null) {
|
||||
// Dummy animation
|
||||
return ValueAnimator.ofInt(0);
|
||||
}
|
||||
return ObjectAnimator.ofFloat(depthController, DEPTH,
|
||||
BACKGROUND_APP.getDepth(mActivity),
|
||||
OVERVIEW.getDepth(mActivity))
|
||||
.setDuration(RECENTS_LAUNCH_DURATION);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ import android.graphics.PointF;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.os.Build;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
@@ -48,6 +49,7 @@ import com.android.launcher3.anim.AnimatorPlaybackController;
|
||||
import com.android.launcher3.graphics.RotationMode;
|
||||
import com.android.launcher3.model.PagedViewOrientedState;
|
||||
import com.android.launcher3.states.RotationHelper;
|
||||
import com.android.launcher3.testing.TestProtocol;
|
||||
import com.android.launcher3.touch.PagedOrientationHandler;
|
||||
import com.android.launcher3.touch.PortraitPagedViewHandler;
|
||||
import com.android.launcher3.util.VibratorWrapper;
|
||||
@@ -198,18 +200,33 @@ public abstract class BaseSwipeUpHandler<T extends BaseDraggingActivity, Q exten
|
||||
}
|
||||
|
||||
protected void startNewTask(int successStateFlag, Consumer<Boolean> resultCallback) {
|
||||
if (TestProtocol.sDebugTracing) {
|
||||
Log.d(TestProtocol.NO_START_FROM_RECENTS, "startNewTask1");
|
||||
}
|
||||
// Launch the task user scrolled to (mRecentsView.getNextPage()).
|
||||
if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
|
||||
// We finish recents animation inside launchTask() when live tile is enabled.
|
||||
mRecentsView.getNextPageTaskView().launchTask(false /* animate */,
|
||||
true /* freezeTaskList */);
|
||||
} else {
|
||||
if (TestProtocol.sDebugTracing) {
|
||||
Log.d(TestProtocol.NO_START_FROM_RECENTS, "startNewTask2");
|
||||
}
|
||||
int taskId = mRecentsView.getNextPageTaskView().getTask().key.id;
|
||||
mFinishingRecentsAnimationForNewTaskId = taskId;
|
||||
mRecentsAnimationController.finish(true /* toRecents */, () -> {
|
||||
if (TestProtocol.sDebugTracing) {
|
||||
Log.d(TestProtocol.NO_START_FROM_RECENTS, "onFinishComplete1");
|
||||
}
|
||||
if (!mCanceled) {
|
||||
if (TestProtocol.sDebugTracing) {
|
||||
Log.d(TestProtocol.NO_START_FROM_RECENTS, "onFinishComplete2");
|
||||
}
|
||||
TaskView nextTask = mRecentsView.getTaskView(taskId);
|
||||
if (nextTask != null) {
|
||||
if (TestProtocol.sDebugTracing) {
|
||||
Log.d(TestProtocol.NO_START_FROM_RECENTS, "onFinishComplete3");
|
||||
}
|
||||
nextTask.launchTask(false /* animate */, true /* freezeTaskList */,
|
||||
success -> {
|
||||
resultCallback.accept(success);
|
||||
|
||||
@@ -166,6 +166,7 @@ public class FallbackSwipeHandler extends BaseSwipeUpHandler<RecentsActivity, Fa
|
||||
super.onActivityInit(alreadyOnHome);
|
||||
mActivity = mActivityInterface.getCreatedActivity();
|
||||
mRecentsView = mActivity.getOverviewPanel();
|
||||
mRecentsView.setOnPageTransitionEndCallback(null);
|
||||
linkRecentsViewScroll();
|
||||
mRecentsView.setDisallowScrollToClearAll(true);
|
||||
mRecentsView.getClearAllButton().setVisibilityAlpha(0);
|
||||
@@ -434,7 +435,12 @@ public class FallbackSwipeHandler extends BaseSwipeUpHandler<RecentsActivity, Fa
|
||||
|
||||
@Override
|
||||
public void onAnimationSuccess(Animator animator) {
|
||||
finishAnimationTargetSetAnimationComplete();
|
||||
if (mRecentsView != null) {
|
||||
mRecentsView.setOnPageTransitionEndCallback(FallbackSwipeHandler.this
|
||||
::finishAnimationTargetSetAnimationComplete);
|
||||
} else {
|
||||
finishAnimationTargetSetAnimationComplete();
|
||||
}
|
||||
mFinishAnimation = null;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* 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.quickstep;
|
||||
|
||||
import static android.content.Intent.EXTRA_STREAM;
|
||||
|
||||
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
|
||||
import static com.android.quickstep.util.ImageActionUtils.persistBitmapAndStartActivity;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Insets;
|
||||
import android.graphics.Rect;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.UiThread;
|
||||
|
||||
import com.android.launcher3.BuildConfig;
|
||||
import com.android.quickstep.util.ImageActionUtils;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* Contains image selection functions necessary to complete overview action button functions.
|
||||
*/
|
||||
public class ImageActionsApi {
|
||||
|
||||
private static final String TAG = BuildConfig.APPLICATION_ID + "ImageActionsApi";
|
||||
private final Context mContext;
|
||||
private final Supplier<Bitmap> mBitmapSupplier;
|
||||
private final SystemUiProxy mSystemUiProxy;
|
||||
|
||||
public ImageActionsApi(Context context, Supplier<Bitmap> bitmapSupplier) {
|
||||
mContext = context;
|
||||
mBitmapSupplier = bitmapSupplier;
|
||||
mSystemUiProxy = SystemUiProxy.INSTANCE.get(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Share the image this api was constructed with using the provided intent. The implementation
|
||||
* should add an {@link Intent#EXTRA_STREAM} with the URI pointing to the image to the intent.
|
||||
*/
|
||||
@UiThread
|
||||
public void shareWithExplicitIntent(@Nullable Rect crop, Intent intent) {
|
||||
if (mBitmapSupplier.get() == null) {
|
||||
Log.e(TAG, "No snapshot available, not starting share.");
|
||||
return;
|
||||
}
|
||||
|
||||
UI_HELPER_EXECUTOR.execute(() -> persistBitmapAndStartActivity(mContext,
|
||||
mBitmapSupplier.get(), crop, intent, (uri, intentForUri) -> {
|
||||
intentForUri.putExtra(EXTRA_STREAM, uri);
|
||||
return new Intent[]{intentForUri};
|
||||
}, TAG));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Share the image this api was constructed with.
|
||||
*/
|
||||
@UiThread
|
||||
public void startShareActivity() {
|
||||
ImageActionUtils.startShareActivity(mContext, mBitmapSupplier, null, null, TAG);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param screenshot to be saved to the media store.
|
||||
* @param screenshotBounds the location of where the bitmap was laid out on the screen in
|
||||
* screen coordinates.
|
||||
* @param visibleInsets that are used to draw the screenshot within the bounds.
|
||||
* @param taskId of the task that the screenshot was taken of.
|
||||
*/
|
||||
public void saveScreenshot(Bitmap screenshot, Rect screenshotBounds,
|
||||
Insets visibleInsets, int taskId) {
|
||||
ImageActionUtils.saveScreenshot(mSystemUiProxy, screenshot, screenshotBounds, visibleInsets,
|
||||
taskId);
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -55,9 +55,9 @@ import com.android.launcher3.LauncherState;
|
||||
import com.android.launcher3.allapps.DiscoveryBounce;
|
||||
import com.android.launcher3.anim.AnimatorPlaybackController;
|
||||
import com.android.launcher3.appprediction.PredictionUiStateManager;
|
||||
import com.android.launcher3.statehandlers.DepthController;
|
||||
import com.android.launcher3.statehandlers.DepthController.ClampedDepthProperty;
|
||||
import com.android.launcher3.touch.PagedOrientationHandler;
|
||||
import com.android.launcher3.uioverrides.DepthController;
|
||||
import com.android.launcher3.uioverrides.DepthController.ClampedDepthProperty;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto;
|
||||
import com.android.launcher3.views.FloatingIconView;
|
||||
import com.android.quickstep.SysUINavigationMode.Mode;
|
||||
|
||||
+54
-23
@@ -29,6 +29,7 @@ import static com.android.quickstep.GestureState.GestureEndTarget.LAST_TASK;
|
||||
import static com.android.quickstep.GestureState.GestureEndTarget.NEW_TASK;
|
||||
import static com.android.quickstep.GestureState.GestureEndTarget.RECENTS;
|
||||
import static com.android.quickstep.GestureState.STATE_END_TARGET_ANIMATION_FINISHED;
|
||||
import static com.android.quickstep.GestureState.STATE_RECENTS_SCROLLING_FINISHED;
|
||||
import static com.android.quickstep.MultiStateCallback.DEBUG_STATES;
|
||||
import static com.android.quickstep.SysUINavigationMode.Mode.TWO_BUTTONS;
|
||||
import static com.android.quickstep.util.ShelfPeekAnim.ShelfAnimState.HIDE;
|
||||
@@ -46,6 +47,7 @@ import android.graphics.PointF;
|
||||
import android.graphics.RectF;
|
||||
import android.os.Build;
|
||||
import android.os.SystemClock;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.View.OnApplyWindowInsetsListener;
|
||||
import android.view.ViewTreeObserver.OnDrawListener;
|
||||
@@ -64,6 +66,7 @@ import com.android.launcher3.anim.AnimationSuccessListener;
|
||||
import com.android.launcher3.anim.AnimatorPlaybackController;
|
||||
import com.android.launcher3.anim.Interpolators;
|
||||
import com.android.launcher3.logging.UserEventDispatcher;
|
||||
import com.android.launcher3.testing.TestProtocol;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
|
||||
@@ -244,7 +247,11 @@ public class LauncherSwipeHandler<T extends BaseDraggingActivity>
|
||||
| STATE_GESTURE_STARTED,
|
||||
this::setupLauncherUiAfterSwipeUpToRecentsAnimation);
|
||||
|
||||
mGestureState.runOnceAtState(STATE_END_TARGET_ANIMATION_FINISHED, this::onEndTargetSet);
|
||||
mGestureState.runOnceAtState(STATE_END_TARGET_ANIMATION_FINISHED,
|
||||
this::continueComputingRecentsScrollIfNecessary);
|
||||
mGestureState.runOnceAtState(STATE_END_TARGET_ANIMATION_FINISHED
|
||||
| STATE_RECENTS_SCROLLING_FINISHED,
|
||||
this::onSettledOnEndTarget);
|
||||
|
||||
mStateCallback.runOnceAtState(STATE_HANDLER_INVALIDATED, this::invalidateHandler);
|
||||
mStateCallback.runOnceAtState(STATE_LAUNCHER_PRESENT | STATE_HANDLER_INVALIDATED,
|
||||
@@ -283,6 +290,7 @@ public class LauncherSwipeHandler<T extends BaseDraggingActivity>
|
||||
}
|
||||
|
||||
mRecentsView = activity.getOverviewPanel();
|
||||
mRecentsView.setOnPageTransitionEndCallback(null);
|
||||
linkRecentsViewScroll();
|
||||
addLiveTileOverlay();
|
||||
|
||||
@@ -294,7 +302,6 @@ public class LauncherSwipeHandler<T extends BaseDraggingActivity>
|
||||
}
|
||||
|
||||
setupRecentsViewUi();
|
||||
mActivityInterface.getDepthController().setSurfaceToLauncher(mRecentsView);
|
||||
|
||||
if (mDeviceState.getNavMode() == TWO_BUTTONS) {
|
||||
// If the device is in two button mode, swiping up will show overview with predictions
|
||||
@@ -506,16 +513,22 @@ public class LauncherSwipeHandler<T extends BaseDraggingActivity>
|
||||
}
|
||||
|
||||
private void buildAnimationController() {
|
||||
if (mGestureState.getEndTarget() == HOME || mHasLauncherTransitionControllerStarted) {
|
||||
// We don't want a new mLauncherTransitionController if
|
||||
// mGestureState.getEndTarget() == HOME (it has its own animation) or if we're already
|
||||
// animating the current controller.
|
||||
if (!canCreateNewOrUpdateExistingLauncherTransitionController()) {
|
||||
return;
|
||||
}
|
||||
initTransitionEndpoints(mActivity.getDeviceProfile());
|
||||
mAnimationFactory.createActivityInterface(mTransitionDragLength);
|
||||
}
|
||||
|
||||
/**
|
||||
* We don't want to change mLauncherTransitionController if mGestureState.getEndTarget() == HOME
|
||||
* (it has its own animation) or if we're already animating the current controller.
|
||||
* @return Whether we can create the launcher controller or update its progress.
|
||||
*/
|
||||
private boolean canCreateNewOrUpdateExistingLauncherTransitionController() {
|
||||
return mGestureState.getEndTarget() != HOME && !mHasLauncherTransitionControllerStarted;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WindowInsets onApplyWindowInsets(View view, WindowInsets windowInsets) {
|
||||
WindowInsets result = view.onApplyWindowInsets(windowInsets);
|
||||
@@ -559,15 +572,12 @@ public class LauncherSwipeHandler<T extends BaseDraggingActivity>
|
||||
}
|
||||
}
|
||||
|
||||
if (mLauncherTransitionController == null || mLauncherTransitionController
|
||||
.getAnimationPlayer().isStarted()) {
|
||||
return;
|
||||
}
|
||||
updateLauncherTransitionProgress();
|
||||
}
|
||||
|
||||
private void updateLauncherTransitionProgress() {
|
||||
if (mGestureState.getEndTarget() == HOME) {
|
||||
if (mLauncherTransitionController == null
|
||||
|| !canCreateNewOrUpdateExistingLauncherTransitionController()) {
|
||||
return;
|
||||
}
|
||||
// Normalize the progress to 0 to 1, as the animation controller will clamp it to that
|
||||
@@ -697,7 +707,7 @@ public class LauncherSwipeHandler<T extends BaseDraggingActivity>
|
||||
}
|
||||
}
|
||||
|
||||
private void onEndTargetSet() {
|
||||
private void onSettledOnEndTarget() {
|
||||
switch (mGestureState.getEndTarget()) {
|
||||
case HOME:
|
||||
mStateCallback.setState(STATE_SCALED_CONTROLLER_HOME | STATE_CAPTURE_SCREENSHOT);
|
||||
@@ -860,13 +870,17 @@ public class LauncherSwipeHandler<T extends BaseDraggingActivity>
|
||||
if (mDeviceState.isFullyGesturalNavMode()) {
|
||||
setShelfState(ShelfAnimState.OVERVIEW, interpolator, duration);
|
||||
}
|
||||
} else if (endTarget == NEW_TASK || endTarget == LAST_TASK) {
|
||||
// Let RecentsView handle the scrolling to the task, which we launch in startNewTask()
|
||||
// or resumeLastTask().
|
||||
if (mRecentsView != null) {
|
||||
duration = Math.max(duration, mRecentsView.getScroller().getDuration());
|
||||
}
|
||||
}
|
||||
|
||||
// Let RecentsView handle the scrolling to the task, which we launch in startNewTask()
|
||||
// or resumeLastTask().
|
||||
if (mRecentsView != null) {
|
||||
mRecentsView.setOnPageTransitionEndCallback(
|
||||
() -> mGestureState.setState(STATE_RECENTS_SCROLLING_FINISHED));
|
||||
} else {
|
||||
mGestureState.setState(STATE_RECENTS_SCROLLING_FINISHED);
|
||||
}
|
||||
|
||||
animateToProgress(startShift, endShift, duration, interpolator, endTarget, velocityPxPerMs);
|
||||
}
|
||||
|
||||
@@ -950,15 +964,14 @@ public class LauncherSwipeHandler<T extends BaseDraggingActivity>
|
||||
ValueAnimator windowAnim = mCurrentShift.animateToValue(start, end);
|
||||
windowAnim.setDuration(duration).setInterpolator(interpolator);
|
||||
windowAnim.addUpdateListener(valueAnimator -> {
|
||||
if (mRecentsView != null && mRecentsView.getVisibility() != View.VISIBLE) {
|
||||
// Views typically don't compute scroll when invisible as an optimization,
|
||||
// but in our case we need to since the window offset depends on the scroll.
|
||||
mRecentsView.computeScroll();
|
||||
}
|
||||
computeRecentsScrollIfInvisible();
|
||||
});
|
||||
windowAnim.addListener(new AnimationSuccessListener() {
|
||||
@Override
|
||||
public void onAnimationSuccess(Animator animator) {
|
||||
if (TestProtocol.sDebugTracing) {
|
||||
Log.d(TestProtocol.NO_START_FROM_RECENTS, "onAnimationSuccess");
|
||||
}
|
||||
if (mRecentsAnimationController == null) {
|
||||
// If the recents animation is interrupted, we still end the running
|
||||
// animation (not canceled) so this is still called. In that case, we can
|
||||
@@ -1006,6 +1019,21 @@ public class LauncherSwipeHandler<T extends BaseDraggingActivity>
|
||||
mHasLauncherTransitionControllerStarted = true;
|
||||
}
|
||||
|
||||
private void computeRecentsScrollIfInvisible() {
|
||||
if (mRecentsView != null && mRecentsView.getVisibility() != View.VISIBLE) {
|
||||
// Views typically don't compute scroll when invisible as an optimization,
|
||||
// but in our case we need to since the window offset depends on the scroll.
|
||||
mRecentsView.computeScroll();
|
||||
}
|
||||
}
|
||||
|
||||
private void continueComputingRecentsScrollIfNecessary() {
|
||||
if (!mGestureState.hasState(STATE_RECENTS_SCROLLING_FINISHED)) {
|
||||
computeRecentsScrollIfInvisible();
|
||||
mRecentsView.post(this::continueComputingRecentsScrollIfNecessary);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an animation that transforms the current app window into the home app.
|
||||
* @param startProgress The progress of {@link #mCurrentShift} to start the window from.
|
||||
@@ -1167,6 +1195,9 @@ public class LauncherSwipeHandler<T extends BaseDraggingActivity>
|
||||
}
|
||||
|
||||
private void switchToScreenshot() {
|
||||
if (TestProtocol.sDebugTracing) {
|
||||
Log.d(TestProtocol.NO_START_FROM_RECENTS, "switchToScreenshot");
|
||||
}
|
||||
final int runningTaskId = mGestureState.getRunningTaskId();
|
||||
if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
|
||||
if (mRecentsAnimationController != null) {
|
||||
|
||||
@@ -16,12 +16,13 @@
|
||||
|
||||
package com.android.quickstep;
|
||||
|
||||
import static com.android.launcher3.config.FeatureFlags.ENABLE_OVERVIEW_ACTIONS;
|
||||
import static com.android.launcher3.util.MainThreadInitializedObject.forOverride;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Insets;
|
||||
import android.graphics.Matrix;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import android.graphics.Rect;
|
||||
|
||||
import com.android.launcher3.BaseActivity;
|
||||
import com.android.launcher3.BaseDraggingActivity;
|
||||
@@ -29,6 +30,7 @@ import com.android.launcher3.R;
|
||||
import com.android.launcher3.popup.SystemShortcut;
|
||||
import com.android.launcher3.util.MainThreadInitializedObject;
|
||||
import com.android.launcher3.util.ResourceBasedOverride;
|
||||
import com.android.quickstep.views.OverviewActionsView;
|
||||
import com.android.quickstep.views.TaskThumbnailView;
|
||||
import com.android.quickstep.views.TaskView;
|
||||
import com.android.systemui.plugins.OverscrollPlugin;
|
||||
@@ -43,16 +45,6 @@ import java.util.List;
|
||||
*/
|
||||
public class TaskOverlayFactory implements ResourceBasedOverride {
|
||||
|
||||
/** Note that these will be shown in order from top to bottom, if available for the task. */
|
||||
private static final TaskShortcutFactory[] MENU_OPTIONS = new TaskShortcutFactory[]{
|
||||
TaskShortcutFactory.APP_INFO,
|
||||
TaskShortcutFactory.SPLIT_SCREEN,
|
||||
TaskShortcutFactory.PIN,
|
||||
TaskShortcutFactory.INSTALL,
|
||||
TaskShortcutFactory.FREE_FORM,
|
||||
TaskShortcutFactory.WELLBEING
|
||||
};
|
||||
|
||||
public static List<SystemShortcut> getEnabledShortcuts(TaskView taskView) {
|
||||
final ArrayList<SystemShortcut> shortcuts = new ArrayList<>();
|
||||
final BaseDraggingActivity activity = BaseActivity.fromContext(taskView.getContext());
|
||||
@@ -76,25 +68,68 @@ public class TaskOverlayFactory implements ResourceBasedOverride {
|
||||
}
|
||||
|
||||
public TaskOverlay createOverlay(TaskThumbnailView thumbnailView) {
|
||||
return new TaskOverlay();
|
||||
return new TaskOverlay(thumbnailView);
|
||||
}
|
||||
|
||||
/** Note that these will be shown in order from top to bottom, if available for the task. */
|
||||
private static final TaskShortcutFactory[] MENU_OPTIONS = new TaskShortcutFactory[]{
|
||||
TaskShortcutFactory.APP_INFO,
|
||||
TaskShortcutFactory.SPLIT_SCREEN,
|
||||
TaskShortcutFactory.PIN,
|
||||
TaskShortcutFactory.INSTALL,
|
||||
TaskShortcutFactory.FREE_FORM,
|
||||
TaskShortcutFactory.WELLBEING
|
||||
};
|
||||
|
||||
/**
|
||||
* Overlay on each task handling Overview Action Buttons.
|
||||
*/
|
||||
public static class TaskOverlay {
|
||||
|
||||
private final Context mApplicationContext;
|
||||
private OverviewActionsView mActionsView;
|
||||
private final TaskThumbnailView mThumbnailView;
|
||||
|
||||
|
||||
protected TaskOverlay(TaskThumbnailView taskThumbnailView) {
|
||||
mApplicationContext = taskThumbnailView.getContext().getApplicationContext();
|
||||
mThumbnailView = taskThumbnailView;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
if (mActionsView == null && ENABLE_OVERVIEW_ACTIONS.get()
|
||||
&& SysUINavigationMode.removeShelfFromOverview(mApplicationContext)) {
|
||||
mActionsView = BaseActivity.fromContext(mThumbnailView.getContext()).findViewById(
|
||||
R.id.overview_actions_view);
|
||||
}
|
||||
if (mActionsView != null) {
|
||||
mActionsView.setListener(new OverviewActionsView.Listener() {
|
||||
@Override
|
||||
public void onShare() {
|
||||
imageApi.startShareActivity();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onScreenshot() {
|
||||
imageApi.saveScreenshot(mThumbnailView.getThumbnail(),
|
||||
getTaskSnapshotBounds(), getTaskSnapshotInsets(), task.key.id);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public View getActionsView() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the overlay is no longer used.
|
||||
*/
|
||||
public void reset() { }
|
||||
public void reset() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the overlay is modal, which means only tapping is enabled, but no swiping.
|
||||
@@ -102,5 +137,28 @@ public class TaskOverlayFactory implements ResourceBasedOverride {
|
||||
public boolean isOverlayModal() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the task snapshot as it is displayed on the screen.
|
||||
*
|
||||
* @return the bounds of the snapshot in screen coordinates.
|
||||
*/
|
||||
public Rect getTaskSnapshotBounds() {
|
||||
int[] location = new int[2];
|
||||
mThumbnailView.getLocationOnScreen(location);
|
||||
|
||||
return new Rect(location[0], location[1], mThumbnailView.getWidth() + location[0],
|
||||
mThumbnailView.getHeight() + location[1]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the insets that the snapshot is drawn with.
|
||||
*
|
||||
* @return the insets in screen coordinates.
|
||||
*/
|
||||
public Insets getTaskSnapshotInsets() {
|
||||
// TODO: return the real insets
|
||||
return Insets.of(0, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ import static com.android.launcher3.LauncherState.BACKGROUND_APP;
|
||||
import static com.android.launcher3.anim.Interpolators.LINEAR;
|
||||
import static com.android.launcher3.anim.Interpolators.TOUCH_RESPONSE_INTERPOLATOR;
|
||||
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
|
||||
import static com.android.launcher3.uioverrides.DepthController.DEPTH;
|
||||
import static com.android.launcher3.statehandlers.DepthController.DEPTH;
|
||||
import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_OPENING;
|
||||
|
||||
import android.animation.Animator;
|
||||
@@ -35,7 +35,7 @@ import com.android.launcher3.BaseActivity;
|
||||
import com.android.launcher3.BaseDraggingActivity;
|
||||
import com.android.launcher3.ItemInfo;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.uioverrides.DepthController;
|
||||
import com.android.launcher3.statehandlers.DepthController;
|
||||
import com.android.quickstep.util.AppWindowAnimationHelper;
|
||||
import com.android.quickstep.util.MultiValueUpdateListener;
|
||||
import com.android.quickstep.views.RecentsView;
|
||||
|
||||
+22
-6
@@ -22,6 +22,7 @@ import static android.view.MotionEvent.ACTION_UP;
|
||||
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
|
||||
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
|
||||
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
|
||||
import static com.android.quickstep.GestureState.DEFAULT_STATE;
|
||||
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_INPUT_MONITOR;
|
||||
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SYSUI_PROXY;
|
||||
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_TRACING_ENABLED;
|
||||
@@ -124,6 +125,7 @@ public class TouchInteractionService extends Service implements PluginListener<O
|
||||
private static final String NOTIFY_ACTION_BACK = "com.android.quickstep.action.BACK_GESTURE";
|
||||
private static final String HAS_ENABLED_QUICKSTEP_ONCE = "launcher.has_enabled_quickstep_once";
|
||||
private static final int MAX_BACK_NOTIFICATION_COUNT = 3;
|
||||
|
||||
private int mBackGestureNotificationCounter = -1;
|
||||
@Nullable
|
||||
private OverscrollPlugin mOverscrollPlugin;
|
||||
@@ -263,7 +265,7 @@ public class TouchInteractionService extends Service implements PluginListener<O
|
||||
private InputConsumer mConsumer = InputConsumer.NO_OP;
|
||||
private Choreographer mMainChoreographer;
|
||||
private InputConsumer mResetGestureInputConsumer;
|
||||
private GestureState mGestureState = new GestureState();
|
||||
private GestureState mGestureState = DEFAULT_STATE;
|
||||
|
||||
private InputMonitorCompat mInputMonitorCompat;
|
||||
private InputEventReceiver mInputEventReceiver;
|
||||
@@ -435,16 +437,14 @@ public class TouchInteractionService extends Service implements PluginListener<O
|
||||
|
||||
Object traceToken = TraceHelper.INSTANCE.beginFlagsOverride(
|
||||
TraceHelper.FLAG_ALLOW_BINDER_TRACKING);
|
||||
mDeviceState.setOrientationTransformIfNeeded(event);
|
||||
|
||||
final int action = event.getAction();
|
||||
if (action == ACTION_DOWN) {
|
||||
GestureState newGestureState = new GestureState(mOverviewComponentObserver,
|
||||
ActiveGestureLog.INSTANCE.generateAndSetLogId());
|
||||
newGestureState.updateRunningTask(TraceHelper.whitelistIpcs("getRunningTask.0",
|
||||
() -> mAM.getRunningTask(true /* filterOnlyVisibleRecents */)));
|
||||
mDeviceState.setOrientationTransformIfNeeded(event);
|
||||
GestureState newGestureState;
|
||||
|
||||
if (mDeviceState.isInSwipeUpTouchRegion(event)) {
|
||||
newGestureState = createGestureState();
|
||||
mConsumer.onConsumerAboutToBeSwitched();
|
||||
mConsumer = newConsumer(mGestureState, newGestureState, event);
|
||||
|
||||
@@ -453,6 +453,7 @@ public class TouchInteractionService extends Service implements PluginListener<O
|
||||
} else if (mDeviceState.isUserUnlocked()
|
||||
&& mDeviceState.isFullyGesturalNavMode()
|
||||
&& mDeviceState.canTriggerAssistantAction(event)) {
|
||||
newGestureState = createGestureState();
|
||||
// Do not change mConsumer as if there is an ongoing QuickSwitch gesture, we should
|
||||
// not interrupt it. QuickSwitch assumes that interruption can only happen if the
|
||||
// next gesture is also quick switch.
|
||||
@@ -462,11 +463,18 @@ public class TouchInteractionService extends Service implements PluginListener<O
|
||||
InputConsumer.NO_OP, mInputMonitorCompat,
|
||||
mOverviewComponentObserver.assistantGestureIsConstrained());
|
||||
} else {
|
||||
newGestureState = DEFAULT_STATE;
|
||||
mUncheckedConsumer = InputConsumer.NO_OP;
|
||||
}
|
||||
|
||||
// Save the current gesture state
|
||||
mGestureState = newGestureState;
|
||||
} else {
|
||||
// Other events
|
||||
if (mUncheckedConsumer != InputConsumer.NO_OP) {
|
||||
// Only transform the event if we are handling it in a proper consumer
|
||||
mDeviceState.setOrientationTransformIfNeeded(event);
|
||||
}
|
||||
}
|
||||
|
||||
ActiveGestureLog.INSTANCE.addLog("onMotionEvent", event.getActionMasked());
|
||||
@@ -481,6 +489,14 @@ public class TouchInteractionService extends Service implements PluginListener<O
|
||||
TraceHelper.INSTANCE.endFlagsOverride(traceToken);
|
||||
}
|
||||
|
||||
private GestureState createGestureState() {
|
||||
GestureState gestureState = new GestureState(mOverviewComponentObserver,
|
||||
ActiveGestureLog.INSTANCE.generateAndSetLogId());
|
||||
gestureState.updateRunningTask(TraceHelper.whitelistIpcs("getRunningTask.0",
|
||||
() -> mAM.getRunningTask(true /* filterOnlyVisibleRecents */)));
|
||||
return gestureState;
|
||||
}
|
||||
|
||||
private InputConsumer newConsumer(GestureState previousGestureState,
|
||||
GestureState newGestureState, MotionEvent event) {
|
||||
boolean canStartSystemGesture = mDeviceState.canStartSystemGesture();
|
||||
|
||||
+1
-1
@@ -41,7 +41,7 @@ public abstract class DelegateInputConsumer implements InputConsumer {
|
||||
|
||||
protected void setActive(MotionEvent ev) {
|
||||
mState = STATE_ACTIVE;
|
||||
TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "pilferPointers");
|
||||
TestLogging.recordEvent(TestProtocol.SEQUENCE_PILFER, "pilferPointers");
|
||||
mInputMonitor.pilferPointers();
|
||||
|
||||
// Send cancel event
|
||||
|
||||
+1
-1
@@ -204,7 +204,7 @@ public class DeviceLockedInputConsumer implements InputConsumer,
|
||||
|
||||
private void startRecentsTransition() {
|
||||
mThresholdCrossed = true;
|
||||
TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "pilferPointers");
|
||||
TestLogging.recordEvent(TestProtocol.SEQUENCE_PILFER, "pilferPointers");
|
||||
mInputMonitorCompat.pilferPointers();
|
||||
|
||||
Intent intent = new Intent(Intent.ACTION_MAIN)
|
||||
|
||||
+1
-1
@@ -314,7 +314,7 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC
|
||||
if (mInteractionHandler == null) {
|
||||
return;
|
||||
}
|
||||
TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "pilferPointers");
|
||||
TestLogging.recordEvent(TestProtocol.SEQUENCE_PILFER, "pilferPointers");
|
||||
mInputMonitorCompat.pilferPointers();
|
||||
|
||||
mActivityInterface.closeOverlay();
|
||||
|
||||
+1
-1
@@ -108,7 +108,7 @@ public class OverviewInputConsumer<T extends BaseDraggingActivity>
|
||||
ActiveGestureLog.INSTANCE.addLog("startQuickstep");
|
||||
}
|
||||
if (mInputMonitor != null) {
|
||||
TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "pilferPointers");
|
||||
TestLogging.recordEvent(TestProtocol.SEQUENCE_PILFER, "pilferPointers");
|
||||
mInputMonitor.pilferPointers();
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -65,7 +65,7 @@ public class OverviewWithoutFocusInputConsumer implements InputConsumer {
|
||||
|
||||
private void onInterceptTouch() {
|
||||
if (mInputMonitor != null) {
|
||||
TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "pilferPointers");
|
||||
TestLogging.recordEvent(TestProtocol.SEQUENCE_PILFER, "pilferPointers");
|
||||
mInputMonitor.pilferPointers();
|
||||
}
|
||||
}
|
||||
|
||||
+6
-5
@@ -19,7 +19,7 @@ import static com.android.launcher3.LauncherState.ALL_APPS;
|
||||
import static com.android.launcher3.LauncherState.ALL_APPS_HEADER_EXTRA;
|
||||
import static com.android.launcher3.LauncherState.NORMAL;
|
||||
import static com.android.launcher3.LauncherState.OVERVIEW;
|
||||
import static com.android.launcher3.LauncherState.RECENTS_CLEAR_ALL_BUTTON;
|
||||
import static com.android.launcher3.LauncherState.OVERVIEW_BUTTONS;
|
||||
import static com.android.launcher3.LauncherState.SPRING_LOADED;
|
||||
import static com.android.launcher3.QuickstepAppTransitionManagerImpl.ALL_APPS_PROGRESS_OFF_SCREEN;
|
||||
import static com.android.launcher3.allapps.AllAppsTransitionController.ALL_APPS_PROGRESS;
|
||||
@@ -37,9 +37,9 @@ import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import com.android.launcher3.BaseQuickstepLauncher;
|
||||
import com.android.launcher3.DeviceProfile;
|
||||
import com.android.launcher3.Hotseat;
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.LauncherState;
|
||||
import com.android.launcher3.LauncherStateManager.StateListener;
|
||||
import com.android.launcher3.R;
|
||||
@@ -47,8 +47,8 @@ import com.android.launcher3.anim.Interpolators;
|
||||
import com.android.launcher3.appprediction.PredictionUiStateManager;
|
||||
import com.android.launcher3.appprediction.PredictionUiStateManager.Client;
|
||||
import com.android.launcher3.config.FeatureFlags;
|
||||
import com.android.launcher3.statehandlers.DepthController;
|
||||
import com.android.launcher3.states.RotationHelper;
|
||||
import com.android.launcher3.uioverrides.DepthController;
|
||||
import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
|
||||
import com.android.launcher3.util.TraceHelper;
|
||||
import com.android.launcher3.views.ScrimView;
|
||||
@@ -63,7 +63,8 @@ import com.android.systemui.plugins.RecentsExtraCard;
|
||||
* {@link RecentsView} used in Launcher activity
|
||||
*/
|
||||
@TargetApi(Build.VERSION_CODES.O)
|
||||
public class LauncherRecentsView extends RecentsView<Launcher> implements StateListener {
|
||||
public class LauncherRecentsView extends RecentsView<BaseQuickstepLauncher>
|
||||
implements StateListener {
|
||||
|
||||
private static final Rect sTempRect = new Rect();
|
||||
|
||||
@@ -322,7 +323,7 @@ public class LauncherRecentsView extends RecentsView<Launcher> implements StateL
|
||||
if (enabled) {
|
||||
LauncherState state = mActivity.getStateManager().getState();
|
||||
boolean hasClearAllButton = (state.getVisibleElements(mActivity)
|
||||
& RECENTS_CLEAR_ALL_BUTTON) != 0;
|
||||
& OVERVIEW_BUTTONS) != 0;
|
||||
setDisallowScrollToClearAll(!hasClearAllButton);
|
||||
}
|
||||
}
|
||||
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* 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.quickstep.views;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.android.launcher3.R;
|
||||
|
||||
/**
|
||||
* View for showing action buttons in Overview
|
||||
*/
|
||||
public class OverviewActionsView extends FrameLayout {
|
||||
|
||||
private final View mScreenshotButton;
|
||||
private final View mShareButton;
|
||||
|
||||
/**
|
||||
* Listener for taps on the various actions.
|
||||
*/
|
||||
public interface Listener {
|
||||
/** User has initiated the share actions. */
|
||||
void onShare();
|
||||
|
||||
/** User has initiated the screenshot action. */
|
||||
void onScreenshot();
|
||||
}
|
||||
|
||||
public OverviewActionsView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public OverviewActionsView(Context context, @Nullable AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public OverviewActionsView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
|
||||
this(context, attrs, defStyleAttr, 0);
|
||||
}
|
||||
|
||||
public OverviewActionsView(Context context, AttributeSet attrs, int defStyleAttr,
|
||||
int defStyleRes) {
|
||||
super(context, attrs, defStyleAttr, defStyleRes);
|
||||
LayoutInflater.from(context).inflate(R.layout.overview_actions, this, true);
|
||||
mShareButton = findViewById(R.id.action_share);
|
||||
mScreenshotButton = findViewById(R.id.action_screenshot);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set listener for callbacks on action button taps.
|
||||
*
|
||||
* @param listener for callbacks, or {@code null} to clear the listener.
|
||||
*/
|
||||
public void setListener(@Nullable OverviewActionsView.Listener listener) {
|
||||
mShareButton.setOnClickListener(
|
||||
listener == null ? null : view -> listener.onShare());
|
||||
mScreenshotButton.setOnClickListener(
|
||||
listener == null ? null : view -> listener.onScreenshot());
|
||||
}
|
||||
}
|
||||
@@ -30,7 +30,9 @@ import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
|
||||
import static com.android.launcher3.anim.Interpolators.LINEAR;
|
||||
import static com.android.launcher3.config.FeatureFlags.ENABLE_OVERVIEW_ACTIONS;
|
||||
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
|
||||
import static com.android.launcher3.uioverrides.DepthController.DEPTH;
|
||||
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.TASK_DISMISS_SWIPE_UP;
|
||||
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.TASK_LAUNCH_SWIPE_DOWN;
|
||||
import static com.android.launcher3.statehandlers.DepthController.DEPTH;
|
||||
import static com.android.launcher3.uioverrides.touchcontrollers.TaskViewTouchController.SUCCESS_TRANSITION_PROGRESS;
|
||||
import static com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch.TAP;
|
||||
import static com.android.launcher3.userevent.nano.LauncherLogProto.ControlType.CLEAR_ALL_BUTTON;
|
||||
@@ -96,9 +98,9 @@ import com.android.launcher3.anim.SpringProperty;
|
||||
import com.android.launcher3.compat.AccessibilityManagerCompat;
|
||||
import com.android.launcher3.config.FeatureFlags;
|
||||
import com.android.launcher3.graphics.RotationMode;
|
||||
import com.android.launcher3.statehandlers.DepthController;
|
||||
import com.android.launcher3.states.RotationHelper;
|
||||
import com.android.launcher3.touch.PagedOrientationHandler.CurveProperties;
|
||||
import com.android.launcher3.uioverrides.DepthController;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
|
||||
@@ -1183,13 +1185,13 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
verticalFactor * secondaryTaskDimension).setDuration(duration), LINEAR, sp);
|
||||
}
|
||||
|
||||
private void removeTask(Task task, int index, EndState endState) {
|
||||
if (task != null) {
|
||||
ActivityManagerWrapper.getInstance().removeTask(task.key.id);
|
||||
ComponentKey componentKey = TaskUtils.getLaunchComponentKeyForTask(task.key);
|
||||
private void removeTask(TaskView taskView, int index, EndState endState) {
|
||||
if (taskView.getTask() != null) {
|
||||
ActivityManagerWrapper.getInstance().removeTask(taskView.getTask().key.id);
|
||||
ComponentKey compKey = TaskUtils.getLaunchComponentKeyForTask(taskView.getTask().key);
|
||||
mActivity.getUserEventDispatcher().logTaskLaunchOrDismiss(
|
||||
endState.logAction, Direction.UP, index, componentKey);
|
||||
mActivity.getStatsLogManager().logTaskDismiss(this, componentKey);
|
||||
endState.logAction, Direction.UP, index, compKey);
|
||||
mActivity.getStatsLogManager().log(TASK_DISMISS_SWIPE_UP, taskView.buildProto());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1284,7 +1286,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
private void onEnd(EndState endState) {
|
||||
if (endState.isSuccess) {
|
||||
if (shouldRemoveTask) {
|
||||
removeTask(taskView.getTask(), draggedIndex, endState);
|
||||
removeTask(taskView, draggedIndex, endState);
|
||||
}
|
||||
|
||||
int pageToSnapTo = mCurrentPage;
|
||||
@@ -1733,6 +1735,8 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
mActivity.getUserEventDispatcher().logTaskLaunchOrDismiss(
|
||||
endState.logAction, Direction.DOWN, indexOfChild(tv),
|
||||
TaskUtils.getLaunchComponentKeyForTask(task.key));
|
||||
mActivity.getStatsLogManager().log(TASK_LAUNCH_SWIPE_DOWN, tv.buildProto()
|
||||
);
|
||||
}
|
||||
} else {
|
||||
onTaskLaunched(false);
|
||||
|
||||
@@ -29,6 +29,7 @@ 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.TOUCH_RESPONSE_INTERPOLATOR;
|
||||
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
|
||||
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.TASK_LAUNCH_TAP;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
@@ -43,6 +44,7 @@ import android.graphics.RectF;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Process;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.FloatProperty;
|
||||
import android.util.Log;
|
||||
@@ -59,6 +61,7 @@ import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.anim.AnimatorPlaybackController;
|
||||
import com.android.launcher3.anim.Interpolators;
|
||||
import com.android.launcher3.anim.PendingAnimation;
|
||||
import com.android.launcher3.logger.LauncherAtom;
|
||||
import com.android.launcher3.logging.UserEventDispatcher;
|
||||
import com.android.launcher3.popup.SystemShortcut;
|
||||
import com.android.launcher3.states.RotationHelper;
|
||||
@@ -68,6 +71,7 @@ import com.android.launcher3.touch.PagedOrientationHandler;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
|
||||
import com.android.launcher3.util.ComponentKey;
|
||||
import com.android.launcher3.util.ViewPool.Reusable;
|
||||
import com.android.quickstep.RecentsModel;
|
||||
import com.android.quickstep.TaskIconCache;
|
||||
@@ -217,8 +221,7 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
|
||||
mActivity.getUserEventDispatcher().logTaskLaunchOrDismiss(
|
||||
Touch.TAP, Direction.NONE, getRecentsView().indexOfChild(this),
|
||||
TaskUtils.getLaunchComponentKeyForTask(getTask().key));
|
||||
mActivity.getStatsLogManager().logTaskLaunch(getRecentsView(),
|
||||
TaskUtils.getLaunchComponentKeyForTask(getTask().key));
|
||||
mActivity.getStatsLogManager().log(TASK_LAUNCH_TAP, buildProto());
|
||||
});
|
||||
mCornerRadius = TaskCornerRadius.get(context);
|
||||
mWindowCornerRadius = QuickStepContract.getWindowCornerRadius(context.getResources());
|
||||
@@ -229,6 +232,17 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
|
||||
setOutlineProvider(mOutlineProvider);
|
||||
}
|
||||
|
||||
/* Builds proto for logging */
|
||||
protected LauncherAtom.ItemInfo buildProto() {
|
||||
ComponentKey componentKey = TaskUtils.getLaunchComponentKeyForTask(getTask().key);
|
||||
LauncherAtom.ItemInfo.Builder itemBuilder = LauncherAtom.ItemInfo.newBuilder();
|
||||
itemBuilder.setIsWork(componentKey.user != Process.myUserHandle());
|
||||
itemBuilder.setTask(LauncherAtom.Task.newBuilder()
|
||||
.setComponentName(componentKey.componentName.flattenToShortString())
|
||||
.setIndex(getRecentsView().indexOfChild(this)));
|
||||
return itemBuilder.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFinishInflate() {
|
||||
super.onFinishInflate();
|
||||
@@ -812,8 +826,8 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
|
||||
super.onInitializeAccessibilityNodeInfo(info);
|
||||
|
||||
info.addAction(
|
||||
new AccessibilityNodeInfo.AccessibilityAction(R.string.accessibility_close_task,
|
||||
getContext().getText(R.string.accessibility_close_task)));
|
||||
new AccessibilityNodeInfo.AccessibilityAction(R.string.accessibility_close,
|
||||
getContext().getText(R.string.accessibility_close)));
|
||||
|
||||
final Context context = getContext();
|
||||
for (SystemShortcut s : TaskOverlayFactory.getEnabledShortcuts(this)) {
|
||||
@@ -837,7 +851,7 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
|
||||
|
||||
@Override
|
||||
public boolean performAccessibilityAction(int action, Bundle arguments) {
|
||||
if (action == R.string.accessibility_close_task) {
|
||||
if (action == R.string.accessibility_close) {
|
||||
getRecentsView().dismissTask(this, true /*animateTaskView*/,
|
||||
true /*removeTask*/);
|
||||
return true;
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
<!-- 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.
|
||||
-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M17,1.01L7,1c-1.1,0 -2,0.9 -2,2v18c0,1.1 0.9,2 2,2h10c1.1,0 2,-0.9 2,-2L19,3c0,-1.1 -0.9,-1.99 -2,-1.99zM17,21L7,21v-1h10v1zM17,18L7,18L7,6h10v12zM17,4L7,4L7,3h10v1zM9.5,8.5L12,8.5L12,7L8,7v4h1.5zM12,17h4v-4h-1.5v2.5L12,15.5z"/>
|
||||
</vector>
|
||||
@@ -0,0 +1,23 @@
|
||||
<!-- 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.
|
||||
-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M18,16c-0.79,0 -1.5,0.31 -2.03,0.81L8.91,12.7c0.05,-0.23 0.09,-0.46 0.09,-0.7s-0.04,-0.47 -0.09,-0.7l7.05,-4.11c0.53,0.5 1.25,0.81 2.04,0.81 1.66,0 3,-1.34 3,-3s-1.34,-3 -3,-3 -3,1.34 -3,3c0,0.24 0.04,0.48 0.09,0.7L8.04,9.81C7.5,9.31 6.79,9 6,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3c0.79,0 1.5,-0.31 2.04,-0.81l7.05,4.12c-0.05,0.22 -0.09,0.45 -0.09,0.69 0,1.66 1.34,3 3,3s3,-1.34 3,-3 -1.34,-3 -3,-3zM18,4c0.55,0 1,0.45 1,1s-0.45,1 -1,1 -1,-0.45 -1,-1 0.45,-1 1,-1zM6,13c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1 1,0.45 1,1 -0.45,1 -1,1zM18,20c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1 1,0.45 1,1 -0.45,1 -1,1z"/>
|
||||
</vector>
|
||||
@@ -0,0 +1,41 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<merge xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<LinearLayout
|
||||
android:id="@+id/action_buttons"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:orientation="horizontal">
|
||||
<Space
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="1dp"
|
||||
android:layout_weight="1" >
|
||||
</Space>
|
||||
<Button
|
||||
android:id="@+id/action_screenshot"
|
||||
style="@style/OverviewActionButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:drawableTop="@drawable/ic_screenshot"
|
||||
android:text="@string/action_screenshot" />
|
||||
<Space
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="1dp"
|
||||
android:layout_weight="1" >
|
||||
</Space>
|
||||
|
||||
<Button
|
||||
android:id="@+id/action_share"
|
||||
style="@style/OverviewActionButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:drawableTop="@drawable/ic_share"
|
||||
android:text="@string/action_share" />
|
||||
<Space
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="1dp"
|
||||
android:layout_weight="1" >
|
||||
</Space>
|
||||
</LinearLayout>
|
||||
|
||||
</merge>
|
||||
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
<com.android.quickstep.views.OverviewActionsView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone">
|
||||
|
||||
</com.android.quickstep.views.OverviewActionsView>
|
||||
@@ -23,7 +23,7 @@
|
||||
<dimen name="task_corner_radius_small">2dp</dimen>
|
||||
|
||||
<!-- Overrideable in overlay that provides the Overview Actions. -->
|
||||
<dimen name="overview_actions_height">0dp</dimen>
|
||||
<dimen name="overview_actions_height">110dp</dimen>
|
||||
|
||||
<dimen name="recents_page_spacing">10dp</dimen>
|
||||
<dimen name="recents_clear_all_deadzone_vertical_margin">70dp</dimen>
|
||||
|
||||
@@ -32,9 +32,6 @@
|
||||
<!-- Recents: The empty recents string. [CHAR LIMIT=NONE] -->
|
||||
<string name="recents_empty_message">No recent items</string>
|
||||
|
||||
<!-- Content description for the recent apps's accessibility option that closes it. [CHAR LIMIT=NONE] -->
|
||||
<string name="accessibility_close_task">Close</string>
|
||||
|
||||
<!-- Content description for the recent apps's accessibility option that opens its usage settings. [CHAR LIMIT=NONE] -->
|
||||
<string name="accessibility_app_usage_settings">App usage settings</string>
|
||||
|
||||
@@ -83,16 +80,15 @@
|
||||
<!-- Button text to dismiss opt in for fully predicted hotseat -->
|
||||
<string name="hotseat_edu_dismiss">No thanks</string>
|
||||
|
||||
<!-- action shown to turn of predictions after onboarding -->
|
||||
<!-- action shown to turn off predictions after onboarding -->
|
||||
<string name="hotseat_turn_off">Settings</string>
|
||||
|
||||
<!-- 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>
|
||||
<!-- tip shown if user declines migration and has some open spots for prediction -->
|
||||
<string name="hotseat_tip_no_empty_slots">Drag apps off the bottom row to get app suggestions</string>
|
||||
<!-- tip shown if user declines migration and has no open spots for prediction -->
|
||||
<string name="hotseat_tip_gaps_filled">App suggestions added to empty space.</string>
|
||||
|
||||
<string name="hotseat_tip_no_empty_slots">Drag apps off the bottom row to get app suggestions</string>
|
||||
<!-- 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>
|
||||
|
||||
<!-- Title shown during interactive part of Back gesture tutorial for right edge. [CHAR LIMIT=30] -->
|
||||
<string name="back_gesture_tutorial_playground_title_swipe_inward_right_edge" translatable="false">Try the back gesture</string>
|
||||
@@ -113,4 +109,10 @@
|
||||
<string name="back_gesture_tutorial_action_button_label" translatable="false">Done</string>
|
||||
<!-- Button text shown on a text button on the confirm screen. [CHAR LIMIT=14] -->
|
||||
<string name="back_gesture_tutorial_action_text_button_label" translatable="false">Settings</string>
|
||||
</resources>
|
||||
|
||||
<!-- ******* Overview ******* -->
|
||||
<!-- Label for a button that causes the current overview app to be shared. [CHAR_LIMIT=40] -->
|
||||
<string name="action_share">Share</string>
|
||||
<!-- Label for a button that causes a screen shot of the current app to be taken. [CHAR_LIMIT=40] -->
|
||||
<string name="action_screenshot">Screenshot</string>
|
||||
</resources>
|
||||
|
||||
@@ -60,4 +60,13 @@
|
||||
parent="TextAppearance.BackGestureTutorial.ButtonLabel">
|
||||
<item name="android:textColor">@color/back_gesture_tutorial_primary_color</item>
|
||||
</style>
|
||||
|
||||
<style name="OverviewActionButton"
|
||||
parent="@android:style/Widget.DeviceDefault.Button.Borderless">
|
||||
<item name="android:textColor">?attr/workspaceTextColor</item>
|
||||
<item name="android:drawableTint">?attr/workspaceTextColor</item>
|
||||
<item name="android:tint">?attr/workspaceTextColor</item>
|
||||
<item name="android:drawablePadding">4dp</item>
|
||||
<item name="android:textAllCaps">false</item>
|
||||
</style>
|
||||
</resources>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<paths xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<cache-path name="shared_images" path="/" />
|
||||
<files-path name="log_files" path="/" />
|
||||
</paths>
|
||||
@@ -34,6 +34,7 @@ import android.content.Intent;
|
||||
import android.content.IntentSender;
|
||||
import android.os.Bundle;
|
||||
import android.os.CancellationSignal;
|
||||
import android.view.View;
|
||||
|
||||
import com.android.launcher3.LauncherState.ScaleAndTranslation;
|
||||
import com.android.launcher3.LauncherStateManager.StateHandler;
|
||||
@@ -43,8 +44,9 @@ import com.android.launcher3.model.WellbeingModel;
|
||||
import com.android.launcher3.popup.SystemShortcut;
|
||||
import com.android.launcher3.proxy.ProxyActivityStarter;
|
||||
import com.android.launcher3.proxy.StartActivityParams;
|
||||
import com.android.launcher3.statehandlers.BackButtonAlphaHandler;
|
||||
import com.android.launcher3.statehandlers.DepthController;
|
||||
import com.android.launcher3.touch.PagedOrientationHandler;
|
||||
import com.android.launcher3.uioverrides.BackButtonAlphaHandler;
|
||||
import com.android.launcher3.uioverrides.RecentsViewStateController;
|
||||
import com.android.launcher3.util.UiThreadHelper;
|
||||
import com.android.quickstep.RecentsModel;
|
||||
@@ -67,6 +69,7 @@ import java.util.stream.Stream;
|
||||
public abstract class BaseQuickstepLauncher extends Launcher
|
||||
implements NavigationModeChangeListener {
|
||||
|
||||
private DepthController mDepthController = new DepthController(this);
|
||||
protected SystemActions mSystemActions;
|
||||
|
||||
/**
|
||||
@@ -78,6 +81,8 @@ public abstract class BaseQuickstepLauncher extends Launcher
|
||||
|
||||
private final ShelfPeekAnim mShelfPeekAnim = new ShelfPeekAnim(this);
|
||||
|
||||
private View mActionsView;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
@@ -222,16 +227,22 @@ public abstract class BaseQuickstepLauncher extends Launcher
|
||||
@Override
|
||||
protected void setupViews() {
|
||||
super.setupViews();
|
||||
mActionsView = findViewById(R.id.overview_actions_view);
|
||||
|
||||
|
||||
if (FeatureFlags.ENABLE_OVERVIEW_ACTIONS.get() && removeShelfFromOverview(this)) {
|
||||
// Overview is above all other launcher elements, including qsb, so move it to the top.
|
||||
getOverviewPanel().bringToFront();
|
||||
if (getActionsView() != null) {
|
||||
getActionsView().bringToFront();
|
||||
if (mActionsView != null) {
|
||||
mActionsView.bringToFront();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public View getActionsView() {
|
||||
return mActionsView;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void closeOpenViews(boolean animate) {
|
||||
super.closeOpenViews(animate);
|
||||
@@ -249,6 +260,10 @@ public abstract class BaseQuickstepLauncher extends Launcher
|
||||
new BackButtonAlphaHandler(this)};
|
||||
}
|
||||
|
||||
public DepthController getDepthController() {
|
||||
return mDepthController;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ScaleAndTranslation getOverviewScaleAndTranslationForNormalState() {
|
||||
if (SysUINavigationMode.getMode(this) == Mode.NO_BUTTON) {
|
||||
@@ -294,6 +309,10 @@ public abstract class BaseQuickstepLauncher extends Launcher
|
||||
onLauncherStateOrFocusChanged();
|
||||
}
|
||||
|
||||
if ((changeBits & ACTIVITY_STATE_STARTED) != 0) {
|
||||
mDepthController.setActivityStarted(isStarted());
|
||||
}
|
||||
|
||||
super.onActivityFlagsChanged(changeBits);
|
||||
}
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ import static com.android.launcher3.anim.Interpolators.EXAGGERATED_EASE;
|
||||
import static com.android.launcher3.anim.Interpolators.LINEAR;
|
||||
import static com.android.launcher3.config.FeatureFlags.KEYGUARD_ANIMATION;
|
||||
import static com.android.launcher3.dragndrop.DragLayer.ALPHA_INDEX_TRANSITIONS;
|
||||
import static com.android.launcher3.uioverrides.DepthController.DEPTH;
|
||||
import static com.android.launcher3.statehandlers.DepthController.DEPTH;
|
||||
import static com.android.launcher3.views.FloatingIconView.SHAPE_PROGRESS_DURATION;
|
||||
import static com.android.quickstep.TaskUtils.taskIsATargetWithMode;
|
||||
import static com.android.systemui.shared.system.QuickStepContract.getWindowCornerRadius;
|
||||
@@ -72,7 +72,7 @@ import com.android.launcher3.allapps.AllAppsTransitionController;
|
||||
import com.android.launcher3.config.FeatureFlags;
|
||||
import com.android.launcher3.dragndrop.DragLayer;
|
||||
import com.android.launcher3.shortcuts.DeepShortcutView;
|
||||
import com.android.launcher3.uioverrides.DepthController;
|
||||
import com.android.launcher3.statehandlers.DepthController;
|
||||
import com.android.launcher3.util.DynamicResource;
|
||||
import com.android.launcher3.util.MultiValueAlpha;
|
||||
import com.android.launcher3.util.MultiValueAlpha.AlphaProperty;
|
||||
@@ -622,7 +622,7 @@ public abstract class QuickstepAppTransitionManagerImpl extends LauncherAppTrans
|
||||
backgroundRadiusAnim.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
depthController.setSurfaceToLauncher(mLauncher.getDragLayer());
|
||||
depthController.setSurfaceToApp(null);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
+4
-1
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.launcher3.uioverrides;
|
||||
package com.android.launcher3.statehandlers;
|
||||
|
||||
import static com.android.launcher3.anim.Interpolators.LINEAR;
|
||||
import static com.android.quickstep.AnimatedFloat.VALUE;
|
||||
@@ -29,6 +29,9 @@ import com.android.quickstep.AnimatedFloat;
|
||||
import com.android.quickstep.SysUINavigationMode;
|
||||
import com.android.quickstep.SystemUiProxy;
|
||||
|
||||
/**
|
||||
* State handler for animating back button alpha
|
||||
*/
|
||||
public class BackButtonAlphaHandler implements LauncherStateManager.StateHandler {
|
||||
|
||||
private final BaseQuickstepLauncher mLauncher;
|
||||
+26
-8
@@ -14,13 +14,14 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.launcher3.uioverrides;
|
||||
package com.android.launcher3.statehandlers;
|
||||
|
||||
import static com.android.launcher3.anim.Interpolators.LINEAR;
|
||||
|
||||
import android.os.IBinder;
|
||||
import android.util.FloatProperty;
|
||||
import android.view.View;
|
||||
import android.view.ViewTreeObserver;
|
||||
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.LauncherState;
|
||||
@@ -77,6 +78,16 @@ public class DepthController implements LauncherStateManager.StateHandler {
|
||||
}
|
||||
}
|
||||
|
||||
private final ViewTreeObserver.OnDrawListener mOnDrawListener =
|
||||
new ViewTreeObserver.OnDrawListener() {
|
||||
@Override
|
||||
public void onDraw() {
|
||||
View view = mLauncher.getDragLayer();
|
||||
setSurface(new SurfaceControlCompat(view));
|
||||
view.post(() -> view.getViewTreeObserver().removeOnDrawListener(this));
|
||||
}
|
||||
};
|
||||
|
||||
private final Launcher mLauncher;
|
||||
/**
|
||||
* Blur radius when completely zoomed out, in pixels.
|
||||
@@ -102,22 +113,29 @@ public class DepthController implements LauncherStateManager.StateHandler {
|
||||
mWallpaperManager = new WallpaperManagerCompat(mLauncher);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets if the underlying activity is started or not
|
||||
*/
|
||||
public void setActivityStarted(boolean isStarted) {
|
||||
if (isStarted) {
|
||||
mLauncher.getDragLayer().getViewTreeObserver().addOnDrawListener(mOnDrawListener);
|
||||
} else {
|
||||
mLauncher.getDragLayer().getViewTreeObserver().removeOnDrawListener(mOnDrawListener);
|
||||
setSurface(null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the specified app target surface to apply the blur to.
|
||||
*/
|
||||
public void setSurfaceToApp(RemoteAnimationTargetCompat target) {
|
||||
if (target != null) {
|
||||
setSurface(target.leash);
|
||||
} else {
|
||||
setActivityStarted(mLauncher.isStarted());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the surface to apply the blur to as the launcher surface.
|
||||
*/
|
||||
public void setSurfaceToLauncher(View v) {
|
||||
setSurface(v != null ? new SurfaceControlCompat(v) : null);
|
||||
}
|
||||
|
||||
private void setSurface(SurfaceControlCompat surface) {
|
||||
if (mSurface != surface) {
|
||||
mSurface = surface;
|
||||
+11
-33
@@ -17,7 +17,6 @@
|
||||
package com.android.launcher3.uioverrides;
|
||||
|
||||
import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
|
||||
import static com.android.launcher3.LauncherAnimUtils.VIEW_ALPHA;
|
||||
import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X;
|
||||
import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y;
|
||||
import static com.android.launcher3.anim.Interpolators.AGGRESSIVE_EASE_IN_OUT;
|
||||
@@ -34,11 +33,10 @@ import static com.android.launcher3.states.StateAnimationConfig.SKIP_OVERVIEW;
|
||||
|
||||
import android.util.FloatProperty;
|
||||
import android.view.View;
|
||||
import android.view.animation.Interpolator;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.BaseQuickstepLauncher;
|
||||
import com.android.launcher3.LauncherState;
|
||||
import com.android.launcher3.LauncherState.ScaleAndTranslation;
|
||||
import com.android.launcher3.LauncherStateManager.StateHandler;
|
||||
@@ -55,13 +53,11 @@ import com.android.launcher3.states.StateAnimationConfig;
|
||||
public abstract class BaseRecentsViewStateController<T extends View>
|
||||
implements StateHandler {
|
||||
protected final T mRecentsView;
|
||||
protected final Launcher mLauncher;
|
||||
protected final View mActionsView;
|
||||
protected final BaseQuickstepLauncher mLauncher;
|
||||
|
||||
public BaseRecentsViewStateController(@NonNull Launcher launcher) {
|
||||
public BaseRecentsViewStateController(@NonNull BaseQuickstepLauncher launcher) {
|
||||
mLauncher = launcher;
|
||||
mRecentsView = launcher.getOverviewPanel();
|
||||
mActionsView = launcher.getActionsView();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -69,19 +65,12 @@ public abstract class BaseRecentsViewStateController<T extends View>
|
||||
ScaleAndTranslation scaleAndTranslation = state
|
||||
.getOverviewScaleAndTranslation(mLauncher);
|
||||
SCALE_PROPERTY.set(mRecentsView, scaleAndTranslation.scale);
|
||||
float translationX = scaleAndTranslation.translationX;
|
||||
if (mRecentsView.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL) {
|
||||
translationX = -translationX;
|
||||
}
|
||||
mRecentsView.setTranslationX(translationX);
|
||||
mRecentsView.setTranslationX(scaleAndTranslation.translationX);
|
||||
mRecentsView.setTranslationY(scaleAndTranslation.translationY);
|
||||
|
||||
getContentAlphaProperty().set(mRecentsView, state.overviewUi ? 1f : 0);
|
||||
OverviewScrim scrim = mLauncher.getDragLayer().getOverviewScrim();
|
||||
SCRIM_PROGRESS.set(scrim, state.getOverviewScrimAlpha(mLauncher));
|
||||
if (mActionsView != null) {
|
||||
mActionsView.setTranslationX(translationX);
|
||||
mActionsView.setAlpha(state.overviewUi ? 1f : 0);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -107,29 +96,18 @@ public abstract class BaseRecentsViewStateController<T extends View>
|
||||
void setStateWithAnimationInternal(@NonNull final LauncherState toState,
|
||||
@NonNull StateAnimationConfig config, @NonNull PendingAnimation setter) {
|
||||
ScaleAndTranslation scaleAndTranslation = toState.getOverviewScaleAndTranslation(mLauncher);
|
||||
Interpolator scaleInterpolator = config.getInterpolator(ANIM_OVERVIEW_SCALE, LINEAR);
|
||||
setter.setFloat(mRecentsView, SCALE_PROPERTY, scaleAndTranslation.scale, scaleInterpolator);
|
||||
Interpolator translateXInterpolator = config.getInterpolator(
|
||||
ANIM_OVERVIEW_TRANSLATE_X, LINEAR);
|
||||
Interpolator translateYInterpolator = config.getInterpolator(
|
||||
ANIM_OVERVIEW_TRANSLATE_Y, LINEAR);
|
||||
float translationX = scaleAndTranslation.translationX;
|
||||
if (mRecentsView.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL) {
|
||||
translationX = -translationX;
|
||||
}
|
||||
setter.setFloat(mRecentsView, VIEW_TRANSLATE_X, translationX, translateXInterpolator);
|
||||
setter.setFloat(mRecentsView, SCALE_PROPERTY, scaleAndTranslation.scale,
|
||||
config.getInterpolator(ANIM_OVERVIEW_SCALE, LINEAR));
|
||||
setter.setFloat(mRecentsView, VIEW_TRANSLATE_X, scaleAndTranslation.translationX,
|
||||
config.getInterpolator(ANIM_OVERVIEW_TRANSLATE_X, LINEAR));
|
||||
setter.setFloat(mRecentsView, VIEW_TRANSLATE_Y, scaleAndTranslation.translationY,
|
||||
translateYInterpolator);
|
||||
config.getInterpolator(ANIM_OVERVIEW_TRANSLATE_Y, LINEAR));
|
||||
|
||||
setter.setFloat(mRecentsView, getContentAlphaProperty(), toState.overviewUi ? 1 : 0,
|
||||
config.getInterpolator(ANIM_OVERVIEW_FADE, AGGRESSIVE_EASE_IN_OUT));
|
||||
OverviewScrim scrim = mLauncher.getDragLayer().getOverviewScrim();
|
||||
setter.setFloat(scrim, SCRIM_PROGRESS, toState.getOverviewScrimAlpha(mLauncher),
|
||||
config.getInterpolator(ANIM_OVERVIEW_SCRIM_FADE, LINEAR));
|
||||
if (mActionsView != null) {
|
||||
setter.setFloat(mActionsView, VIEW_TRANSLATE_X, translationX, translateXInterpolator);
|
||||
setter.setFloat(mActionsView, VIEW_ALPHA, toState.overviewUi ? 1 : 0,
|
||||
config.getInterpolator(ANIM_OVERVIEW_FADE, AGGRESSIVE_EASE_IN_OUT));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -54,6 +54,9 @@ public class DeviceFlag extends DebugFlag {
|
||||
|
||||
@Override
|
||||
public void addChangeListener(Context context, Runnable r) {
|
||||
if (mListeners == null) {
|
||||
initialize(context);
|
||||
}
|
||||
mListeners.add(r);
|
||||
}
|
||||
|
||||
|
||||
@@ -32,8 +32,8 @@ import androidx.annotation.UiThread;
|
||||
import com.android.launcher3.BaseDraggingActivity;
|
||||
import com.android.launcher3.DeviceProfile;
|
||||
import com.android.launcher3.anim.AnimatorPlaybackController;
|
||||
import com.android.launcher3.statehandlers.DepthController;
|
||||
import com.android.launcher3.touch.PagedOrientationHandler;
|
||||
import com.android.launcher3.uioverrides.DepthController;
|
||||
import com.android.quickstep.util.ActivityInitListener;
|
||||
import com.android.quickstep.util.ShelfPeekAnim;
|
||||
import com.android.systemui.shared.recents.model.ThumbnailData;
|
||||
|
||||
@@ -64,6 +64,8 @@ public class GestureState implements RecentsAnimationCallbacks.RecentsAnimationL
|
||||
private static final String TAG = "GestureState";
|
||||
|
||||
private static final ArrayList<String> STATE_NAMES = new ArrayList<>();
|
||||
public static final GestureState DEFAULT_STATE = new GestureState();
|
||||
|
||||
private static int FLAG_COUNT = 0;
|
||||
private static int getFlagForIndex(String name) {
|
||||
if (DEBUG_STATES) {
|
||||
@@ -103,6 +105,10 @@ public class GestureState implements RecentsAnimationCallbacks.RecentsAnimationL
|
||||
public static final int STATE_RECENTS_ANIMATION_ENDED =
|
||||
getFlagForIndex("STATE_RECENTS_ANIMATION_ENDED");
|
||||
|
||||
// Called when RecentsView stops scrolling and settles on a TaskView.
|
||||
public static final int STATE_RECENTS_SCROLLING_FINISHED =
|
||||
getFlagForIndex("STATE_RECENTS_SCROLLING_FINISHED");
|
||||
|
||||
|
||||
// Needed to interact with the current activity
|
||||
private final Intent mHomeIntent;
|
||||
|
||||
@@ -19,11 +19,13 @@ import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
|
||||
|
||||
import android.graphics.Rect;
|
||||
import android.util.ArraySet;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.BinderThread;
|
||||
import androidx.annotation.UiThread;
|
||||
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.testing.TestProtocol;
|
||||
import com.android.launcher3.util.Preconditions;
|
||||
import com.android.systemui.shared.recents.model.ThumbnailData;
|
||||
import com.android.systemui.shared.system.RecentsAnimationControllerCompat;
|
||||
@@ -89,6 +91,9 @@ public class RecentsAnimationCallbacks implements
|
||||
RemoteAnimationTargetCompat[] appTargets,
|
||||
RemoteAnimationTargetCompat[] wallpaperTargets,
|
||||
Rect homeContentInsets, Rect minimizedHomeBounds) {
|
||||
if (TestProtocol.sDebugTracing) {
|
||||
Log.d(TestProtocol.NO_START_FROM_RECENTS, "onAnimationStart");
|
||||
}
|
||||
RecentsAnimationTargets targets = new RecentsAnimationTargets(appTargets,
|
||||
wallpaperTargets, homeContentInsets, minimizedHomeBounds);
|
||||
mController = new RecentsAnimationController(animationController,
|
||||
|
||||
@@ -22,6 +22,7 @@ import static com.android.quickstep.SysUINavigationMode.Mode.THREE_BUTTONS;
|
||||
import static com.android.quickstep.SysUINavigationMode.Mode.TWO_BUTTONS;
|
||||
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_CLICKABLE;
|
||||
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE;
|
||||
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BUBBLES_EXPANDED;
|
||||
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_HOME_DISABLED;
|
||||
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NAV_BAR_HIDDEN;
|
||||
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED;
|
||||
@@ -356,6 +357,7 @@ public class RecentsAnimationDeviceState implements
|
||||
return (mSystemUiStateFlags & SYSUI_STATE_NAV_BAR_HIDDEN) == 0
|
||||
&& (mSystemUiStateFlags & SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED) == 0
|
||||
&& (mSystemUiStateFlags & SYSUI_STATE_QUICK_SETTINGS_EXPANDED) == 0
|
||||
&& (mSystemUiStateFlags & SYSUI_STATE_BUBBLES_EXPANDED) == 0
|
||||
&& ((mSystemUiStateFlags & SYSUI_STATE_HOME_DISABLED) == 0
|
||||
|| (mSystemUiStateFlags & SYSUI_STATE_OVERVIEW_DISABLED) == 0);
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ import androidx.annotation.UiThread;
|
||||
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.config.FeatureFlags;
|
||||
import com.android.launcher3.testing.TestProtocol;
|
||||
import com.android.systemui.shared.recents.model.ThumbnailData;
|
||||
import com.android.systemui.shared.system.ActivityManagerWrapper;
|
||||
|
||||
@@ -52,6 +53,9 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn
|
||||
@UiThread
|
||||
public RecentsAnimationCallbacks startRecentsAnimation(GestureState gestureState,
|
||||
Intent intent, RecentsAnimationCallbacks.RecentsAnimationListener listener) {
|
||||
if (TestProtocol.sDebugTracing) {
|
||||
Log.d(TestProtocol.NO_START_FROM_RECENTS, "startRecentsAnimation");
|
||||
}
|
||||
// Notify if recents animation is still running
|
||||
if (mController != null) {
|
||||
String msg = "New recents animation started before old animation completed";
|
||||
|
||||
@@ -18,36 +18,22 @@ package com.android.quickstep.logging;
|
||||
|
||||
import static android.stats.launcher.nano.Launcher.ALLAPPS;
|
||||
import static android.stats.launcher.nano.Launcher.BACKGROUND;
|
||||
import static android.stats.launcher.nano.Launcher.DISMISS_TASK;
|
||||
import static android.stats.launcher.nano.Launcher.HOME;
|
||||
import static android.stats.launcher.nano.Launcher.LAUNCH_APP;
|
||||
import static android.stats.launcher.nano.Launcher.LAUNCH_TASK;
|
||||
import static android.stats.launcher.nano.Launcher.OVERVIEW;
|
||||
|
||||
import static com.android.launcher3.logging.UserEventDispatcher.makeTargetsList;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.UserHandle;
|
||||
import android.stats.launcher.nano.Launcher;
|
||||
import android.stats.launcher.nano.LauncherExtension;
|
||||
import android.stats.launcher.nano.LauncherTarget;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.android.launcher3.FolderInfo;
|
||||
import com.android.launcher3.ItemInfo;
|
||||
import com.android.launcher3.LauncherAppState;
|
||||
import com.android.launcher3.LauncherAppWidgetInfo;
|
||||
import com.android.launcher3.logger.LauncherAtom;
|
||||
import com.android.launcher3.logging.StatsLogManager;
|
||||
import com.android.launcher3.logging.StatsLogUtils;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto.ControlType;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto.ItemType;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
|
||||
import com.android.launcher3.util.ComponentKey;
|
||||
import com.android.systemui.shared.system.SysUiStatsLog;
|
||||
|
||||
import com.google.protobuf.nano.MessageNano;
|
||||
import com.android.launcher3.model.AllAppsList;
|
||||
import com.android.launcher3.model.BaseModelUpdateTask;
|
||||
import com.android.launcher3.model.BgDataModel;
|
||||
import com.android.launcher3.util.IntSparseArrayMap;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
@@ -62,186 +48,17 @@ import java.util.ArrayList;
|
||||
public class StatsLogCompatManager extends StatsLogManager {
|
||||
|
||||
private static final int SUPPORTED_TARGET_DEPTH = 2;
|
||||
private static final String TAG = "StatsLogCompatManager";
|
||||
private static final String TAG = "StatsLog";
|
||||
private static final boolean DEBUG = false;
|
||||
private static Context sContext;
|
||||
|
||||
public StatsLogCompatManager(Context context) {
|
||||
sContext = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void logAppLaunch(View v, Intent intent, @Nullable UserHandle userHandle) {
|
||||
LauncherExtension ext = new LauncherExtension();
|
||||
ext.srcTarget = new LauncherTarget[SUPPORTED_TARGET_DEPTH];
|
||||
int srcState = mStateProvider.getCurrentState();
|
||||
fillInLauncherExtension(v, ext);
|
||||
if (ext.srcTarget[0] != null) {
|
||||
ext.srcTarget[0].item = LauncherTarget.APP_ICON;
|
||||
}
|
||||
SysUiStatsLog.write(SysUiStatsLog.LAUNCHER_EVENT, LAUNCH_APP, srcState,
|
||||
BACKGROUND /* dstState */, MessageNano.toByteArray(ext), true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void logTaskLaunch(View v, ComponentKey componentKey) {
|
||||
LauncherExtension ext = new LauncherExtension();
|
||||
ext.srcTarget = new LauncherTarget[SUPPORTED_TARGET_DEPTH];
|
||||
int srcState = OVERVIEW;
|
||||
fillInLauncherExtension(v, ext);
|
||||
SysUiStatsLog.write(SysUiStatsLog.LAUNCHER_EVENT, LAUNCH_TASK, srcState,
|
||||
BACKGROUND /* dstState */, MessageNano.toByteArray(ext), true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void logTaskDismiss(View v, ComponentKey componentKey) {
|
||||
LauncherExtension ext = new LauncherExtension();
|
||||
ext.srcTarget = new LauncherTarget[SUPPORTED_TARGET_DEPTH];
|
||||
int srcState = OVERVIEW;
|
||||
fillInLauncherExtension(v, ext);
|
||||
SysUiStatsLog.write(SysUiStatsLog.LAUNCHER_EVENT, DISMISS_TASK, srcState,
|
||||
BACKGROUND /* dstState */, MessageNano.toByteArray(ext), true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void logSwipeOnContainer(boolean isSwipingToLeft, int pageId) {
|
||||
LauncherExtension ext = new LauncherExtension();
|
||||
ext.srcTarget = new LauncherTarget[1];
|
||||
int srcState = mStateProvider.getCurrentState();
|
||||
fillInLauncherExtensionWithPageId(ext, pageId);
|
||||
int launcherAction = isSwipingToLeft ? Launcher.SWIPE_LEFT : Launcher.SWIPE_RIGHT;
|
||||
SysUiStatsLog.write(SysUiStatsLog.LAUNCHER_EVENT, launcherAction, srcState, srcState,
|
||||
MessageNano.toByteArray(ext), true);
|
||||
}
|
||||
|
||||
public static boolean fillInLauncherExtension(View v, LauncherExtension extension) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "fillInLauncherExtension");
|
||||
}
|
||||
|
||||
StatsLogUtils.LogContainerProvider provider = StatsLogUtils.getLaunchProviderRecursive(v);
|
||||
if (v == null || !(v.getTag() instanceof ItemInfo) || provider == null) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "View or provider is null, or view doesn't have an ItemInfo tag.");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
Target child = new Target();
|
||||
ArrayList<Target> targets = makeTargetsList(child);
|
||||
targets.add(child);
|
||||
provider.fillInLogContainerData((ItemInfo) v.getTag(), child, targets);
|
||||
|
||||
int maxDepth = Math.min(SUPPORTED_TARGET_DEPTH, targets.size());
|
||||
extension.srcTarget = new LauncherTarget[maxDepth];
|
||||
for (int i = 0; i < maxDepth; i++) {
|
||||
extension.srcTarget[i] = new LauncherTarget();
|
||||
copy(targets.get(i), extension.srcTarget[i]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean fillInLauncherExtensionWithPageId(LauncherExtension ext, int pageId) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "fillInLauncherExtensionWithPageId, pageId = " + pageId);
|
||||
}
|
||||
|
||||
Target target = new Target();
|
||||
target.pageIndex = pageId;
|
||||
ext.srcTarget[0] = new LauncherTarget();
|
||||
copy(target, ext.srcTarget[0]);
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void copy(Target src, LauncherTarget dst) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "copy target information from clearcut Target to LauncherTarget.");
|
||||
}
|
||||
|
||||
// Fill in type
|
||||
switch (src.type) {
|
||||
case Target.Type.ITEM:
|
||||
dst.type = LauncherTarget.ITEM_TYPE;
|
||||
break;
|
||||
case Target.Type.CONTROL:
|
||||
dst.type = LauncherTarget.CONTROL_TYPE;
|
||||
break;
|
||||
case Target.Type.CONTAINER:
|
||||
dst.type = LauncherTarget.CONTAINER_TYPE;
|
||||
break;
|
||||
default:
|
||||
dst.type = LauncherTarget.NONE;
|
||||
break;
|
||||
}
|
||||
|
||||
// Fill in item
|
||||
switch (src.itemType) {
|
||||
case ItemType.APP_ICON:
|
||||
dst.item = LauncherTarget.APP_ICON;
|
||||
break;
|
||||
case ItemType.SHORTCUT:
|
||||
dst.item = LauncherTarget.SHORTCUT;
|
||||
break;
|
||||
case ItemType.WIDGET:
|
||||
dst.item = LauncherTarget.WIDGET;
|
||||
break;
|
||||
case ItemType.FOLDER_ICON:
|
||||
dst.item = LauncherTarget.FOLDER_ICON;
|
||||
break;
|
||||
case ItemType.DEEPSHORTCUT:
|
||||
dst.item = LauncherTarget.DEEPSHORTCUT;
|
||||
break;
|
||||
case ItemType.SEARCHBOX:
|
||||
dst.item = LauncherTarget.SEARCHBOX;
|
||||
break;
|
||||
case ItemType.EDITTEXT:
|
||||
dst.item = LauncherTarget.EDITTEXT;
|
||||
break;
|
||||
case ItemType.NOTIFICATION:
|
||||
dst.item = LauncherTarget.NOTIFICATION;
|
||||
break;
|
||||
case ItemType.TASK:
|
||||
dst.item = LauncherTarget.TASK;
|
||||
break;
|
||||
default:
|
||||
dst.item = LauncherTarget.DEFAULT_ITEM;
|
||||
break;
|
||||
}
|
||||
|
||||
// Fill in container
|
||||
switch (src.containerType) {
|
||||
case ContainerType.HOTSEAT:
|
||||
dst.container = LauncherTarget.HOTSEAT;
|
||||
break;
|
||||
case ContainerType.FOLDER:
|
||||
dst.container = LauncherTarget.FOLDER;
|
||||
break;
|
||||
case ContainerType.PREDICTION:
|
||||
dst.container = LauncherTarget.PREDICTION;
|
||||
break;
|
||||
case ContainerType.SEARCHRESULT:
|
||||
dst.container = LauncherTarget.SEARCHRESULT;
|
||||
break;
|
||||
default:
|
||||
dst.container = LauncherTarget.DEFAULT_CONTAINER;
|
||||
break;
|
||||
}
|
||||
|
||||
// Fill in control
|
||||
switch (src.controlType) {
|
||||
case ControlType.UNINSTALL_TARGET:
|
||||
dst.control = LauncherTarget.UNINSTALL;
|
||||
break;
|
||||
case ControlType.REMOVE_TARGET:
|
||||
dst.control = LauncherTarget.REMOVE;
|
||||
break;
|
||||
default:
|
||||
dst.control = LauncherTarget.DEFAULT_CONTROL;
|
||||
break;
|
||||
}
|
||||
|
||||
// Fill in other fields
|
||||
dst.pageId = src.pageIndex;
|
||||
dst.gridX = src.gridX;
|
||||
dst.gridY = src.gridY;
|
||||
public void log(LauncherEvent eventId, LauncherAtom.ItemInfo item) {
|
||||
// Call StatsLog method
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -254,4 +71,36 @@ public class StatsLogCompatManager extends StatsLogManager {
|
||||
"StatsLogUtil constants doesn't match enums in launcher.proto");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs the workspace layout information on the model thread.
|
||||
*/
|
||||
public void logSnapshot() {
|
||||
LauncherAppState.getInstance(sContext).getModel().enqueueModelUpdateTask(
|
||||
new SnapshotWorker());
|
||||
}
|
||||
|
||||
private class SnapshotWorker extends BaseModelUpdateTask {
|
||||
@Override
|
||||
public void execute(LauncherAppState app, BgDataModel dataModel, AllAppsList apps) {
|
||||
IntSparseArrayMap<FolderInfo> folders = dataModel.folders.clone();
|
||||
ArrayList<ItemInfo> workspaceItems = (ArrayList) dataModel.workspaceItems.clone();
|
||||
ArrayList<LauncherAppWidgetInfo> appWidgets = (ArrayList) dataModel.appWidgets.clone();
|
||||
|
||||
for (ItemInfo info : workspaceItems) {
|
||||
LauncherAtom.ItemInfo atomInfo = info.buildProto(null, null);
|
||||
// call StatsLog method
|
||||
}
|
||||
for (FolderInfo fInfo : folders) {
|
||||
for (ItemInfo info : fInfo.contents) {
|
||||
LauncherAtom.ItemInfo atomInfo = info.buildProto(null, fInfo);
|
||||
// call StatsLog method
|
||||
}
|
||||
}
|
||||
for (ItemInfo info : appWidgets) {
|
||||
LauncherAtom.ItemInfo atomInfo = info.buildProto(null, null);
|
||||
// call StatsLog method
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
* 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.quickstep.util;
|
||||
|
||||
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
|
||||
import static android.content.Intent.FLAG_GRANT_READ_URI_PERMISSION;
|
||||
|
||||
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
|
||||
|
||||
import android.content.ClipData;
|
||||
import android.content.ClipDescription;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Insets;
|
||||
import android.graphics.Picture;
|
||||
import android.graphics.Rect;
|
||||
import android.net.Uri;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.UiThread;
|
||||
import androidx.annotation.WorkerThread;
|
||||
import androidx.core.content.FileProvider;
|
||||
|
||||
import com.android.launcher3.BuildConfig;
|
||||
import com.android.quickstep.SystemUiProxy;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* Utility class containing methods to help manage image actions such as sharing, cropping, and
|
||||
* saving image.
|
||||
*/
|
||||
public class ImageActionUtils {
|
||||
|
||||
private static final String AUTHORITY = BuildConfig.APPLICATION_ID + ".overview.fileprovider";
|
||||
|
||||
/**
|
||||
* Saves screenshot to location determine by SystemUiProxy
|
||||
*/
|
||||
public static void saveScreenshot(SystemUiProxy systemUiProxy, Bitmap screenshot,
|
||||
Rect screenshotBounds,
|
||||
Insets visibleInsets, int taskId) {
|
||||
systemUiProxy.handleImageAsScreenshot(screenshot, screenshotBounds, visibleInsets, taskId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Launch the activity to share image.
|
||||
*/
|
||||
@UiThread
|
||||
public static void startShareActivity(Context context, Supplier<Bitmap> bitmapSupplier,
|
||||
Rect crop, Intent intent, String tag) {
|
||||
if (bitmapSupplier.get() == null) {
|
||||
Log.e(tag, "No snapshot available, not starting share.");
|
||||
return;
|
||||
}
|
||||
|
||||
UI_HELPER_EXECUTOR.execute(() -> persistBitmapAndStartActivity(context,
|
||||
bitmapSupplier.get(), crop, intent, ImageActionUtils::getShareIntentForImageUri,
|
||||
tag));
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts activity based on given intent created from image uri.
|
||||
*/
|
||||
@WorkerThread
|
||||
public static void persistBitmapAndStartActivity(Context context, Bitmap bitmap, Rect crop,
|
||||
Intent intent, BiFunction<Uri, Intent, Intent[]> uriToIntentMap, String tag) {
|
||||
context.startActivities(
|
||||
uriToIntentMap.apply(getImageUri(bitmap, crop, context, tag), intent));
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts image bitmap to Uri by temporarily saving bitmap to cache, and creating Uri pointing
|
||||
* to that location. Used to be able to share an image with another app.
|
||||
*
|
||||
* @param bitmap The whole bitmap to be shared.
|
||||
* @param crop The section of the bitmap to be shared.
|
||||
* @param context The application context, used to interact with file system.
|
||||
* @param tag Tag used to log errors.
|
||||
* @return Uri that points to the cropped version of desired bitmap to share.
|
||||
*/
|
||||
@WorkerThread
|
||||
public static Uri getImageUri(Bitmap bitmap, Rect crop, Context context, String tag) {
|
||||
Bitmap croppedBitmap = cropBitmap(bitmap, crop);
|
||||
int cropHash = crop == null ? 0 : crop.hashCode();
|
||||
String baseName = "image_" + bitmap.hashCode() + "_" + cropHash + ".png";
|
||||
File file = new File(context.getCacheDir(), baseName);
|
||||
|
||||
try (FileOutputStream fos = new FileOutputStream(file)) {
|
||||
croppedBitmap.compress(Bitmap.CompressFormat.PNG, 100, fos);
|
||||
} catch (IOException e) {
|
||||
Log.e(tag, "Error saving image", e);
|
||||
}
|
||||
|
||||
return FileProvider.getUriForFile(context, AUTHORITY, file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Crops the bitmap to the provided size and returns a software backed bitmap whenever possible.
|
||||
*
|
||||
* @param bitmap The bitmap to be cropped.
|
||||
* @param crop The section of the bitmap in the crop.
|
||||
* @return The cropped bitmap.
|
||||
*/
|
||||
@WorkerThread
|
||||
public static Bitmap cropBitmap(Bitmap bitmap, Rect crop) {
|
||||
Rect src = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
|
||||
if (crop == null) {
|
||||
crop = new Rect(src);
|
||||
}
|
||||
if (crop.equals(src)) {
|
||||
return bitmap;
|
||||
} else {
|
||||
if (bitmap.getConfig() != Bitmap.Config.HARDWARE) {
|
||||
return Bitmap.createBitmap(bitmap, crop.left, crop.top, crop.width(),
|
||||
crop.height());
|
||||
}
|
||||
|
||||
// For hardware bitmaps, use the Picture API to directly create a software bitmap
|
||||
Picture picture = new Picture();
|
||||
Canvas canvas = picture.beginRecording(crop.width(), crop.height());
|
||||
canvas.drawBitmap(bitmap, -crop.left, -crop.top, null);
|
||||
picture.endRecording();
|
||||
return Bitmap.createBitmap(picture, crop.width(), crop.height(),
|
||||
Bitmap.Config.ARGB_8888);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the intent used to share image.
|
||||
*/
|
||||
@WorkerThread
|
||||
private static Intent[] getShareIntentForImageUri(Uri uri, Intent intent) {
|
||||
if (intent == null) {
|
||||
intent = new Intent();
|
||||
}
|
||||
ClipData clipdata = new ClipData(new ClipDescription("content",
|
||||
new String[]{ClipDescription.MIMETYPE_TEXT_PLAIN}),
|
||||
new ClipData.Item(uri));
|
||||
intent.setAction(Intent.ACTION_SEND)
|
||||
.setComponent(null)
|
||||
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
.setType("image/png")
|
||||
.setFlags(FLAG_GRANT_READ_URI_PERMISSION)
|
||||
.putExtra(Intent.EXTRA_STREAM, uri)
|
||||
.setClipData(clipdata);
|
||||
return new Intent[]{Intent.createChooser(intent, null).addFlags(FLAG_ACTIVITY_NEW_TASK)};
|
||||
}
|
||||
}
|
||||
@@ -88,7 +88,6 @@ public class AppPredictionsUITests extends AbstractQuickStepTest {
|
||||
*/
|
||||
@Test
|
||||
public void testPredictionExistsInAllApps() {
|
||||
mDevice.pressHome();
|
||||
mLauncher.pressHome().switchToAllApps();
|
||||
|
||||
// Dispatch an update
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 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.
|
||||
-->
|
||||
<com.android.launcher3.graphics.ShadowDrawable
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:src="@drawable/ic_block_no_shadow"
|
||||
android:elevation="@dimen/drop_target_shadow_elevation" />
|
||||
+1
-1
@@ -50,7 +50,7 @@
|
||||
android:src="@drawable/ic_remove_no_shadow"
|
||||
android:tint="@android:color/white"
|
||||
android:background="?android:attr/selectableItemBackgroundBorderless"
|
||||
android:contentDescription="@string/accessibility_close_task"/>
|
||||
android:contentDescription="@string/accessibility_close"/>
|
||||
</LinearLayout>
|
||||
|
||||
<View
|
||||
@@ -34,5 +34,4 @@
|
||||
android:singleLine="true"
|
||||
android:textColor="?android:attr/textColorSecondary"
|
||||
android:textColorHint="@drawable/all_apps_search_hint"
|
||||
android:textSize="16sp"
|
||||
android:translationY="24dp" />
|
||||
android:textSize="16sp" />
|
||||
@@ -20,7 +20,7 @@
|
||||
android:gravity="center">
|
||||
|
||||
<TextView
|
||||
style="@style/TextHeadline"
|
||||
style="@style/PrimaryMediumText"
|
||||
android:textColor="?attr/workProfileOverlayTextColor"
|
||||
android:id="@+id/work_apps_paused_title"
|
||||
android:layout_width="wrap_content"
|
||||
|
||||
@@ -85,6 +85,10 @@
|
||||
<dimen name="all_apps_tabs_side_padding">12dp</dimen>
|
||||
<dimen name="all_apps_divider_height">1dp</dimen>
|
||||
|
||||
<dimen name="all_apps_tip_bottom_margin">8dp</dimen>
|
||||
<!-- The size of corner radius of the arrow in the arrow toast. -->
|
||||
<dimen name="arrow_toast_corner_radius">2dp</dimen>
|
||||
|
||||
<dimen name="all_apps_work_profile_tab_footer_padding">20dp</dimen>
|
||||
|
||||
<!-- Search bar in All Apps -->
|
||||
|
||||
@@ -17,4 +17,5 @@
|
||||
<drawable name="ic_setup_shadow">@drawable/ic_setting</drawable>
|
||||
<drawable name="ic_remove_shadow">@drawable/ic_remove_no_shadow</drawable>
|
||||
<drawable name="ic_uninstall_shadow">@drawable/ic_uninstall_no_shadow</drawable>
|
||||
<drawable name="ic_block_shadow">@drawable/ic_block_no_shadow</drawable>
|
||||
</resources>
|
||||
@@ -316,6 +316,9 @@
|
||||
<!-- Accessibility action to dismiss a notification in the shortcuts menu for an icon. [CHAR_LIMIT=30] -->
|
||||
<string name="action_dismiss_notification">Dismiss</string>
|
||||
|
||||
<!-- Content description for arrow tip close button. [CHAR LIMIT=NONE] -->
|
||||
<string name="accessibility_close">Close</string>
|
||||
|
||||
<!-- Accessibility confirmation for notification being dismissed. -->
|
||||
<string name="notification_dismissed">Notification dismissed</string>
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.android.launcher3;
|
||||
|
||||
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.APP_LAUNCH_TAP;
|
||||
import static com.android.launcher3.util.DefaultDisplay.CHANGE_ROTATION;
|
||||
|
||||
import android.app.ActivityOptions;
|
||||
@@ -181,7 +182,7 @@ public abstract class BaseDraggingActivity extends BaseActivity
|
||||
sourceContainer);
|
||||
}
|
||||
getUserEventDispatcher().logAppLaunch(v, intent, user);
|
||||
getStatsLogManager().logAppLaunch(v, intent, user);
|
||||
getStatsLogManager().log(APP_LAUNCH_TAP, item.buildProto(null, null));
|
||||
return true;
|
||||
} catch (NullPointerException|ActivityNotFoundException|SecurityException e) {
|
||||
Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.android.launcher3;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
@@ -25,6 +26,7 @@ import android.view.ViewGroup;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.android.launcher3.compat.AccessibilityManagerCompat;
|
||||
import com.android.launcher3.testing.TestProtocol;
|
||||
import com.android.launcher3.views.RecyclerViewFastScroller;
|
||||
|
||||
|
||||
@@ -177,6 +179,10 @@ public abstract class BaseRecyclerView extends RecyclerView {
|
||||
public void onScrollStateChanged(int state) {
|
||||
super.onScrollStateChanged(state);
|
||||
|
||||
if (TestProtocol.sDebugTracing) {
|
||||
Log.d(TestProtocol.NO_SCROLL_END_WIDGETS, "onScrollStateChanged: " + state);
|
||||
}
|
||||
|
||||
if (state == SCROLL_STATE_IDLE) {
|
||||
AccessibilityManagerCompat.sendScrollFinishedEventToTest(getContext());
|
||||
}
|
||||
|
||||
@@ -39,7 +39,6 @@ import android.util.TypedValue;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewConfiguration;
|
||||
import android.view.ViewDebug;
|
||||
import android.widget.TextView;
|
||||
|
||||
@@ -109,8 +108,6 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver,
|
||||
private final int mDisplay;
|
||||
|
||||
private final CheckLongPressHelper mLongPressHelper;
|
||||
private final StylusEventHelper mStylusEventHelper;
|
||||
private final float mSlop;
|
||||
|
||||
private final boolean mLayoutHorizontal;
|
||||
private final int mIconSize;
|
||||
@@ -137,9 +134,6 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver,
|
||||
@ViewDebug.ExportedProperty(category = "launcher")
|
||||
private boolean mDisableRelayout = false;
|
||||
|
||||
@ViewDebug.ExportedProperty(category = "launcher")
|
||||
private final boolean mIgnorePaddingTouch;
|
||||
|
||||
private IconLoadRequest mIconLoadRequest;
|
||||
|
||||
public BubbleTextView(Context context) {
|
||||
@@ -153,7 +147,6 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver,
|
||||
public BubbleTextView(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
mActivity = ActivityContext.lookupContext(context);
|
||||
mSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
|
||||
|
||||
TypedArray a = context.obtainStyledAttributes(attrs,
|
||||
R.styleable.BubbleTextView, defStyle, 0);
|
||||
@@ -166,23 +159,19 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver,
|
||||
setTextSize(TypedValue.COMPLEX_UNIT_PX, grid.iconTextSizePx);
|
||||
setCompoundDrawablePadding(grid.iconDrawablePaddingPx);
|
||||
defaultIconSize = grid.iconSizePx;
|
||||
mIgnorePaddingTouch = true;
|
||||
} else if (mDisplay == DISPLAY_ALL_APPS) {
|
||||
DeviceProfile grid = mActivity.getDeviceProfile();
|
||||
setTextSize(TypedValue.COMPLEX_UNIT_PX, grid.allAppsIconTextSizePx);
|
||||
setCompoundDrawablePadding(grid.allAppsIconDrawablePaddingPx);
|
||||
defaultIconSize = grid.allAppsIconSizePx;
|
||||
mIgnorePaddingTouch = true;
|
||||
} else if (mDisplay == DISPLAY_FOLDER) {
|
||||
DeviceProfile grid = mActivity.getDeviceProfile();
|
||||
setTextSize(TypedValue.COMPLEX_UNIT_PX, grid.folderChildTextSizePx);
|
||||
setCompoundDrawablePadding(grid.folderChildDrawablePaddingPx);
|
||||
defaultIconSize = grid.folderChildIconSizePx;
|
||||
mIgnorePaddingTouch = true;
|
||||
} else {
|
||||
// widget_selection or shortcut_popup
|
||||
defaultIconSize = mActivity.getDeviceProfile().iconSizePx;
|
||||
mIgnorePaddingTouch = false;
|
||||
}
|
||||
|
||||
mCenterVertically = a.getBoolean(R.styleable.BubbleTextView_centerVertically, false);
|
||||
@@ -192,7 +181,6 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver,
|
||||
a.recycle();
|
||||
|
||||
mLongPressHelper = new CheckLongPressHelper(this);
|
||||
mStylusEventHelper = new StylusEventHelper(new SimpleOnStylusPressListener(this), this);
|
||||
|
||||
mDotParams = new DotRenderer.DrawParams();
|
||||
|
||||
@@ -333,42 +321,21 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver,
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
// ignore events if they happen in padding area
|
||||
if (event.getAction() == MotionEvent.ACTION_DOWN && mIgnorePaddingTouch
|
||||
if (event.getAction() == MotionEvent.ACTION_DOWN
|
||||
&& (event.getY() < getPaddingTop()
|
||||
|| event.getX() < getPaddingLeft()
|
||||
|| event.getY() > getHeight() - getPaddingBottom()
|
||||
|| event.getX() > getWidth() - getPaddingRight())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Call the superclass onTouchEvent first, because sometimes it changes the state to
|
||||
// isPressed() on an ACTION_UP
|
||||
boolean result = super.onTouchEvent(event);
|
||||
|
||||
// Check for a stylus button press, if it occurs cancel any long press checks.
|
||||
if (mStylusEventHelper.onMotionEvent(event)) {
|
||||
mLongPressHelper.cancelLongPress();
|
||||
result = true;
|
||||
if (isLongClickable()) {
|
||||
super.onTouchEvent(event);
|
||||
mLongPressHelper.onTouchEvent(event);
|
||||
// Keep receiving the rest of the events
|
||||
return true;
|
||||
} else {
|
||||
return super.onTouchEvent(event);
|
||||
}
|
||||
|
||||
switch (event.getAction()) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
// If we're in a stylus button press, don't check for long press.
|
||||
if (!mStylusEventHelper.inStylusButtonPressed()) {
|
||||
mLongPressHelper.postCheckForLongPress();
|
||||
}
|
||||
break;
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
case MotionEvent.ACTION_UP:
|
||||
mLongPressHelper.cancelLongPress();
|
||||
break;
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
if (!Utilities.pointInView(this, event.getX(), event.getY(), mSlop)) {
|
||||
mLongPressHelper.cancelLongPress();
|
||||
}
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void setStayPressed(boolean stayPressed) {
|
||||
@@ -531,7 +498,6 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver,
|
||||
@Override
|
||||
public void cancelLongPress() {
|
||||
super.cancelLongPress();
|
||||
|
||||
mLongPressHelper.cancelLongPress();
|
||||
}
|
||||
|
||||
|
||||
@@ -16,46 +16,68 @@
|
||||
|
||||
package com.android.launcher3;
|
||||
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewConfiguration;
|
||||
|
||||
import com.android.launcher3.util.Thunk;
|
||||
|
||||
/**
|
||||
* Utility class to handle tripper long press on a view with custom timeout and stylus event
|
||||
*/
|
||||
public class CheckLongPressHelper {
|
||||
|
||||
public static final float DEFAULT_LONG_PRESS_TIMEOUT_FACTOR = 0.75f;
|
||||
|
||||
@Thunk View mView;
|
||||
@Thunk View.OnLongClickListener mListener;
|
||||
@Thunk boolean mHasPerformedLongPress;
|
||||
private float mLongPressTimeoutFactor = DEFAULT_LONG_PRESS_TIMEOUT_FACTOR;
|
||||
private CheckForLongPress mPendingCheckForLongPress;
|
||||
private final View mView;
|
||||
private final View.OnLongClickListener mListener;
|
||||
private final float mSlop;
|
||||
|
||||
class CheckForLongPress implements Runnable {
|
||||
public void run() {
|
||||
if ((mView.getParent() != null) && mView.hasWindowFocus()
|
||||
&& !mHasPerformedLongPress) {
|
||||
boolean handled;
|
||||
if (mListener != null) {
|
||||
handled = mListener.onLongClick(mView);
|
||||
} else {
|
||||
handled = mView.performLongClick();
|
||||
}
|
||||
if (handled) {
|
||||
mView.setPressed(false);
|
||||
mHasPerformedLongPress = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
private float mLongPressTimeoutFactor = DEFAULT_LONG_PRESS_TIMEOUT_FACTOR;
|
||||
|
||||
private boolean mHasPerformedLongPress;
|
||||
|
||||
private Runnable mPendingCheckForLongPress;
|
||||
|
||||
public CheckLongPressHelper(View v) {
|
||||
mView = v;
|
||||
this(v, null);
|
||||
}
|
||||
|
||||
public CheckLongPressHelper(View v, View.OnLongClickListener listener) {
|
||||
mView = v;
|
||||
mListener = listener;
|
||||
mSlop = ViewConfiguration.get(mView.getContext()).getScaledTouchSlop();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the touch event on a view
|
||||
*
|
||||
* @see View#onTouchEvent(MotionEvent)
|
||||
*/
|
||||
public void onTouchEvent(MotionEvent ev) {
|
||||
switch (ev.getAction()) {
|
||||
case MotionEvent.ACTION_DOWN: {
|
||||
// Just in case the previous long press hasn't been cleared, we make sure to
|
||||
// start fresh on touch down.
|
||||
cancelLongPress();
|
||||
|
||||
postCheckForLongPress();
|
||||
if (isStylusButtonPressed(ev)) {
|
||||
triggerLongPress();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
case MotionEvent.ACTION_UP:
|
||||
cancelLongPress();
|
||||
break;
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
if (!Utilities.pointInView(mView, ev.getX(), ev.getY(), mSlop)) {
|
||||
cancelLongPress();
|
||||
} else if (mPendingCheckForLongPress != null && isStylusButtonPressed(ev)) {
|
||||
// Only trigger long press if it has not been cancelled before
|
||||
triggerLongPress();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -65,25 +87,64 @@ public class CheckLongPressHelper {
|
||||
mLongPressTimeoutFactor = longPressTimeoutFactor;
|
||||
}
|
||||
|
||||
public void postCheckForLongPress() {
|
||||
private void postCheckForLongPress() {
|
||||
mHasPerformedLongPress = false;
|
||||
|
||||
if (mPendingCheckForLongPress == null) {
|
||||
mPendingCheckForLongPress = new CheckForLongPress();
|
||||
mPendingCheckForLongPress = this::triggerLongPress;
|
||||
}
|
||||
mView.postDelayed(mPendingCheckForLongPress,
|
||||
(long) (ViewConfiguration.getLongPressTimeout() * mLongPressTimeoutFactor));
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancels any pending long press
|
||||
*/
|
||||
public void cancelLongPress() {
|
||||
mHasPerformedLongPress = false;
|
||||
clearCallbacks();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if long press has been performed in the current touch gesture
|
||||
*/
|
||||
public boolean hasPerformedLongPress() {
|
||||
return mHasPerformedLongPress;
|
||||
}
|
||||
|
||||
private void triggerLongPress() {
|
||||
if ((mView.getParent() != null) && mView.hasWindowFocus() && !mHasPerformedLongPress) {
|
||||
boolean handled;
|
||||
if (mListener != null) {
|
||||
handled = mListener.onLongClick(mView);
|
||||
} else {
|
||||
handled = mView.performLongClick();
|
||||
}
|
||||
if (handled) {
|
||||
mView.setPressed(false);
|
||||
mHasPerformedLongPress = true;
|
||||
}
|
||||
clearCallbacks();
|
||||
}
|
||||
}
|
||||
|
||||
private void clearCallbacks() {
|
||||
if (mPendingCheckForLongPress != null) {
|
||||
mView.removeCallbacks(mPendingCheckForLongPress);
|
||||
mPendingCheckForLongPress = null;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasPerformedLongPress() {
|
||||
return mHasPerformedLongPress;
|
||||
|
||||
/**
|
||||
* Identifies if the provided {@link MotionEvent} is a stylus with the primary stylus button
|
||||
* pressed.
|
||||
*
|
||||
* @param event The event to check.
|
||||
* @return Whether a stylus button press occurred.
|
||||
*/
|
||||
private static boolean isStylusButtonPressed(MotionEvent event) {
|
||||
return event.getToolType(0) == MotionEvent.TOOL_TYPE_STYLUS
|
||||
&& event.isButtonPressed(MotionEvent.BUTTON_SECONDARY);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,13 @@
|
||||
|
||||
package com.android.launcher3;
|
||||
|
||||
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_DESKTOP;
|
||||
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT;
|
||||
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_DEEP_SHORTCUT;
|
||||
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Intent;
|
||||
@@ -24,13 +31,17 @@ import android.os.UserHandle;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.android.launcher3.logger.LauncherAtom;
|
||||
import com.android.launcher3.util.ContentWriter;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Represents an item in the launcher.
|
||||
*/
|
||||
public class ItemInfo {
|
||||
|
||||
public static final boolean DEBUG = true;
|
||||
public static final int NO_ID = -1;
|
||||
|
||||
/**
|
||||
@@ -190,6 +201,7 @@ public class ItemInfo {
|
||||
return "id=" + id
|
||||
+ " type=" + LauncherSettings.Favorites.itemTypeToString(itemType)
|
||||
+ " container=" + LauncherSettings.Favorites.containerToString((int)container)
|
||||
+ " targetComponent=" + getTargetComponent()
|
||||
+ " screen=" + screenId
|
||||
+ " cell(" + cellX + "," + cellY + ")"
|
||||
+ " span(" + spanX + "," + spanY + ")"
|
||||
@@ -221,4 +233,70 @@ public class ItemInfo {
|
||||
return container == LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION
|
||||
|| container == LauncherSettings.Favorites.CONTAINER_PREDICTION;
|
||||
}
|
||||
|
||||
/**
|
||||
* Can be overridden by inherited classes to fill in {@link LauncherAtom.ItemInfo}
|
||||
*/
|
||||
public void setItemBuilder(LauncherAtom.ItemInfo.Builder builder) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates {@link LauncherAtom.ItemInfo} with important fields and parent container info.
|
||||
*/
|
||||
public LauncherAtom.ItemInfo buildProto(Intent intent, FolderInfo fInfo) {
|
||||
|
||||
LauncherAtom.ItemInfo.Builder itemBuilder = LauncherAtom.ItemInfo.newBuilder();
|
||||
itemBuilder.setIsWork(user != Process.myUserHandle());
|
||||
ComponentName cn = getTargetComponent();
|
||||
switch (itemType) {
|
||||
case ITEM_TYPE_APPLICATION:
|
||||
itemBuilder.setApplication(LauncherAtom.Application.newBuilder()
|
||||
.setComponentName(cn.flattenToShortString())
|
||||
.setPackageName(cn.getPackageName()));
|
||||
break;
|
||||
case ITEM_TYPE_DEEP_SHORTCUT:
|
||||
case ITEM_TYPE_SHORTCUT:
|
||||
itemBuilder.setShortcut(LauncherAtom.Shortcut.newBuilder()
|
||||
.setShortcutName(cn.flattenToShortString()));
|
||||
break;
|
||||
case ITEM_TYPE_APPWIDGET:
|
||||
setItemBuilder(itemBuilder);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
}
|
||||
if (fInfo != null) {
|
||||
LauncherAtom.FolderContainer.Builder folderBuilder =
|
||||
LauncherAtom.FolderContainer.newBuilder();
|
||||
folderBuilder.setGridX(cellX).setGridY(cellY).setPageIndex(screenId);
|
||||
|
||||
switch (fInfo.container) {
|
||||
case CONTAINER_HOTSEAT:
|
||||
folderBuilder.setHotseat(LauncherAtom.HotseatContainer.newBuilder()
|
||||
.setIndex(fInfo.screenId));
|
||||
break;
|
||||
case CONTAINER_DESKTOP:
|
||||
folderBuilder.setWorkspace(LauncherAtom.WorkspaceContainer.newBuilder()
|
||||
.setPageIndex(fInfo.screenId)
|
||||
.setGridX(fInfo.cellX).setGridY(fInfo.cellY));
|
||||
break;
|
||||
}
|
||||
itemBuilder.setFolder(folderBuilder);
|
||||
} else {
|
||||
switch (container) {
|
||||
case CONTAINER_HOTSEAT:
|
||||
itemBuilder.setHotseat(LauncherAtom.HotseatContainer.newBuilder()
|
||||
.setIndex(screenId));
|
||||
break;
|
||||
case CONTAINER_DESKTOP:
|
||||
itemBuilder.setWorkspace(LauncherAtom.WorkspaceContainer.newBuilder()
|
||||
.setGridX(cellX)
|
||||
.setGridY(cellY)
|
||||
.setPageIndex(screenId));
|
||||
break;
|
||||
}
|
||||
}
|
||||
return itemBuilder.build();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,7 +77,6 @@ import android.view.Menu;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewTreeObserver;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
import android.view.animation.OvershootInterpolator;
|
||||
import android.widget.Toast;
|
||||
@@ -115,6 +114,7 @@ import com.android.launcher3.model.BgDataModel.Callbacks;
|
||||
import com.android.launcher3.model.ModelWriter;
|
||||
import com.android.launcher3.notification.NotificationListener;
|
||||
import com.android.launcher3.pm.PinRequestHelper;
|
||||
import com.android.launcher3.pm.UserCache;
|
||||
import com.android.launcher3.popup.PopupContainerWithArrow;
|
||||
import com.android.launcher3.popup.PopupDataProvider;
|
||||
import com.android.launcher3.popup.SystemShortcut;
|
||||
@@ -124,7 +124,6 @@ import com.android.launcher3.testing.TestLogging;
|
||||
import com.android.launcher3.testing.TestProtocol;
|
||||
import com.android.launcher3.touch.AllAppsSwipeController;
|
||||
import com.android.launcher3.touch.ItemClickHandler;
|
||||
import com.android.launcher3.uioverrides.DepthController;
|
||||
import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
|
||||
@@ -139,6 +138,7 @@ import com.android.launcher3.util.MultiValueAlpha.AlphaProperty;
|
||||
import com.android.launcher3.util.PackageManagerHelper;
|
||||
import com.android.launcher3.util.PackageUserKey;
|
||||
import com.android.launcher3.util.PendingRequestArgs;
|
||||
import com.android.launcher3.util.SafeCloseable;
|
||||
import com.android.launcher3.util.ShortcutUtil;
|
||||
import com.android.launcher3.util.SystemUiController;
|
||||
import com.android.launcher3.util.Themes;
|
||||
@@ -271,7 +271,6 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
|
||||
|
||||
// UI and state for the overview panel
|
||||
private View mOverviewPanel;
|
||||
private View mActionsView;
|
||||
|
||||
@Thunk
|
||||
boolean mWorkspaceLoading = true;
|
||||
@@ -326,20 +325,10 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
|
||||
private boolean mDeferOverlayCallbacks;
|
||||
private final Runnable mDeferredOverlayCallbacks = this::checkIfOverlayStillDeferred;
|
||||
|
||||
private DepthController mDepthController =
|
||||
new DepthController(this);
|
||||
|
||||
private final ViewTreeObserver.OnDrawListener mOnDrawListener =
|
||||
new ViewTreeObserver.OnDrawListener() {
|
||||
@Override
|
||||
public void onDraw() {
|
||||
getDepthController().setSurfaceToLauncher(mDragLayer);
|
||||
mDragLayer.post(() -> mDragLayer.getViewTreeObserver().removeOnDrawListener(
|
||||
this));
|
||||
}
|
||||
};
|
||||
|
||||
private long mLastTouchUpTime = -1;
|
||||
private boolean mTouchInProgress;
|
||||
|
||||
private SafeCloseable mUserChangedCallbackCloseable;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
@@ -459,6 +448,9 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
|
||||
});
|
||||
|
||||
TraceHelper.INSTANCE.endSection(traceToken);
|
||||
|
||||
mUserChangedCallbackCloseable = UserCache.INSTANCE.get(this).addUserChangeListener(
|
||||
() -> getStateManager().goToState(NORMAL));
|
||||
}
|
||||
|
||||
protected LauncherOverlayManager getDefaultOverlay() {
|
||||
@@ -760,8 +752,8 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
|
||||
data.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1) : -1;
|
||||
if (resultCode == RESULT_CANCELED) {
|
||||
completeTwoStageWidgetDrop(RESULT_CANCELED, appWidgetId, requestArgs);
|
||||
mWorkspace.removeExtraEmptyScreenDelayed(true, exitSpringLoaded,
|
||||
ON_ACTIVITY_RESULT_ANIMATION_DELAY, false);
|
||||
mWorkspace.removeExtraEmptyScreenDelayed(
|
||||
ON_ACTIVITY_RESULT_ANIMATION_DELAY, false, exitSpringLoaded);
|
||||
} else if (resultCode == RESULT_OK) {
|
||||
addAppWidgetImpl(
|
||||
appWidgetId, requestArgs, null,
|
||||
@@ -791,15 +783,9 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
|
||||
"returned from the widget configuration activity.");
|
||||
result = RESULT_CANCELED;
|
||||
completeTwoStageWidgetDrop(result, appWidgetId, requestArgs);
|
||||
final Runnable onComplete = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
getStateManager().goToState(NORMAL);
|
||||
}
|
||||
};
|
||||
|
||||
mWorkspace.removeExtraEmptyScreenDelayed(true, onComplete,
|
||||
ON_ACTIVITY_RESULT_ANIMATION_DELAY, false);
|
||||
mWorkspace.removeExtraEmptyScreenDelayed(
|
||||
ON_ACTIVITY_RESULT_ANIMATION_DELAY, false,
|
||||
() -> getStateManager().goToState(NORMAL));
|
||||
} else {
|
||||
if (requestArgs.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {
|
||||
// When the screen id represents an actual screen (as opposed to a rank)
|
||||
@@ -818,8 +804,8 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
|
||||
dropLayout.setDropPending(false);
|
||||
}
|
||||
};
|
||||
mWorkspace.removeExtraEmptyScreenDelayed(true, onComplete,
|
||||
ON_ACTIVITY_RESULT_ANIMATION_DELAY, false);
|
||||
mWorkspace.removeExtraEmptyScreenDelayed(
|
||||
ON_ACTIVITY_RESULT_ANIMATION_DELAY, false, onComplete);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -838,12 +824,12 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
|
||||
// Handle custom shortcuts created using ACTION_CREATE_SHORTCUT.
|
||||
if (resultCode == RESULT_OK && requestArgs.container != ItemInfo.NO_ID) {
|
||||
completeAdd(requestCode, data, -1, requestArgs);
|
||||
mWorkspace.removeExtraEmptyScreenDelayed(true, exitSpringLoaded,
|
||||
ON_ACTIVITY_RESULT_ANIMATION_DELAY, false);
|
||||
mWorkspace.removeExtraEmptyScreenDelayed(
|
||||
ON_ACTIVITY_RESULT_ANIMATION_DELAY, false, exitSpringLoaded);
|
||||
|
||||
} else if (resultCode == RESULT_CANCELED) {
|
||||
mWorkspace.removeExtraEmptyScreenDelayed(true, exitSpringLoaded,
|
||||
ON_ACTIVITY_RESULT_ANIMATION_DELAY, false);
|
||||
mWorkspace.removeExtraEmptyScreenDelayed(
|
||||
ON_ACTIVITY_RESULT_ANIMATION_DELAY, false, exitSpringLoaded);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -942,8 +928,6 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
|
||||
final int origDragLayerChildCount = mDragLayer.getChildCount();
|
||||
super.onStop();
|
||||
|
||||
mDragLayer.getViewTreeObserver().removeOnDrawListener(mOnDrawListener);
|
||||
|
||||
if (mDeferOverlayCallbacks) {
|
||||
checkIfOverlayStillDeferred();
|
||||
} else {
|
||||
@@ -956,7 +940,6 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
|
||||
|
||||
NotificationListener.removeNotificationsChangedListener();
|
||||
getStateManager().moveToRestState();
|
||||
getDepthController().setSurfaceToLauncher(null);
|
||||
|
||||
// Workaround for b/78520668, explicitly trim memory once UI is hidden
|
||||
onTrimMemory(TRIM_MEMORY_UI_HIDDEN);
|
||||
@@ -974,6 +957,8 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "Activity.onStop");
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -984,10 +969,10 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
|
||||
if (!mDeferOverlayCallbacks) {
|
||||
mOverlayManager.onActivityStarted(this);
|
||||
}
|
||||
mDragLayer.getViewTreeObserver().addOnDrawListener(mOnDrawListener);
|
||||
|
||||
mAppWidgetHost.setListenIfResumed(true);
|
||||
TraceHelper.INSTANCE.endSection(traceToken);
|
||||
TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "Activity.onStart");
|
||||
}
|
||||
|
||||
private void handleDeferredResume() {
|
||||
@@ -1180,7 +1165,6 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
|
||||
mWorkspace = mDragLayer.findViewById(R.id.workspace);
|
||||
mWorkspace.initParentViews(mDragLayer);
|
||||
mOverviewPanel = findViewById(R.id.overview_panel);
|
||||
mActionsView = findViewById(R.id.overview_actions_view);
|
||||
mHotseat = findViewById(R.id.hotseat);
|
||||
|
||||
mLauncherView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|
||||
@@ -1207,7 +1191,6 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
|
||||
mScrimView = findViewById(R.id.scrim_view);
|
||||
|
||||
// Setup the drag controller (drop targets have to be added in reverse order in priority)
|
||||
mDragController.setMoveTarget(mWorkspace);
|
||||
mDropTargetBar.setup(mDragController);
|
||||
|
||||
mAllAppsController.setupViews(mAppsView);
|
||||
@@ -1428,10 +1411,6 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
|
||||
return (T) mOverviewPanel;
|
||||
}
|
||||
|
||||
public View getActionsView() {
|
||||
return mActionsView;
|
||||
}
|
||||
|
||||
public DropTargetBar getDropTargetBar() {
|
||||
return mDropTargetBar;
|
||||
}
|
||||
@@ -1507,11 +1486,7 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
|
||||
target.pageIndex = mWorkspace.getCurrentPage();
|
||||
ued.logActionCommand(Action.Command.HOME_INTENT, target,
|
||||
newContainerTarget(ContainerType.WORKSPACE));
|
||||
|
||||
final View v = getWindow().peekDecorView();
|
||||
if (v != null && v.getWindowToken() != null) {
|
||||
UiThreadHelper.hideKeyboardAsync(this, v.getWindowToken());
|
||||
}
|
||||
hideKeyboard();
|
||||
|
||||
if (mLauncherCallbacks != null) {
|
||||
mLauncherCallbacks.onHomeIntent(internalStateHandled);
|
||||
@@ -1522,6 +1497,16 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
|
||||
TraceHelper.INSTANCE.endSection(traceToken);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hides the keyboard if visible
|
||||
*/
|
||||
public void hideKeyboard() {
|
||||
final View v = getWindow().peekDecorView();
|
||||
if (v != null && v.getWindowToken() != null) {
|
||||
UiThreadHelper.hideKeyboardAsync(this, v.getWindowToken());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRestoreInstanceState(Bundle state) {
|
||||
super.onRestoreInstanceState(state);
|
||||
@@ -1589,6 +1574,7 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
|
||||
|
||||
mOverlayManager.onActivityDestroyed(this);
|
||||
mAppTransitionManager.unregisterRemoteAnimations();
|
||||
mUserChangedCallbackCloseable.close();
|
||||
}
|
||||
|
||||
public LauncherAccessibilityDelegate getAccessibilityDelegate() {
|
||||
@@ -1682,7 +1668,7 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
|
||||
};
|
||||
completeAddAppWidget(appWidgetId, info, boundWidget,
|
||||
addFlowHandler.getProviderInfo(this));
|
||||
mWorkspace.removeExtraEmptyScreenDelayed(true, onComplete, delay, false);
|
||||
mWorkspace.removeExtraEmptyScreenDelayed(delay, false, onComplete);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1840,13 +1826,28 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
|
||||
|
||||
@Override
|
||||
public boolean dispatchTouchEvent(MotionEvent ev) {
|
||||
if (ev.getAction() == MotionEvent.ACTION_UP) {
|
||||
mLastTouchUpTime = System.currentTimeMillis();
|
||||
switch (ev.getAction()) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
mTouchInProgress = true;
|
||||
break;
|
||||
case MotionEvent.ACTION_UP:
|
||||
mLastTouchUpTime = System.currentTimeMillis();
|
||||
// Follow through
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
mTouchInProgress = false;
|
||||
break;
|
||||
}
|
||||
TestLogging.recordMotionEvent(TestProtocol.SEQUENCE_MAIN, "Touch event", ev);
|
||||
return super.dispatchTouchEvent(ev);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if a touch interaction is in progress
|
||||
*/
|
||||
public boolean isTouchInProgress() {
|
||||
return mTouchInProgress;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
if (finishAutoCancelActionMode()) {
|
||||
@@ -2112,7 +2113,7 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
|
||||
}
|
||||
|
||||
// Remove the extra empty screen
|
||||
mWorkspace.removeExtraEmptyScreen(false, false);
|
||||
mWorkspace.removeExtraEmptyScreen(false);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2716,8 +2717,7 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
|
||||
}
|
||||
|
||||
protected StateHandler[] createStateHandlers() {
|
||||
return new StateHandler[] { getAllAppsController(), getWorkspace(),
|
||||
getDepthController() };
|
||||
return new StateHandler[] { getAllAppsController(), getWorkspace() };
|
||||
}
|
||||
|
||||
public TouchController[] createTouchControllers() {
|
||||
@@ -2754,10 +2754,6 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
|
||||
return Stream.of(APP_INFO, WIDGETS, INSTALL);
|
||||
}
|
||||
|
||||
public DepthController getDepthController() {
|
||||
return mDepthController;
|
||||
}
|
||||
|
||||
public static Launcher getLauncher(Context context) {
|
||||
return fromContext(context);
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import android.content.ComponentName;
|
||||
import android.content.Intent;
|
||||
import android.os.Process;
|
||||
|
||||
import com.android.launcher3.logger.LauncherAtom;
|
||||
import com.android.launcher3.model.PackageItemInfo;
|
||||
import com.android.launcher3.util.ContentWriter;
|
||||
|
||||
@@ -162,7 +163,9 @@ public class LauncherAppWidgetInfo extends ItemInfo {
|
||||
|
||||
@Override
|
||||
protected String dumpProperties() {
|
||||
return super.dumpProperties() + " appWidgetId=" + appWidgetId;
|
||||
return super.dumpProperties()
|
||||
+ " providerName=" + providerName
|
||||
+ " appWidgetId=" + appWidgetId;
|
||||
}
|
||||
|
||||
public final boolean isWidgetIdAllocated() {
|
||||
@@ -182,4 +185,13 @@ public class LauncherAppWidgetInfo extends ItemInfo {
|
||||
public final boolean hasOptionFlag(int option) {
|
||||
return (options & option) != 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setItemBuilder(LauncherAtom.ItemInfo.Builder builder) {
|
||||
builder.setWidget(LauncherAtom.Widget.newBuilder()
|
||||
.setSpanX(spanX)
|
||||
.setSpanY(spanY)
|
||||
.setComponentName(providerName.toString())
|
||||
.setPackageName(providerName.getPackageName()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,6 +85,7 @@ import java.net.URISyntaxException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Locale;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class LauncherProvider extends ContentProvider {
|
||||
private static final String TAG = "LauncherProvider";
|
||||
@@ -145,7 +146,7 @@ public class LauncherProvider extends ContentProvider {
|
||||
*/
|
||||
protected synchronized void createDbIfNotExists() {
|
||||
if (mOpenHelper == null) {
|
||||
mOpenHelper = new DatabaseHelper(getContext());
|
||||
mOpenHelper = DatabaseHelper.createDatabaseHelper(getContext());
|
||||
|
||||
if (RestoreDbTask.isPending(getContext())) {
|
||||
if (!RestoreDbTask.performRestore(getContext(), mOpenHelper,
|
||||
@@ -159,17 +160,17 @@ public class LauncherProvider extends ContentProvider {
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized boolean updateCurrentOpenHelper() {
|
||||
final InvariantDeviceProfile idp = InvariantDeviceProfile.INSTANCE.get(getContext());
|
||||
if (TextUtils.equals(idp.dbFile, mOpenHelper.getDatabaseName())) {
|
||||
private synchronized boolean prepForMigration(String dbFile, String targetTableName,
|
||||
Supplier<DatabaseHelper> src, Supplier<DatabaseHelper> dst) {
|
||||
if (TextUtils.equals(dbFile, mOpenHelper.getDatabaseName())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
DatabaseHelper oldHelper = mOpenHelper;
|
||||
mOpenHelper = new DatabaseHelper(getContext());
|
||||
copyTable(oldHelper.getReadableDatabase(), Favorites.TABLE_NAME,
|
||||
mOpenHelper.getWritableDatabase(), Favorites.TMP_TABLE, getContext());
|
||||
oldHelper.close();
|
||||
final DatabaseHelper helper = src.get();
|
||||
mOpenHelper = dst.get();
|
||||
copyTable(helper.getReadableDatabase(), Favorites.TABLE_NAME,
|
||||
mOpenHelper.getWritableDatabase(), targetTableName, getContext());
|
||||
helper.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -425,7 +426,23 @@ public class LauncherProvider extends ContentProvider {
|
||||
if (MULTI_DB_GRID_MIRATION_ALGO.get()) {
|
||||
Bundle result = new Bundle();
|
||||
result.putBoolean(LauncherSettings.Settings.EXTRA_VALUE,
|
||||
updateCurrentOpenHelper());
|
||||
prepForMigration(
|
||||
InvariantDeviceProfile.INSTANCE.get(getContext()).dbFile,
|
||||
Favorites.TMP_TABLE,
|
||||
() -> mOpenHelper,
|
||||
() -> DatabaseHelper.createDatabaseHelper(getContext())));
|
||||
return result;
|
||||
}
|
||||
}
|
||||
case LauncherSettings.Settings.METHOD_PREP_FOR_PREVIEW: {
|
||||
if (MULTI_DB_GRID_MIRATION_ALGO.get()) {
|
||||
Bundle result = new Bundle();
|
||||
result.putBoolean(LauncherSettings.Settings.EXTRA_VALUE,
|
||||
prepForMigration(
|
||||
arg /* dbFile */,
|
||||
Favorites.PREVIEW_TABLE_NAME,
|
||||
() -> DatabaseHelper.createDatabaseHelper(getContext(), arg),
|
||||
() -> mOpenHelper));
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -596,23 +613,31 @@ public class LauncherProvider extends ContentProvider {
|
||||
private int mMaxScreenId = -1;
|
||||
private boolean mBackupTableExists;
|
||||
|
||||
DatabaseHelper(Context context) {
|
||||
this(context, MULTI_DB_GRID_MIRATION_ALGO.get() ? InvariantDeviceProfile.INSTANCE.get(
|
||||
context).dbFile : LauncherFiles.LAUNCHER_DB);
|
||||
static DatabaseHelper createDatabaseHelper(Context context) {
|
||||
return createDatabaseHelper(context, null);
|
||||
}
|
||||
|
||||
static DatabaseHelper createDatabaseHelper(Context context, String dbName) {
|
||||
if (dbName == null) {
|
||||
dbName = MULTI_DB_GRID_MIRATION_ALGO.get() ? InvariantDeviceProfile.INSTANCE.get(
|
||||
context).dbFile : LauncherFiles.LAUNCHER_DB;
|
||||
}
|
||||
DatabaseHelper databaseHelper = new DatabaseHelper(context, dbName);
|
||||
// Table creation sometimes fails silently, which leads to a crash loop.
|
||||
// This way, we will try to create a table every time after crash, so the device
|
||||
// would eventually be able to recover.
|
||||
if (!tableExists(getReadableDatabase(), Favorites.TABLE_NAME)) {
|
||||
if (!tableExists(databaseHelper.getReadableDatabase(), Favorites.TABLE_NAME)) {
|
||||
Log.e(TAG, "Tables are missing after onCreate has been called. Trying to recreate");
|
||||
// This operation is a no-op if the table already exists.
|
||||
addFavoritesTable(getWritableDatabase(), true);
|
||||
databaseHelper.addFavoritesTable(databaseHelper.getWritableDatabase(), true);
|
||||
}
|
||||
if (!MULTI_DB_GRID_MIRATION_ALGO.get()) {
|
||||
mBackupTableExists = tableExists(getReadableDatabase(),
|
||||
Favorites.BACKUP_TABLE_NAME);
|
||||
databaseHelper.mBackupTableExists = tableExists(
|
||||
databaseHelper.getReadableDatabase(), Favorites.BACKUP_TABLE_NAME);
|
||||
}
|
||||
|
||||
initIds();
|
||||
databaseHelper.initIds();
|
||||
return databaseHelper;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -326,10 +326,16 @@ public class LauncherSettings {
|
||||
|
||||
public static final String METHOD_UPDATE_CURRENT_OPEN_HELPER = "update_current_open_helper";
|
||||
|
||||
public static final String METHOD_PREP_FOR_PREVIEW = "prep_for_preview";
|
||||
|
||||
public static final String EXTRA_VALUE = "value";
|
||||
|
||||
public static Bundle call(ContentResolver cr, String method) {
|
||||
return cr.call(CONTENT_URI, method, null, null);
|
||||
return call(cr, method, null);
|
||||
}
|
||||
|
||||
public static Bundle call(ContentResolver cr, String method, String arg) {
|
||||
return cr.call(CONTENT_URI, method, arg, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ public abstract class LauncherState {
|
||||
public static final int ALL_APPS_HEADER_EXTRA = 1 << 3; // e.g. app predictions
|
||||
public static final int ALL_APPS_CONTENT = 1 << 4;
|
||||
public static final int VERTICAL_SWIPE_INDICATOR = 1 << 5;
|
||||
public static final int RECENTS_CLEAR_ALL_BUTTON = 1 << 6;
|
||||
public static final int OVERVIEW_BUTTONS = 1 << 6;
|
||||
|
||||
/** Mask of all the items that are contained in the apps view. */
|
||||
public static final int APPS_VIEW_ITEM_MASK =
|
||||
|
||||
@@ -324,6 +324,7 @@ public class LauncherStateManager {
|
||||
|
||||
public AnimatorPlaybackController createAnimationToNewWorkspace(LauncherState state,
|
||||
StateAnimationConfig config) {
|
||||
config.userControlled = true;
|
||||
mConfig.reset();
|
||||
config.copyTo(mConfig);
|
||||
mConfig.playbackController = createAnimationToNewWorkspaceInternal(state)
|
||||
|
||||
@@ -50,6 +50,8 @@ import static com.android.launcher3.touch.PagedOrientationHandler.CANVAS_TRANSLA
|
||||
import static com.android.launcher3.touch.PagedOrientationHandler.VIEW_SCROLL_BY;
|
||||
import static com.android.launcher3.touch.PagedOrientationHandler.VIEW_SCROLL_TO;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.android.launcher3.anim.Interpolators;
|
||||
import com.android.launcher3.compat.AccessibilityManagerCompat;
|
||||
import com.android.launcher3.config.FeatureFlags;
|
||||
@@ -133,6 +135,7 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
|
||||
protected int mActivePointerId = INVALID_POINTER;
|
||||
|
||||
protected boolean mIsPageInTransition = false;
|
||||
private Runnable mOnPageTransitionEndCallback;
|
||||
|
||||
protected float mSpringOverScroll;
|
||||
|
||||
@@ -391,6 +394,22 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
|
||||
AccessibilityManagerCompat.sendScrollFinishedEventToTest(getContext());
|
||||
AccessibilityManagerCompat.sendCustomAccessibilityEvent(getPageAt(mCurrentPage),
|
||||
AccessibilityEvent.TYPE_VIEW_FOCUSED, null);
|
||||
if (mOnPageTransitionEndCallback != null) {
|
||||
mOnPageTransitionEndCallback.run();
|
||||
mOnPageTransitionEndCallback = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a callback to run once when the scrolling finishes. If there is currently
|
||||
* no page in transition, then the callback is called immediately.
|
||||
*/
|
||||
public void setOnPageTransitionEndCallback(@Nullable Runnable callback) {
|
||||
if (mIsPageInTransition || callback == null) {
|
||||
mOnPageTransitionEndCallback = callback;
|
||||
} else {
|
||||
callback.run();
|
||||
}
|
||||
}
|
||||
|
||||
protected int getUnboundedScroll() {
|
||||
|
||||
@@ -108,7 +108,7 @@ public class SecondaryDropTarget extends ButtonDropTarget implements OnAlarmList
|
||||
updateText(R.string.uninstall_drop_target_label);
|
||||
} else if (action == DISMISS_PREDICTION) {
|
||||
mHoverColor = Themes.getColorAccent(getContext());
|
||||
setDrawable(R.drawable.ic_block);
|
||||
setDrawable(R.drawable.ic_block_shadow);
|
||||
updateText(R.string.dismiss_prediction_label);
|
||||
} else if (action == RECONFIGURE) {
|
||||
mHoverColor = Themes.getColorAccent(getContext());
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
package com.android.launcher3;
|
||||
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
|
||||
import com.android.launcher3.StylusEventHelper.StylusButtonListener;
|
||||
|
||||
/**
|
||||
* Simple listener that performs a long click on the view after a stylus button press.
|
||||
*/
|
||||
public class SimpleOnStylusPressListener implements StylusButtonListener {
|
||||
private View mView;
|
||||
|
||||
public SimpleOnStylusPressListener(View view) {
|
||||
mView = view;
|
||||
}
|
||||
|
||||
public boolean onPressed(MotionEvent event) {
|
||||
return mView.isLongClickable() && mView.performLongClick();
|
||||
}
|
||||
|
||||
public boolean onReleased(MotionEvent event) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1,109 +0,0 @@
|
||||
package com.android.launcher3;
|
||||
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewConfiguration;
|
||||
|
||||
/**
|
||||
* Helper for identifying when a stylus touches a view while the primary stylus button is pressed.
|
||||
* This can occur in {@value MotionEvent#ACTION_DOWN} or {@value MotionEvent#ACTION_MOVE}.
|
||||
*/
|
||||
public class StylusEventHelper {
|
||||
|
||||
/**
|
||||
* Implement this interface to receive callbacks for a stylus button press and release.
|
||||
*/
|
||||
public interface StylusButtonListener {
|
||||
/**
|
||||
* Called when the stylus button is pressed.
|
||||
*
|
||||
* @param event The MotionEvent that the button press occurred for.
|
||||
* @return Whether the event was handled.
|
||||
*/
|
||||
public boolean onPressed(MotionEvent event);
|
||||
|
||||
/**
|
||||
* Called when the stylus button is released after a button press. This is also called if
|
||||
* the event is canceled or the stylus is lifted off the screen.
|
||||
*
|
||||
* @param event The MotionEvent the button release occurred for.
|
||||
* @return Whether the event was handled.
|
||||
*/
|
||||
public boolean onReleased(MotionEvent event);
|
||||
}
|
||||
|
||||
private boolean mIsButtonPressed;
|
||||
private View mView;
|
||||
private StylusButtonListener mListener;
|
||||
private final float mSlop;
|
||||
|
||||
/**
|
||||
* Constructs a helper for listening to stylus button presses and releases. Ensure that {
|
||||
* {@link #onMotionEvent(MotionEvent)} and {@link #onGenericMotionEvent(MotionEvent)} are called on
|
||||
* the helper to correctly identify stylus events.
|
||||
*
|
||||
* @param listener The listener to call for stylus events.
|
||||
* @param view Optional view associated with the touch events.
|
||||
*/
|
||||
public StylusEventHelper(StylusButtonListener listener, View view) {
|
||||
mListener = listener;
|
||||
mView = view;
|
||||
if (mView != null) {
|
||||
mSlop = ViewConfiguration.get(mView.getContext()).getScaledTouchSlop();
|
||||
} else {
|
||||
mSlop = ViewConfiguration.getTouchSlop();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean onMotionEvent(MotionEvent event) {
|
||||
final boolean stylusButtonPressed = isStylusButtonPressed(event);
|
||||
switch (event.getAction()) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
mIsButtonPressed = stylusButtonPressed;
|
||||
if (mIsButtonPressed) {
|
||||
return mListener.onPressed(event);
|
||||
}
|
||||
break;
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
if (!Utilities.pointInView(mView, event.getX(), event.getY(), mSlop)) {
|
||||
return false;
|
||||
}
|
||||
if (!mIsButtonPressed && stylusButtonPressed) {
|
||||
mIsButtonPressed = true;
|
||||
return mListener.onPressed(event);
|
||||
} else if (mIsButtonPressed && !stylusButtonPressed) {
|
||||
mIsButtonPressed = false;
|
||||
return mListener.onReleased(event);
|
||||
}
|
||||
break;
|
||||
case MotionEvent.ACTION_UP:
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
if (mIsButtonPressed) {
|
||||
mIsButtonPressed = false;
|
||||
return mListener.onReleased(event);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether a stylus button press is occurring.
|
||||
*/
|
||||
public boolean inStylusButtonPressed() {
|
||||
return mIsButtonPressed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Identifies if the provided {@link MotionEvent} is a stylus with the primary stylus button
|
||||
* pressed.
|
||||
*
|
||||
* @param event The event to check.
|
||||
* @return Whether a stylus button press occurred.
|
||||
*/
|
||||
private static boolean isStylusButtonPressed(MotionEvent event) {
|
||||
return event.getToolType(0) == MotionEvent.TOOL_TYPE_STYLUS
|
||||
&& ((event.getButtonState() & MotionEvent.BUTTON_SECONDARY)
|
||||
== MotionEvent.BUTTON_SECONDARY);
|
||||
}
|
||||
}
|
||||
@@ -29,7 +29,6 @@ import static com.android.launcher3.logging.LoggerUtils.newContainerTarget;
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.LayoutTransition;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.animation.ValueAnimator.AnimatorUpdateListener;
|
||||
import android.annotation.SuppressLint;
|
||||
@@ -43,7 +42,6 @@ import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.Message;
|
||||
import android.os.Parcelable;
|
||||
import android.os.UserHandle;
|
||||
@@ -125,9 +123,6 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
|
||||
|
||||
private static final boolean ENFORCE_DRAG_EVENT_ORDER = false;
|
||||
|
||||
private static final int SNAP_OFF_EMPTY_SCREEN_DURATION = 400;
|
||||
private static final int FADE_EMPTY_SCREEN_DURATION = 150;
|
||||
|
||||
private static final int ADJACENT_SCREEN_DROP_DURATION = 300;
|
||||
|
||||
private static final int DEFAULT_PAGE = 0;
|
||||
@@ -140,7 +135,6 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
|
||||
@Thunk final IntSparseArrayMap<CellLayout> mWorkspaceScreens = new IntSparseArrayMap<>();
|
||||
@Thunk final IntArray mScreenOrder = new IntArray();
|
||||
|
||||
@Thunk Runnable mRemoveEmptyScreenRunnable;
|
||||
@Thunk boolean mDeferRemoveExtraEmptyScreen = false;
|
||||
|
||||
/**
|
||||
@@ -428,7 +422,7 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
|
||||
}
|
||||
|
||||
if (!mDeferRemoveExtraEmptyScreen) {
|
||||
removeExtraEmptyScreen(true, mDragSourceInternal != null);
|
||||
removeExtraEmptyScreen(mDragSourceInternal != null);
|
||||
}
|
||||
|
||||
updateChildrenLayersEnabled();
|
||||
@@ -453,8 +447,16 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
|
||||
private void setupLayoutTransition() {
|
||||
// We want to show layout transitions when pages are deleted, to close the gap.
|
||||
mLayoutTransition = new LayoutTransition();
|
||||
|
||||
mLayoutTransition.enableTransitionType(LayoutTransition.DISAPPEARING);
|
||||
mLayoutTransition.enableTransitionType(LayoutTransition.CHANGE_DISAPPEARING);
|
||||
// Change the interpolators such that the fade animation plays before the move animation.
|
||||
// This prevents empty adjacent pages to overlay during animation
|
||||
mLayoutTransition.setInterpolator(LayoutTransition.DISAPPEARING,
|
||||
Interpolators.clampToProgress(Interpolators.ACCEL_DEACCEL, 0, 0.5f));
|
||||
mLayoutTransition.setInterpolator(LayoutTransition.CHANGE_DISAPPEARING,
|
||||
Interpolators.clampToProgress(Interpolators.ACCEL_DEACCEL, 0.5f, 1));
|
||||
|
||||
mLayoutTransition.disableTransitionType(LayoutTransition.APPEARING);
|
||||
mLayoutTransition.disableTransitionType(LayoutTransition.CHANGE_APPEARING);
|
||||
setLayoutTransition(mLayoutTransition);
|
||||
@@ -571,9 +573,6 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
|
||||
boolean lastChildOnScreen = false;
|
||||
boolean childOnFinalScreen = false;
|
||||
|
||||
// Cancel any pending removal of empty screen
|
||||
mRemoveEmptyScreenRunnable = null;
|
||||
|
||||
if (mDragSourceInternal != null) {
|
||||
if (mDragSourceInternal.getChildCount() == 1) {
|
||||
lastChildOnScreen = true;
|
||||
@@ -624,43 +623,34 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
|
||||
}
|
||||
}
|
||||
|
||||
public void removeExtraEmptyScreen(final boolean animate, boolean stripEmptyScreens) {
|
||||
removeExtraEmptyScreenDelayed(animate, null, 0, stripEmptyScreens);
|
||||
public void removeExtraEmptyScreen(boolean stripEmptyScreens) {
|
||||
removeExtraEmptyScreenDelayed(0, stripEmptyScreens, null);
|
||||
}
|
||||
|
||||
public void removeExtraEmptyScreenDelayed(final boolean animate, final Runnable onComplete,
|
||||
final int delay, final boolean stripEmptyScreens) {
|
||||
public void removeExtraEmptyScreenDelayed(
|
||||
int delay, boolean stripEmptyScreens, Runnable onComplete) {
|
||||
if (mLauncher.isWorkspaceLoading()) {
|
||||
// Don't strip empty screens if the workspace is still loading
|
||||
return;
|
||||
}
|
||||
|
||||
if (delay > 0) {
|
||||
postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
removeExtraEmptyScreenDelayed(animate, onComplete, 0, stripEmptyScreens);
|
||||
}
|
||||
}, delay);
|
||||
postDelayed(
|
||||
() -> removeExtraEmptyScreenDelayed(0, stripEmptyScreens, onComplete), delay);
|
||||
return;
|
||||
}
|
||||
|
||||
convertFinalScreenToEmptyScreenIfNecessary();
|
||||
if (hasExtraEmptyScreen()) {
|
||||
int emptyIndex = mScreenOrder.indexOf(EXTRA_EMPTY_SCREEN_ID);
|
||||
if (getNextPage() == emptyIndex) {
|
||||
snapToPage(getNextPage() - 1, SNAP_OFF_EMPTY_SCREEN_DURATION);
|
||||
fadeAndRemoveEmptyScreen(SNAP_OFF_EMPTY_SCREEN_DURATION, FADE_EMPTY_SCREEN_DURATION,
|
||||
onComplete, stripEmptyScreens);
|
||||
} else {
|
||||
snapToPage(getNextPage(), 0);
|
||||
fadeAndRemoveEmptyScreen(0, FADE_EMPTY_SCREEN_DURATION,
|
||||
onComplete, stripEmptyScreens);
|
||||
}
|
||||
return;
|
||||
} else if (stripEmptyScreens) {
|
||||
// If we're not going to strip the empty screens after removing
|
||||
// the extra empty screen, do it right away.
|
||||
removeView(mWorkspaceScreens.get(EXTRA_EMPTY_SCREEN_ID));
|
||||
mWorkspaceScreens.remove(EXTRA_EMPTY_SCREEN_ID);
|
||||
mScreenOrder.removeValue(EXTRA_EMPTY_SCREEN_ID);
|
||||
|
||||
// Update the page indicator to reflect the removed page.
|
||||
showPageIndicatorAtCurrentScroll();
|
||||
}
|
||||
|
||||
if (stripEmptyScreens) {
|
||||
stripEmptyScreens();
|
||||
}
|
||||
|
||||
@@ -669,44 +659,6 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
|
||||
}
|
||||
}
|
||||
|
||||
private void fadeAndRemoveEmptyScreen(int delay, int duration, final Runnable onComplete,
|
||||
final boolean stripEmptyScreens) {
|
||||
// XXX: Do we need to update LM workspace screens below?
|
||||
final CellLayout cl = mWorkspaceScreens.get(EXTRA_EMPTY_SCREEN_ID);
|
||||
|
||||
mRemoveEmptyScreenRunnable = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (hasExtraEmptyScreen()) {
|
||||
mWorkspaceScreens.remove(EXTRA_EMPTY_SCREEN_ID);
|
||||
mScreenOrder.removeValue(EXTRA_EMPTY_SCREEN_ID);
|
||||
removeView(cl);
|
||||
if (stripEmptyScreens) {
|
||||
stripEmptyScreens();
|
||||
}
|
||||
// Update the page indicator to reflect the removed page.
|
||||
showPageIndicatorAtCurrentScroll();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ObjectAnimator oa = ObjectAnimator.ofFloat(cl, ALPHA, 0f);
|
||||
oa.setDuration(duration);
|
||||
oa.setStartDelay(delay);
|
||||
oa.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
if (mRemoveEmptyScreenRunnable != null) {
|
||||
mRemoveEmptyScreenRunnable.run();
|
||||
}
|
||||
if (onComplete != null) {
|
||||
onComplete.run();
|
||||
}
|
||||
}
|
||||
});
|
||||
oa.start();
|
||||
}
|
||||
|
||||
public boolean hasExtraEmptyScreen() {
|
||||
return mWorkspaceScreens.containsKey(EXTRA_EMPTY_SCREEN_ID) && getChildCount() > 1;
|
||||
}
|
||||
@@ -793,8 +745,6 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
|
||||
}
|
||||
}
|
||||
|
||||
boolean isInAccessibleDrag = mLauncher.getAccessibilityDelegate().isInAccessibleDrag();
|
||||
|
||||
// We enforce at least one page to add new items to. In the case that we remove the last
|
||||
// such screen, we convert the last screen to the empty screen
|
||||
int minScreens = 1;
|
||||
@@ -813,7 +763,6 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
|
||||
removeView(cl);
|
||||
} else {
|
||||
// if this is the last screen, convert it to the empty screen
|
||||
mRemoveEmptyScreenRunnable = null;
|
||||
mWorkspaceScreens.put(EXTRA_EMPTY_SCREEN_ID, cl);
|
||||
mScreenOrder.add(EXTRA_EMPTY_SCREEN_ID);
|
||||
}
|
||||
@@ -1042,7 +991,6 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
|
||||
if (!mOverlayShown) {
|
||||
mLauncher.getUserEventDispatcher().logActionOnContainer(Action.Touch.SWIPE,
|
||||
Action.Direction.LEFT, ContainerType.WORKSPACE, 0);
|
||||
mLauncher.getStatsLogManager().logSwipeOnContainer(true, 0);
|
||||
}
|
||||
mOverlayShown = true;
|
||||
// Not announcing the overlay page for accessibility since it announces itself.
|
||||
@@ -1052,7 +1000,6 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
|
||||
if (!ued.isPreviousHomeGesture()) {
|
||||
mLauncher.getUserEventDispatcher().logActionOnContainer(Action.Touch.SWIPE,
|
||||
Action.Direction.RIGHT, ContainerType.WORKSPACE, -1);
|
||||
mLauncher.getStatsLogManager().logSwipeOnContainer(false, -1);
|
||||
}
|
||||
} else if (Float.compare(mOverlayTranslation, 0f) != 0) {
|
||||
// When arriving to 0 overscroll from non-zero overscroll, announce page for
|
||||
@@ -1224,10 +1171,8 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
|
||||
|
||||
protected void onAttachedToWindow() {
|
||||
super.onAttachedToWindow();
|
||||
IBinder windowToken = getWindowToken();
|
||||
mWallpaperOffset.setWindowToken(windowToken);
|
||||
mWallpaperOffset.setWindowToken(getWindowToken());
|
||||
computeScroll();
|
||||
mDragController.setWindowToken(windowToken);
|
||||
}
|
||||
|
||||
protected void onDetachedFromWindow() {
|
||||
|
||||
@@ -146,11 +146,21 @@ public class LauncherAccessibilityDelegate extends AccessibilityDelegate impleme
|
||||
}
|
||||
}
|
||||
|
||||
if (!fromKeyboard && !itemSupportsLongClick(host, item)) {
|
||||
info.setLongClickable(false);
|
||||
info.removeAction(AccessibilityAction.ACTION_LONG_CLICK);
|
||||
}
|
||||
|
||||
if ((item instanceof AppInfo) || (item instanceof PendingAddItemInfo)) {
|
||||
info.addAction(mActions.get(ADD_TO_WORKSPACE));
|
||||
}
|
||||
}
|
||||
|
||||
private boolean itemSupportsLongClick(View host, ItemInfo info) {
|
||||
return new CustomActionsPopup(mLauncher, host).canShow()
|
||||
|| ShortcutUtil.supportsShortcuts(info);
|
||||
}
|
||||
|
||||
private boolean itemSupportsAccessibleDrag(ItemInfo item) {
|
||||
if (item instanceof WorkspaceItemInfo) {
|
||||
// Support the action unless the item is in a context menu.
|
||||
@@ -171,18 +181,18 @@ public class LauncherAccessibilityDelegate extends AccessibilityDelegate impleme
|
||||
|
||||
public boolean performAction(final View host, final ItemInfo item, int action) {
|
||||
if (action == ACTION_LONG_CLICK) {
|
||||
if (ShortcutUtil.isDeepShortcut(item)) {
|
||||
CustomActionsPopup popup = new CustomActionsPopup(mLauncher, host);
|
||||
if (popup.canShow()) {
|
||||
popup.show();
|
||||
return true;
|
||||
}
|
||||
} else if (host instanceof BubbleTextView) {
|
||||
if (ShortcutUtil.supportsShortcuts(item)) {
|
||||
// Long press should be consumed for workspace items, and it should invoke the
|
||||
// Shortcuts / Notifications / Actions pop-up menu, and not start a drag as the
|
||||
// standard long press path does.
|
||||
PopupContainerWithArrow.showForIcon((BubbleTextView) host);
|
||||
return true;
|
||||
} else {
|
||||
CustomActionsPopup popup = new CustomActionsPopup(mLauncher, host);
|
||||
if (popup.canShow()) {
|
||||
popup.show();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -406,6 +406,11 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo
|
||||
setupWorkToggle();
|
||||
mAH[AdapterHolder.MAIN].setup(mViewPager.getChildAt(0), mPersonalMatcher);
|
||||
mAH[AdapterHolder.WORK].setup(mViewPager.getChildAt(1), mWorkMatcher);
|
||||
mViewPager.getPageIndicator().setActiveMarker(AdapterHolder.MAIN);
|
||||
findViewById(R.id.tab_personal)
|
||||
.setOnClickListener((View view) -> mViewPager.snapToPage(AdapterHolder.MAIN));
|
||||
findViewById(R.id.tab_work)
|
||||
.setOnClickListener((View view) -> mViewPager.snapToPage(AdapterHolder.WORK));
|
||||
onTabChanged(mViewPager.getNextPage());
|
||||
} else {
|
||||
mAH[AdapterHolder.MAIN].setup(findViewById(R.id.apps_list_view), null);
|
||||
@@ -456,16 +461,10 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo
|
||||
|
||||
public void onTabChanged(int pos) {
|
||||
mHeader.setMainActive(pos == 0);
|
||||
reset(true /* animate */);
|
||||
mViewPager.getPageIndicator().updateTabTextColor(pos);
|
||||
if (mAH[pos].recyclerView != null) {
|
||||
mAH[pos].recyclerView.bindFastScrollbar();
|
||||
|
||||
findViewById(R.id.tab_personal)
|
||||
.setOnClickListener((View view) -> mViewPager.snapToPage(AdapterHolder.MAIN));
|
||||
findViewById(R.id.tab_work)
|
||||
.setOnClickListener((View view) -> mViewPager.snapToPage(AdapterHolder.WORK));
|
||||
}
|
||||
reset(true /* animate */);
|
||||
if (mWorkModeSwitch != null) {
|
||||
mWorkModeSwitch.setWorkTabVisible(pos == AdapterHolder.WORK);
|
||||
}
|
||||
|
||||
@@ -135,6 +135,7 @@ public class PersonalWorkSlidingTabStrip extends LinearLayout implements PageInd
|
||||
@Override
|
||||
public void setActiveMarker(int activePage) {
|
||||
updateTabTextColor(activePage);
|
||||
updateIndicatorPosition(activePage);
|
||||
if (mContainerView != null && mLastActivePage != activePage) {
|
||||
mContainerView.onTabChanged(activePage);
|
||||
}
|
||||
|
||||
@@ -17,8 +17,6 @@ package com.android.launcher3.allapps;
|
||||
|
||||
import static com.android.launcher3.util.PackageManagerHelper.hasShortcutsPermission;
|
||||
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.animation.PropertyValuesHolder;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.graphics.Rect;
|
||||
@@ -27,7 +25,6 @@ import android.os.Process;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.MotionEvent;
|
||||
import android.widget.Switch;
|
||||
|
||||
import com.android.launcher3.Insettable;
|
||||
@@ -35,6 +32,7 @@ import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.pm.UserCache;
|
||||
import com.android.launcher3.views.ArrowTipView;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
@@ -43,27 +41,21 @@ import java.lang.ref.WeakReference;
|
||||
*/
|
||||
public class WorkModeSwitch extends Switch implements Insettable {
|
||||
|
||||
private Rect mInsets = new Rect();
|
||||
protected ObjectAnimator mOpenCloseAnimator;
|
||||
private static final int WORK_TIP_THRESHOLD = 2;
|
||||
public static final String KEY_WORK_TIP_COUNTER = "worked_tip_counter";
|
||||
|
||||
private Rect mInsets = new Rect();
|
||||
|
||||
public WorkModeSwitch(Context context) {
|
||||
super(context);
|
||||
init();
|
||||
}
|
||||
|
||||
public WorkModeSwitch(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
init();
|
||||
}
|
||||
|
||||
public WorkModeSwitch(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
init();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
mOpenCloseAnimator = ObjectAnimator.ofPropertyValuesHolder(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -73,6 +65,9 @@ public class WorkModeSwitch extends Switch implements Insettable {
|
||||
|
||||
@Override
|
||||
public void toggle() {
|
||||
Launcher launcher = Launcher.getLauncher(getContext());
|
||||
// don't show tip if user uses toggle
|
||||
launcher.getSharedPrefs().edit().putInt(KEY_WORK_TIP_COUNTER, -1).apply();
|
||||
trySetQuietModeEnabledToAllProfilesAsync(isChecked());
|
||||
}
|
||||
|
||||
@@ -95,11 +90,6 @@ public class WorkModeSwitch extends Switch implements Insettable {
|
||||
this.setVisibility(shouldShowWorkSwitch() ? VISIBLE : GONE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent ev) {
|
||||
return ev.getActionMasked() == MotionEvent.ACTION_MOVE || super.onTouchEvent(ev);
|
||||
}
|
||||
|
||||
private void trySetQuietModeEnabledToAllProfilesAsync(boolean enabled) {
|
||||
new SetQuietModeEnabledAsyncTask(enabled, new WeakReference<>(this)).execute();
|
||||
}
|
||||
@@ -117,9 +107,15 @@ public class WorkModeSwitch extends Switch implements Insettable {
|
||||
*/
|
||||
public void setWorkTabVisible(boolean workTabVisible) {
|
||||
if (!shouldShowWorkSwitch()) return;
|
||||
|
||||
mOpenCloseAnimator.setValues(PropertyValuesHolder.ofFloat(ALPHA, workTabVisible ? 1 : 0));
|
||||
mOpenCloseAnimator.start();
|
||||
clearAnimation();
|
||||
if (workTabVisible) {
|
||||
setVisibility(VISIBLE);
|
||||
setAlpha(0);
|
||||
animate().alpha(1).start();
|
||||
showTipifNeeded();
|
||||
} else {
|
||||
animate().alpha(0).withEndAction(() -> this.setVisibility(GONE)).start();
|
||||
}
|
||||
}
|
||||
|
||||
private static final class SetQuietModeEnabledAsyncTask
|
||||
@@ -179,4 +175,17 @@ public class WorkModeSwitch extends Switch implements Insettable {
|
||||
|| launcher.checkSelfPermission("android.permission.MODIFY_QUIET_MODE")
|
||||
== PackageManager.PERMISSION_GRANTED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows a work tip on the Nth work tab open
|
||||
*/
|
||||
public void showTipifNeeded() {
|
||||
Launcher launcher = Launcher.getLauncher(getContext());
|
||||
int tipCounter = launcher.getSharedPrefs().getInt(KEY_WORK_TIP_COUNTER, WORK_TIP_THRESHOLD);
|
||||
if (tipCounter < 0) return;
|
||||
if (tipCounter == 0) {
|
||||
new ArrowTipView(launcher).show(launcher.getString(R.string.work_switch_tip), getTop());
|
||||
}
|
||||
launcher.getSharedPrefs().edit().putInt(KEY_WORK_TIP_COUNTER, tipCounter - 1).apply();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,9 +62,8 @@ public class AppsSearchContainerLayout extends ExtendedEditText
|
||||
private AlphabeticalAppsList mApps;
|
||||
private AllAppsContainerView mAppsView;
|
||||
|
||||
// This value was used to position the QSB. We store it here for translationY animations.
|
||||
private final float mFixedTranslationY;
|
||||
private final float mMarginTopAdjusting;
|
||||
// The amount of pixels to shift down and overlap with the rest of the content.
|
||||
private final int mContentOverlap;
|
||||
|
||||
public AppsSearchContainerLayout(Context context) {
|
||||
this(context, null);
|
||||
@@ -82,11 +81,10 @@ public class AppsSearchContainerLayout extends ExtendedEditText
|
||||
|
||||
mSearchQueryBuilder = new SpannableStringBuilder();
|
||||
Selection.setSelection(mSearchQueryBuilder, 0);
|
||||
|
||||
mFixedTranslationY = getTranslationY();
|
||||
mMarginTopAdjusting = mFixedTranslationY - getPaddingTop();
|
||||
|
||||
setHint(prefixTextWithIcon(getContext(), R.drawable.ic_allapps_search, getHint()));
|
||||
|
||||
mContentOverlap =
|
||||
getResources().getDimensionPixelSize(R.dimen.all_apps_search_bar_field_height) / 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -128,6 +126,8 @@ public class AppsSearchContainerLayout extends ExtendedEditText
|
||||
int expectedLeft = parent.getPaddingLeft() + (availableWidth - myWidth) / 2;
|
||||
int shift = expectedLeft - left;
|
||||
setTranslationX(shift);
|
||||
|
||||
offsetTopAndBottom(mContentOverlap);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -196,7 +196,7 @@ public class AppsSearchContainerLayout extends ExtendedEditText
|
||||
@Override
|
||||
public void setInsets(Rect insets) {
|
||||
MarginLayoutParams mlp = (MarginLayoutParams) getLayoutParams();
|
||||
mlp.topMargin = Math.round(Math.max(-mFixedTranslationY, insets.top - mMarginTopAdjusting));
|
||||
mlp.topMargin = insets.top;
|
||||
requestLayout();
|
||||
}
|
||||
|
||||
@@ -205,9 +205,7 @@ public class AppsSearchContainerLayout extends ExtendedEditText
|
||||
if (mLauncher.getDeviceProfile().isVerticalBarLayout()) {
|
||||
return 0;
|
||||
} else {
|
||||
int topMargin = Math.round(Math.max(
|
||||
-mFixedTranslationY, insets.top - mMarginTopAdjusting));
|
||||
return insets.bottom + topMargin + mFixedTranslationY;
|
||||
return insets.bottom + insets.top;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -75,6 +75,9 @@ public class AccessibilityManagerCompat {
|
||||
}
|
||||
|
||||
public static void sendScrollFinishedEventToTest(Context context) {
|
||||
if (TestProtocol.sDebugTracing) {
|
||||
Log.d(TestProtocol.NO_SCROLL_END_WIDGETS, "sendScrollFinishedEventToTest");
|
||||
}
|
||||
final AccessibilityManager accessibilityManager = getAccessibilityManagerForTest(context);
|
||||
if (accessibilityManager == null) return;
|
||||
|
||||
|
||||
@@ -154,7 +154,7 @@ public final class FeatureFlags {
|
||||
"Replace Smartspace with a version rendered by System UI.");
|
||||
|
||||
public static final BooleanFlag ENABLE_LSQ_VELOCITY_PROVIDER = getDebugFlag(
|
||||
"ENABLE_LSQ_VELOCITY_PROVIDER", false,
|
||||
"ENABLE_LSQ_VELOCITY_PROVIDER", true,
|
||||
"Use Least Square algorithm for motion pause detection.");
|
||||
|
||||
public static final BooleanFlag ALWAYS_USE_HARDWARE_OPTIMIZATION_FOR_FOLDER_ANIMATIONS =
|
||||
|
||||
@@ -20,6 +20,7 @@ import static com.android.launcher3.AbstractFloatingView.TYPE_DISCOVERY_BOUNCE;
|
||||
import static com.android.launcher3.LauncherAnimUtils.SPRING_LOADED_EXIT_DELAY;
|
||||
import static com.android.launcher3.LauncherState.NORMAL;
|
||||
import static com.android.launcher3.Utilities.ATLEAST_Q;
|
||||
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
|
||||
|
||||
import android.animation.ValueAnimator;
|
||||
import android.content.ComponentName;
|
||||
@@ -27,7 +28,6 @@ import android.content.res.Resources;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
import android.os.IBinder;
|
||||
import android.view.DragEvent;
|
||||
import android.view.HapticFeedbackConstants;
|
||||
import android.view.KeyEvent;
|
||||
@@ -44,7 +44,6 @@ import com.android.launcher3.WorkspaceItemInfo;
|
||||
import com.android.launcher3.accessibility.DragViewStateAnnouncer;
|
||||
import com.android.launcher3.util.ItemInfoMatcher;
|
||||
import com.android.launcher3.util.TouchController;
|
||||
import com.android.launcher3.util.UiThreadHelper;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
@@ -64,7 +63,7 @@ public class DragController implements DragDriver.EventListener, TouchController
|
||||
private final FlingToDeleteHelper mFlingToDeleteHelper;
|
||||
|
||||
// temporaries to avoid gc thrash
|
||||
private Rect mRectTemp = new Rect();
|
||||
private final Rect mRectTemp = new Rect();
|
||||
private final int[] mCoordinatesTemp = new int[2];
|
||||
|
||||
/**
|
||||
@@ -86,21 +85,14 @@ public class DragController implements DragDriver.EventListener, TouchController
|
||||
private DropTarget.DragObject mDragObject;
|
||||
|
||||
/** Who can receive drop events */
|
||||
private ArrayList<DropTarget> mDropTargets = new ArrayList<>();
|
||||
private ArrayList<DragListener> mListeners = new ArrayList<>();
|
||||
|
||||
/** The window token used as the parent for the DragView. */
|
||||
private IBinder mWindowToken;
|
||||
|
||||
private View mMoveTarget;
|
||||
private final ArrayList<DropTarget> mDropTargets = new ArrayList<>();
|
||||
private final ArrayList<DragListener> mListeners = new ArrayList<>();
|
||||
|
||||
private DropTarget mLastDropTarget;
|
||||
|
||||
private int mLastTouchClassification;
|
||||
private int mDistanceSinceScroll = 0;
|
||||
|
||||
private Rect mDragLayerRect = new Rect();
|
||||
|
||||
private boolean mIsInPreDrag;
|
||||
|
||||
/**
|
||||
@@ -153,8 +145,7 @@ public class DragController implements DragDriver.EventListener, TouchController
|
||||
android.os.Debug.startMethodTracing("Launcher");
|
||||
}
|
||||
|
||||
// Hide soft keyboard, if visible
|
||||
UiThreadHelper.hideKeyboardAsync(mLauncher, mWindowToken);
|
||||
mLauncher.hideKeyboard();
|
||||
AbstractFloatingView.closeOpenViews(mLauncher, false, TYPE_DISCOVERY_BOUNCE);
|
||||
|
||||
mOptions = options;
|
||||
@@ -217,6 +208,11 @@ public class DragController implements DragDriver.EventListener, TouchController
|
||||
|
||||
handleMoveEvent(mLastTouch.x, mLastTouch.y);
|
||||
mLauncher.getUserEventDispatcher().resetActionDurationMillis();
|
||||
|
||||
if (!mLauncher.isTouchInProgress() && options.simulatedDndStartPoint == null) {
|
||||
// If it is an internal drag and the touch is already complete, cancel immediately
|
||||
MAIN_EXECUTOR.submit(this::cancelDrag);
|
||||
}
|
||||
return dragView;
|
||||
}
|
||||
|
||||
@@ -362,9 +358,9 @@ public class DragController implements DragDriver.EventListener, TouchController
|
||||
* Clamps the position to the drag layer bounds.
|
||||
*/
|
||||
private Point getClampedDragLayerPos(float x, float y) {
|
||||
mLauncher.getDragLayer().getLocalVisibleRect(mDragLayerRect);
|
||||
mTmpPoint.x = (int) Math.max(mDragLayerRect.left, Math.min(x, mDragLayerRect.right - 1));
|
||||
mTmpPoint.y = (int) Math.max(mDragLayerRect.top, Math.min(y, mDragLayerRect.bottom - 1));
|
||||
mLauncher.getDragLayer().getLocalVisibleRect(mRectTemp);
|
||||
mTmpPoint.x = (int) Math.max(mRectTemp.left, Math.min(x, mRectTemp.right - 1));
|
||||
mTmpPoint.y = (int) Math.max(mRectTemp.top, Math.min(y, mRectTemp.bottom - 1));
|
||||
return mTmpPoint;
|
||||
}
|
||||
|
||||
@@ -439,17 +435,6 @@ public class DragController implements DragDriver.EventListener, TouchController
|
||||
return mDragDriver != null && mDragDriver.onDragEvent(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the view that should handle move events.
|
||||
*/
|
||||
public void setMoveTarget(View view) {
|
||||
mMoveTarget = view;
|
||||
}
|
||||
|
||||
public boolean dispatchUnhandledMove(View focused, int direction) {
|
||||
return mMoveTarget != null && mMoveTarget.dispatchUnhandledMove(focused, direction);
|
||||
}
|
||||
|
||||
private void handleMoveEvent(int x, int y) {
|
||||
mDragObject.dragView.move(x, y);
|
||||
|
||||
@@ -593,10 +578,6 @@ public class DragController implements DragDriver.EventListener, TouchController
|
||||
return mLauncher.getWorkspace();
|
||||
}
|
||||
|
||||
public void setWindowToken(IBinder token) {
|
||||
mWindowToken = token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the drag listener which will be notified when a drag starts or ends.
|
||||
*/
|
||||
|
||||
@@ -21,6 +21,7 @@ import static android.view.View.MeasureSpec.EXACTLY;
|
||||
import static android.view.View.MeasureSpec.getMode;
|
||||
import static android.view.View.MeasureSpec.getSize;
|
||||
|
||||
import static com.android.launcher3.anim.Interpolators.DEACCEL_1_5;
|
||||
import static com.android.launcher3.compat.AccessibilityManagerCompat.sendCustomAccessibilityEvent;
|
||||
|
||||
import android.animation.Animator;
|
||||
@@ -49,7 +50,6 @@ import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.ShortcutAndWidgetContainer;
|
||||
import com.android.launcher3.Workspace;
|
||||
import com.android.launcher3.anim.Interpolators;
|
||||
import com.android.launcher3.folder.Folder;
|
||||
import com.android.launcher3.graphics.OverviewScrim;
|
||||
import com.android.launcher3.graphics.RotationMode;
|
||||
@@ -74,11 +74,11 @@ public class DragLayer extends BaseDragLayer<Launcher> {
|
||||
public static final int ANIMATION_END_DISAPPEAR = 0;
|
||||
public static final int ANIMATION_END_REMAIN_VISIBLE = 2;
|
||||
|
||||
@Thunk DragController mDragController;
|
||||
private DragController mDragController;
|
||||
|
||||
// Variables relating to animation of views after drop
|
||||
private ValueAnimator mDropAnim = null;
|
||||
private final TimeInterpolator mCubicEaseOutInterpolator = Interpolators.DEACCEL_1_5;
|
||||
|
||||
@Thunk DragView mDropView = null;
|
||||
@Thunk int mAnchorViewInitialScrollX = 0;
|
||||
@Thunk View mAnchorView = null;
|
||||
@@ -88,13 +88,14 @@ public class DragLayer extends BaseDragLayer<Launcher> {
|
||||
private int mTopViewIndex;
|
||||
private int mChildCountOnLastUpdate = -1;
|
||||
|
||||
private Rect mTmpRect = new Rect();
|
||||
|
||||
// Related to adjacent page hints
|
||||
private final ViewGroupFocusHelper mFocusIndicatorHelper;
|
||||
private final WorkspaceAndHotseatScrim mWorkspaceScrim;
|
||||
private final OverviewScrim mOverviewScrim;
|
||||
|
||||
// View that should handle move events
|
||||
private View mMoveTarget;
|
||||
|
||||
/**
|
||||
* Used to create a new DragLayer from XML.
|
||||
*
|
||||
@@ -116,6 +117,7 @@ public class DragLayer extends BaseDragLayer<Launcher> {
|
||||
public void setup(DragController dragController, Workspace workspace) {
|
||||
mDragController = dragController;
|
||||
mWorkspaceScrim.setWorkspace(workspace);
|
||||
mMoveTarget = workspace;
|
||||
recreateControllers();
|
||||
}
|
||||
|
||||
@@ -223,7 +225,7 @@ public class DragLayer extends BaseDragLayer<Launcher> {
|
||||
@Override
|
||||
public boolean dispatchUnhandledMove(View focused, int direction) {
|
||||
return super.dispatchUnhandledMove(focused, direction)
|
||||
|| mDragController.dispatchUnhandledMove(focused, direction);
|
||||
|| mMoveTarget.dispatchUnhandledMove(focused, direction);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -260,9 +262,10 @@ public class DragLayer extends BaseDragLayer<Launcher> {
|
||||
parentChildren.measureChild(child);
|
||||
parentChildren.layoutChild(child);
|
||||
|
||||
getViewRectRelativeToSelf(dragView, mTmpRect);
|
||||
final int fromX = mTmpRect.left;
|
||||
final int fromY = mTmpRect.top;
|
||||
Rect dragViewBounds = new Rect();
|
||||
getViewRectRelativeToSelf(dragView, dragViewBounds);
|
||||
final int fromX = dragViewBounds.left;
|
||||
final int fromY = dragViewBounds.top;
|
||||
|
||||
float coord[] = new float[2];
|
||||
float childScale = child.getScaleX();
|
||||
@@ -283,15 +286,15 @@ public class DragLayer extends BaseDragLayer<Launcher> {
|
||||
|
||||
if (child instanceof DraggableView) {
|
||||
DraggableView d = (DraggableView) child;
|
||||
d.getVisualDragBounds(mTmpRect);
|
||||
d.getVisualDragBounds(dragViewBounds);
|
||||
|
||||
// This accounts for the offset of the DragView created by scaling it about its
|
||||
// center as it animates into place.
|
||||
float scaleShiftX = dragView.getMeasuredWidth() * (1 - scale) / 2;
|
||||
float scaleShiftY = dragView.getMeasuredHeight() * (1 - scale) / 2;
|
||||
|
||||
toX += scale * (mTmpRect.left - dragView.getBlurSizeOutline() / 2) - scaleShiftX;
|
||||
toY += scale * (mTmpRect.top - dragView.getBlurSizeOutline() / 2) - scaleShiftY;
|
||||
toX += scale * (dragViewBounds.left - dragView.getBlurSizeOutline() / 2) - scaleShiftX;
|
||||
toY += scale * (dragViewBounds.top - dragView.getBlurSizeOutline() / 2) - scaleShiftY;
|
||||
}
|
||||
|
||||
child.setVisibility(INVISIBLE);
|
||||
@@ -348,7 +351,7 @@ public class DragLayer extends BaseDragLayer<Launcher> {
|
||||
if (duration < 0) {
|
||||
duration = res.getInteger(R.integer.config_dropAnimMaxDuration);
|
||||
if (dist < maxDist) {
|
||||
duration *= mCubicEaseOutInterpolator.getInterpolation(dist / maxDist);
|
||||
duration *= DEACCEL_1_5.getInterpolation(dist / maxDist);
|
||||
}
|
||||
duration = Math.max(duration, res.getInteger(R.integer.config_dropAnimMinDuration));
|
||||
}
|
||||
@@ -356,7 +359,7 @@ public class DragLayer extends BaseDragLayer<Launcher> {
|
||||
// Fall back to cubic ease out interpolator for the animation if none is specified
|
||||
TimeInterpolator interpolator = null;
|
||||
if (alphaInterpolator == null || motionInterpolator == null) {
|
||||
interpolator = mCubicEaseOutInterpolator;
|
||||
interpolator = DEACCEL_1_5;
|
||||
}
|
||||
|
||||
// Animate the view
|
||||
|
||||
@@ -31,7 +31,6 @@ import android.util.Property;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewConfiguration;
|
||||
import android.view.ViewDebug;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.FrameLayout;
|
||||
@@ -52,8 +51,6 @@ import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.LauncherSettings;
|
||||
import com.android.launcher3.OnAlarmListener;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.SimpleOnStylusPressListener;
|
||||
import com.android.launcher3.StylusEventHelper;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.Workspace;
|
||||
import com.android.launcher3.WorkspaceItemInfo;
|
||||
@@ -87,7 +84,6 @@ public class FolderIcon extends FrameLayout implements FolderListener, IconLabel
|
||||
private FolderInfo mInfo;
|
||||
|
||||
private CheckLongPressHelper mLongPressHelper;
|
||||
private StylusEventHelper mStylusEventHelper;
|
||||
|
||||
static final int DROP_IN_ANIMATION_DURATION = 400;
|
||||
|
||||
@@ -110,8 +106,6 @@ public class FolderIcon extends FrameLayout implements FolderListener, IconLabel
|
||||
|
||||
boolean mAnimating = false;
|
||||
|
||||
private float mSlop;
|
||||
|
||||
private Alarm mOpenAlarm = new Alarm();
|
||||
|
||||
private boolean mForceHideDot;
|
||||
@@ -149,9 +143,7 @@ public class FolderIcon extends FrameLayout implements FolderListener, IconLabel
|
||||
|
||||
private void init() {
|
||||
mLongPressHelper = new CheckLongPressHelper(this);
|
||||
mStylusEventHelper = new StylusEventHelper(new SimpleOnStylusPressListener(this), this);
|
||||
mPreviewLayoutRule = new ClippedFolderIconLayoutRule();
|
||||
mSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
|
||||
mPreviewItemManager = new PreviewItemManager(this);
|
||||
mDotParams = new DotRenderer.DrawParams();
|
||||
}
|
||||
@@ -663,29 +655,10 @@ public class FolderIcon extends FrameLayout implements FolderListener, IconLabel
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
// Call the superclass onTouchEvent first, because sometimes it changes the state to
|
||||
// isPressed() on an ACTION_UP
|
||||
boolean result = super.onTouchEvent(event);
|
||||
|
||||
// Check for a stylus button press, if it occurs cancel any long press checks.
|
||||
if (mStylusEventHelper.onMotionEvent(event)) {
|
||||
mLongPressHelper.cancelLongPress();
|
||||
return true;
|
||||
}
|
||||
|
||||
switch (event.getAction()) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
mLongPressHelper.postCheckForLongPress();
|
||||
break;
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
case MotionEvent.ACTION_UP:
|
||||
mLongPressHelper.cancelLongPress();
|
||||
break;
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
if (!Utilities.pointInView(this, event.getX(), event.getY(), mSlop)) {
|
||||
mLongPressHelper.cancelLongPress();
|
||||
}
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
super.onTouchEvent(event);
|
||||
mLongPressHelper.onTouchEvent(event);
|
||||
// Keep receiving the rest of the events
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -21,7 +21,6 @@ import static android.view.View.VISIBLE;
|
||||
|
||||
import static com.android.launcher3.config.FeatureFlags.ENABLE_LAUNCHER_PREVIEW_IN_GRID_PICKER;
|
||||
import static com.android.launcher3.config.FeatureFlags.MULTI_DB_GRID_MIRATION_ALGO;
|
||||
import static com.android.launcher3.model.GridSizeMigrationTask.needsToMigrate;
|
||||
import static com.android.launcher3.model.ModelUtils.filterCurrentWorkspaceItems;
|
||||
import static com.android.launcher3.model.ModelUtils.sortWorkspaceItemsSpatially;
|
||||
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
|
||||
@@ -397,7 +396,10 @@ public class LauncherPreviewRenderer implements Callable<Bitmap> {
|
||||
|
||||
private void populate() {
|
||||
if (ENABLE_LAUNCHER_PREVIEW_IN_GRID_PICKER.get()) {
|
||||
boolean needsToMigrate = needsToMigrate(mContext, mIdp);
|
||||
boolean needsToMigrate =
|
||||
MULTI_DB_GRID_MIRATION_ALGO.get()
|
||||
? GridSizeMigrationTaskV2.needsToMigrate(mContext, mIdp)
|
||||
: GridSizeMigrationTask.needsToMigrate(mContext, mIdp);
|
||||
boolean success = false;
|
||||
if (needsToMigrate) {
|
||||
success = MULTI_DB_GRID_MIRATION_ALGO.get()
|
||||
|
||||
@@ -1,169 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2017 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.logging;
|
||||
|
||||
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.os.Process;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.android.launcher3.ItemInfo;
|
||||
import com.android.launcher3.LauncherAppWidgetInfo;
|
||||
import com.android.launcher3.LauncherSettings;
|
||||
import com.android.launcher3.WorkspaceItemInfo;
|
||||
import com.android.launcher3.model.nano.LauncherDumpProto;
|
||||
import com.android.launcher3.model.nano.LauncherDumpProto.ContainerType;
|
||||
import com.android.launcher3.model.nano.LauncherDumpProto.DumpTarget;
|
||||
import com.android.launcher3.model.nano.LauncherDumpProto.ItemType;
|
||||
import com.android.launcher3.model.nano.LauncherDumpProto.UserType;
|
||||
import com.android.launcher3.util.ShortcutUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This class can be used when proto definition doesn't support nesting.
|
||||
*/
|
||||
public class DumpTargetWrapper {
|
||||
DumpTarget node;
|
||||
ArrayList<DumpTargetWrapper> children;
|
||||
|
||||
public DumpTargetWrapper() {
|
||||
children = new ArrayList<>();
|
||||
}
|
||||
|
||||
public DumpTargetWrapper(int containerType, int id) {
|
||||
this();
|
||||
node = newContainerTarget(containerType, id);
|
||||
}
|
||||
|
||||
public DumpTargetWrapper(ItemInfo info) {
|
||||
this();
|
||||
node = newItemTarget(info);
|
||||
}
|
||||
|
||||
public DumpTarget getDumpTarget() {
|
||||
return node;
|
||||
}
|
||||
|
||||
public void add(DumpTargetWrapper child) {
|
||||
children.add(child);
|
||||
}
|
||||
|
||||
public List<DumpTarget> getFlattenedList() {
|
||||
ArrayList<DumpTarget> list = new ArrayList<>();
|
||||
list.add(node);
|
||||
if (!children.isEmpty()) {
|
||||
for(DumpTargetWrapper t: children) {
|
||||
list.addAll(t.getFlattenedList());
|
||||
}
|
||||
list.add(node); // add a delimiter empty object
|
||||
}
|
||||
return list;
|
||||
}
|
||||
public DumpTarget newItemTarget(ItemInfo info) {
|
||||
DumpTarget dt = new DumpTarget();
|
||||
dt.type = DumpTarget.Type.ITEM;
|
||||
if (info == null) {
|
||||
return dt;
|
||||
}
|
||||
switch (info.itemType) {
|
||||
case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
|
||||
dt.itemType = ItemType.APP_ICON;
|
||||
break;
|
||||
case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
|
||||
dt.itemType = ItemType.WIDGET;
|
||||
break;
|
||||
case ITEM_TYPE_DEEP_SHORTCUT:
|
||||
case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
|
||||
dt.itemType = ItemType.SHORTCUT;
|
||||
break;
|
||||
default:
|
||||
dt.itemType = ItemType.UNKNOWN_ITEMTYPE;
|
||||
break;
|
||||
}
|
||||
return dt;
|
||||
}
|
||||
|
||||
public DumpTarget newContainerTarget(int type, int id) {
|
||||
DumpTarget dt = new DumpTarget();
|
||||
dt.type = DumpTarget.Type.CONTAINER;
|
||||
dt.containerType = type;
|
||||
dt.pageId = id;
|
||||
return dt;
|
||||
}
|
||||
|
||||
public static String getDumpTargetStr(DumpTarget t) {
|
||||
if (t == null){
|
||||
return "";
|
||||
}
|
||||
switch (t.type) {
|
||||
case LauncherDumpProto.DumpTarget.Type.ITEM:
|
||||
return getItemStr(t);
|
||||
case LauncherDumpProto.DumpTarget.Type.CONTAINER:
|
||||
String str = LoggerUtils.getFieldName(t.containerType, ContainerType.class);
|
||||
if (t.containerType == ContainerType.WORKSPACE) {
|
||||
str += " id=" + t.pageId;
|
||||
} else if (t.containerType == ContainerType.FOLDER) {
|
||||
str += " grid(" + t.gridX + "," + t.gridY+ ")";
|
||||
}
|
||||
return str;
|
||||
default:
|
||||
return "UNKNOWN TARGET TYPE";
|
||||
}
|
||||
}
|
||||
|
||||
private static String getItemStr(DumpTarget t) {
|
||||
if (t == null) {
|
||||
return "";
|
||||
}
|
||||
String typeStr = LoggerUtils.getFieldName(t.itemType, ItemType.class);
|
||||
if (!TextUtils.isEmpty(t.packageName)) {
|
||||
typeStr += ", package=" + t.packageName;
|
||||
}
|
||||
if (!TextUtils.isEmpty(t.component)) {
|
||||
typeStr += ", component=" + t.component;
|
||||
}
|
||||
return typeStr + ", grid(" + t.gridX + "," + t.gridY + "), span(" + t.spanX + "," + t.spanY
|
||||
+ "), pageIdx=" + t.pageId + " user=" + t.userType;
|
||||
}
|
||||
|
||||
public DumpTarget writeToDumpTarget(ItemInfo info) {
|
||||
if (info == null) {
|
||||
return node;
|
||||
}
|
||||
if (ShortcutUtil.isDeepShortcut(info)) {
|
||||
node.component = ((WorkspaceItemInfo) info).getDeepShortcutId();
|
||||
} else {
|
||||
ComponentName cmp = info.getTargetComponent();
|
||||
node.component = cmp == null ? "" : cmp.flattenToString();
|
||||
}
|
||||
node.packageName = info.getTargetComponent() == null? "":
|
||||
info.getTargetComponent().getPackageName();
|
||||
if (info instanceof LauncherAppWidgetInfo) {
|
||||
node.component = ((LauncherAppWidgetInfo) info).providerName.flattenToString();
|
||||
node.packageName = ((LauncherAppWidgetInfo) info).providerName.getPackageName();
|
||||
}
|
||||
|
||||
node.gridX = info.cellX;
|
||||
node.gridY = info.cellY;
|
||||
node.spanX = info.spanX;
|
||||
node.spanY = info.spanY;
|
||||
node.userType = (info.user.equals(Process.myUserHandle()))? UserType.DEFAULT : UserType.WORK;
|
||||
return node;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* 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.logging;
|
||||
|
||||
import static java.lang.annotation.ElementType.FIELD;
|
||||
import static java.lang.annotation.RetentionPolicy.SOURCE;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Retention(SOURCE)
|
||||
@Target(FIELD)
|
||||
public @interface LauncherUiEvent {
|
||||
/** An explanation, suitable for Android analysts, of the UI event that this log represents. */
|
||||
String doc();
|
||||
}
|
||||
|
||||
@@ -16,23 +16,44 @@
|
||||
package com.android.launcher3.logging;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.UserHandle;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.logger.LauncherAtom;
|
||||
import com.android.launcher3.logger.LauncherAtom.ItemInfo;
|
||||
import com.android.launcher3.logging.StatsLogUtils.LogStateProvider;
|
||||
import com.android.launcher3.util.ComponentKey;
|
||||
import com.android.launcher3.util.ResourceBasedOverride;
|
||||
|
||||
/**
|
||||
* Handles the user event logging in Q.
|
||||
* Handles the user event logging in R+.
|
||||
*/
|
||||
public class StatsLogManager implements ResourceBasedOverride {
|
||||
|
||||
interface EventEnum {
|
||||
int getId();
|
||||
}
|
||||
|
||||
public enum LauncherEvent implements EventEnum {
|
||||
@LauncherUiEvent(doc = "App launched from workspace, hotseat or folder in launcher")
|
||||
APP_LAUNCH_TAP(1),
|
||||
@LauncherUiEvent(doc = "Task launched from overview using TAP")
|
||||
TASK_LAUNCH_TAP(2),
|
||||
@LauncherUiEvent(doc = "Task launched from overview using SWIPE DOWN")
|
||||
TASK_LAUNCH_SWIPE_DOWN(2),
|
||||
@LauncherUiEvent(doc = "TASK dismissed from overview using SWIPE UP")
|
||||
TASK_DISMISS_SWIPE_UP(3);
|
||||
// ADD MORE
|
||||
|
||||
private final int mId;
|
||||
LauncherEvent(int id) {
|
||||
mId = id;
|
||||
}
|
||||
public int getId() {
|
||||
return mId;
|
||||
}
|
||||
}
|
||||
|
||||
protected LogStateProvider mStateProvider;
|
||||
|
||||
public static StatsLogManager newInstance(Context context, LogStateProvider stateProvider) {
|
||||
StatsLogManager mgr = Overrides.getObject(StatsLogManager.class,
|
||||
context.getApplicationContext(), R.string.stats_log_manager_class);
|
||||
@@ -42,11 +63,14 @@ public class StatsLogManager implements ResourceBasedOverride {
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs app launches
|
||||
* Logs an event and accompanying {@link ItemInfo}
|
||||
*/
|
||||
public void logAppLaunch(View v, Intent intent, @Nullable UserHandle userHandle) { }
|
||||
public void logTaskLaunch(View v, ComponentKey key) { }
|
||||
public void logTaskDismiss(View v, ComponentKey key) { }
|
||||
public void logSwipeOnContainer(boolean isSwipingToLeft, int pageId) { }
|
||||
public void log(LauncherEvent eventId, LauncherAtom.ItemInfo itemInfo) { }
|
||||
|
||||
/**
|
||||
* Logs snapshot, or impression of the current workspace.
|
||||
*/
|
||||
public void logSnapshot() { }
|
||||
|
||||
public void verify() {} // TODO: should move into robo tests
|
||||
}
|
||||
|
||||
@@ -36,10 +36,6 @@ import com.android.launcher3.PromiseAppInfo;
|
||||
import com.android.launcher3.Workspace;
|
||||
import com.android.launcher3.WorkspaceItemInfo;
|
||||
import com.android.launcher3.config.FeatureFlags;
|
||||
import com.android.launcher3.logging.DumpTargetWrapper;
|
||||
import com.android.launcher3.model.nano.LauncherDumpProto;
|
||||
import com.android.launcher3.model.nano.LauncherDumpProto.ContainerType;
|
||||
import com.android.launcher3.model.nano.LauncherDumpProto.DumpTarget;
|
||||
import com.android.launcher3.shortcuts.ShortcutKey;
|
||||
import com.android.launcher3.shortcuts.ShortcutRequest;
|
||||
import com.android.launcher3.util.ComponentKey;
|
||||
@@ -50,11 +46,7 @@ import com.android.launcher3.util.ItemInfoMatcher;
|
||||
import com.android.launcher3.util.ViewOnDrawExecutor;
|
||||
import com.android.launcher3.widget.WidgetListRowEntry;
|
||||
|
||||
import com.google.protobuf.nano.MessageNano;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@@ -150,10 +142,6 @@ public class BgDataModel {
|
||||
|
||||
public synchronized void dump(String prefix, FileDescriptor fd, PrintWriter writer,
|
||||
String[] args) {
|
||||
if (Arrays.asList(args).contains("--proto")) {
|
||||
dumpProto(prefix, fd, writer, args);
|
||||
return;
|
||||
}
|
||||
writer.println(prefix + "Data Model:");
|
||||
writer.println(prefix + " ---- workspace items ");
|
||||
for (int i = 0; i < workspaceItems.size(); i++) {
|
||||
@@ -181,89 +169,6 @@ public class BgDataModel {
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized void dumpProto(String prefix, FileDescriptor fd, PrintWriter writer,
|
||||
String[] args) {
|
||||
|
||||
// Add top parent nodes. (L1)
|
||||
DumpTargetWrapper hotseat = new DumpTargetWrapper(ContainerType.HOTSEAT, 0);
|
||||
IntSparseArrayMap<DumpTargetWrapper> workspaces = new IntSparseArrayMap<>();
|
||||
IntArray workspaceScreens = collectWorkspaceScreens();
|
||||
for (int i = 0; i < workspaceScreens.size(); i++) {
|
||||
workspaces.put(workspaceScreens.get(i),
|
||||
new DumpTargetWrapper(ContainerType.WORKSPACE, i));
|
||||
}
|
||||
DumpTargetWrapper dtw;
|
||||
// Add non leaf / non top nodes (L2)
|
||||
for (int i = 0; i < folders.size(); i++) {
|
||||
FolderInfo fInfo = folders.valueAt(i);
|
||||
dtw = new DumpTargetWrapper(ContainerType.FOLDER, folders.size());
|
||||
dtw.writeToDumpTarget(fInfo);
|
||||
for(WorkspaceItemInfo sInfo: fInfo.contents) {
|
||||
DumpTargetWrapper child = new DumpTargetWrapper(sInfo);
|
||||
child.writeToDumpTarget(sInfo);
|
||||
dtw.add(child);
|
||||
}
|
||||
if (fInfo.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {
|
||||
hotseat.add(dtw);
|
||||
} else if (fInfo.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {
|
||||
workspaces.get(fInfo.screenId).add(dtw);
|
||||
}
|
||||
}
|
||||
// Add leaf nodes (L3): *Info
|
||||
for (int i = 0; i < workspaceItems.size(); i++) {
|
||||
ItemInfo info = workspaceItems.get(i);
|
||||
if (info instanceof FolderInfo) {
|
||||
continue;
|
||||
}
|
||||
dtw = new DumpTargetWrapper(info);
|
||||
dtw.writeToDumpTarget(info);
|
||||
if (info.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {
|
||||
hotseat.add(dtw);
|
||||
} else if (info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {
|
||||
workspaces.get(info.screenId).add(dtw);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < appWidgets.size(); i++) {
|
||||
ItemInfo info = appWidgets.get(i);
|
||||
dtw = new DumpTargetWrapper(info);
|
||||
dtw.writeToDumpTarget(info);
|
||||
if (info.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {
|
||||
hotseat.add(dtw);
|
||||
} else if (info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {
|
||||
workspaces.get(info.screenId).add(dtw);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Traverse target wrapper
|
||||
ArrayList<DumpTarget> targetList = new ArrayList<>();
|
||||
targetList.addAll(hotseat.getFlattenedList());
|
||||
for (int i = 0; i < workspaces.size(); i++) {
|
||||
targetList.addAll(workspaces.valueAt(i).getFlattenedList());
|
||||
}
|
||||
|
||||
if (Arrays.asList(args).contains("--debug")) {
|
||||
for (int i = 0; i < targetList.size(); i++) {
|
||||
writer.println(prefix + DumpTargetWrapper.getDumpTargetStr(targetList.get(i)));
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
LauncherDumpProto.LauncherImpression proto = new LauncherDumpProto.LauncherImpression();
|
||||
proto.targets = new DumpTarget[targetList.size()];
|
||||
for (int i = 0; i < targetList.size(); i++) {
|
||||
proto.targets[i] = targetList.get(i);
|
||||
}
|
||||
FileOutputStream fos = new FileOutputStream(fd);
|
||||
try {
|
||||
|
||||
fos.write(MessageNano.toByteArray(proto));
|
||||
Log.d(TAG, MessageNano.toByteArray(proto).length + "Bytes");
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Exception writing dumpsys --proto", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void removeItem(Context context, ItemInfo... items) {
|
||||
removeItem(context, Arrays.asList(items));
|
||||
}
|
||||
|
||||
@@ -123,8 +123,16 @@ public class GridSizeMigrationTaskV2 {
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the migration algorithm if needed. For preview, we provide the intended idp because it
|
||||
* has not been changed. If idp is null, we read it from the context, for actual grid migration.
|
||||
* When migrating the grid for preview, we copy the table
|
||||
* {@link LauncherSettings.Favorites.TABLE_NAME} into
|
||||
* {@link LauncherSettings.Favorites.PREVIEW_TABLE_NAME}, run grid size migration from the
|
||||
* former to the later, then use the later table for preview.
|
||||
*
|
||||
* Similarly when doing the actual grid migration, the former grid option's table
|
||||
* {@link LauncherSettings.Favorites.TABLE_NAME} is copied into the new grid option's
|
||||
* {@link LauncherSettings.Favorites.TMP_TABLE}, we then run the grid size migration algorithm
|
||||
* to migrate the later to the former, and load the workspace from the default
|
||||
* {@link LauncherSettings.Favorites.TABLE_NAME}.
|
||||
*
|
||||
* @return false if the migration failed.
|
||||
*/
|
||||
@@ -151,7 +159,14 @@ public class GridSizeMigrationTaskV2 {
|
||||
HashSet<String> validPackages = getValidPackages(context);
|
||||
int srcHotseatCount = prefs.getInt(KEY_MIGRATION_SRC_HOTSEAT_COUNT, idp.numHotseatIcons);
|
||||
|
||||
if (!LauncherSettings.Settings.call(
|
||||
if (migrateForPreview) {
|
||||
if (!LauncherSettings.Settings.call(
|
||||
context.getContentResolver(),
|
||||
LauncherSettings.Settings.METHOD_PREP_FOR_PREVIEW, idp.dbFile).getBoolean(
|
||||
LauncherSettings.Settings.EXTRA_VALUE)) {
|
||||
return false;
|
||||
}
|
||||
} else if (!LauncherSettings.Settings.call(
|
||||
context.getContentResolver(),
|
||||
LauncherSettings.Settings.METHOD_UPDATE_CURRENT_OPEN_HELPER).getBoolean(
|
||||
LauncherSettings.Settings.EXTRA_VALUE)) {
|
||||
@@ -164,9 +179,13 @@ public class GridSizeMigrationTaskV2 {
|
||||
LauncherSettings.Settings.METHOD_NEW_TRANSACTION).getBinder(
|
||||
LauncherSettings.Settings.EXTRA_VALUE)) {
|
||||
|
||||
DbReader srcReader = new DbReader(t.getDb(), LauncherSettings.Favorites.TMP_TABLE,
|
||||
DbReader srcReader = new DbReader(t.getDb(),
|
||||
migrateForPreview ? LauncherSettings.Favorites.TABLE_NAME
|
||||
: LauncherSettings.Favorites.TMP_TABLE,
|
||||
context, validPackages, srcHotseatCount);
|
||||
DbReader destReader = new DbReader(t.getDb(), LauncherSettings.Favorites.TABLE_NAME,
|
||||
DbReader destReader = new DbReader(t.getDb(),
|
||||
migrateForPreview ? LauncherSettings.Favorites.PREVIEW_TABLE_NAME
|
||||
: LauncherSettings.Favorites.TABLE_NAME,
|
||||
context, validPackages, idp.numHotseatIcons);
|
||||
|
||||
Point targetSize = new Point(idp.numColumns, idp.numRows);
|
||||
@@ -174,7 +193,9 @@ public class GridSizeMigrationTaskV2 {
|
||||
srcReader, destReader, idp.numHotseatIcons, targetSize);
|
||||
task.migrate();
|
||||
|
||||
dropTable(t.getDb(), LauncherSettings.Favorites.TMP_TABLE);
|
||||
if (!migrateForPreview) {
|
||||
dropTable(t.getDb(), LauncherSettings.Favorites.TMP_TABLE);
|
||||
}
|
||||
|
||||
t.commit();
|
||||
return true;
|
||||
@@ -186,11 +207,13 @@ public class GridSizeMigrationTaskV2 {
|
||||
Log.v(TAG, "Workspace migration completed in "
|
||||
+ (System.currentTimeMillis() - migrationStartTime));
|
||||
|
||||
// Save current configuration, so that the migration does not run again.
|
||||
prefs.edit()
|
||||
.putString(KEY_MIGRATION_SRC_WORKSPACE_SIZE, gridSizeString)
|
||||
.putInt(KEY_MIGRATION_SRC_HOTSEAT_COUNT, idp.numHotseatIcons)
|
||||
.apply();
|
||||
if (!migrateForPreview) {
|
||||
// Save current configuration, so that the migration does not run again.
|
||||
prefs.edit()
|
||||
.putString(KEY_MIGRATION_SRC_WORKSPACE_SIZE, gridSizeString)
|
||||
.putInt(KEY_MIGRATION_SRC_HOTSEAT_COUNT, idp.numHotseatIcons)
|
||||
.apply();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -202,7 +225,7 @@ public class GridSizeMigrationTaskV2 {
|
||||
|
||||
// Migrate hotseat
|
||||
HotseatPlacementSolution hotseatSolution = new HotseatPlacementSolution(mDb, mSrcReader,
|
||||
mContext, mDestHotseatSize, mHotseatItems, mHotseatDiff);
|
||||
mDestReader, mContext, mDestHotseatSize, mHotseatItems, mHotseatDiff);
|
||||
hotseatSolution.find();
|
||||
|
||||
// Sort the items by the reading order.
|
||||
@@ -215,7 +238,7 @@ public class GridSizeMigrationTaskV2 {
|
||||
}
|
||||
List<DbEntry> entries = mDestReader.loadWorkspaceEntries(screenId);
|
||||
GridPlacementSolution workspaceSolution = new GridPlacementSolution(mDb, mSrcReader,
|
||||
mContext, entries, screenId, mTrgX, mTrgY, mWorkspaceDiff);
|
||||
mDestReader, mContext, entries, screenId, mTrgX, mTrgY, mWorkspaceDiff);
|
||||
workspaceSolution.find();
|
||||
if (mWorkspaceDiff.isEmpty()) {
|
||||
break;
|
||||
@@ -225,7 +248,8 @@ public class GridSizeMigrationTaskV2 {
|
||||
int screenId = mDestReader.mLastScreenId + 1;
|
||||
while (!mWorkspaceDiff.isEmpty()) {
|
||||
GridPlacementSolution workspaceSolution = new GridPlacementSolution(mDb, mSrcReader,
|
||||
mContext, new ArrayList<>(), screenId, mTrgX, mTrgY, mWorkspaceDiff);
|
||||
mDestReader, mContext, new ArrayList<>(), screenId, mTrgX, mTrgY,
|
||||
mWorkspaceDiff);
|
||||
workspaceSolution.find();
|
||||
screenId++;
|
||||
}
|
||||
@@ -246,7 +270,8 @@ public class GridSizeMigrationTaskV2 {
|
||||
}
|
||||
|
||||
private static void insertEntryInDb(SQLiteDatabase db, Context context,
|
||||
ArrayList<DbEntry> entriesFromSrcDb, DbEntry entry) {
|
||||
ArrayList<DbEntry> entriesFromSrcDb, DbEntry entry, String srcTableName,
|
||||
String destTableName) {
|
||||
int id = -1;
|
||||
switch (entry.itemType) {
|
||||
case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
|
||||
@@ -283,8 +308,8 @@ public class GridSizeMigrationTaskV2 {
|
||||
return;
|
||||
}
|
||||
|
||||
Cursor c = db.query(LauncherSettings.Favorites.TMP_TABLE, null,
|
||||
LauncherSettings.Favorites._ID + " = '" + id + "'", null, null, null, null);
|
||||
Cursor c = db.query(srcTableName, null, LauncherSettings.Favorites._ID + " = '" + id + "'",
|
||||
null, null, null, null);
|
||||
|
||||
while (c.moveToNext()) {
|
||||
ContentValues values = new ContentValues();
|
||||
@@ -294,14 +319,14 @@ public class GridSizeMigrationTaskV2 {
|
||||
LauncherSettings.Settings.call(context.getContentResolver(),
|
||||
LauncherSettings.Settings.METHOD_NEW_ITEM_ID).getInt(
|
||||
LauncherSettings.Settings.EXTRA_VALUE));
|
||||
db.insert(LauncherSettings.Favorites.TABLE_NAME, null, values);
|
||||
db.insert(destTableName, null, values);
|
||||
}
|
||||
c.close();
|
||||
}
|
||||
|
||||
private static void removeEntryFromDb(SQLiteDatabase db, IntArray entryId) {
|
||||
db.delete(LauncherSettings.Favorites.TABLE_NAME, Utilities.createDbSelectionQuery(
|
||||
LauncherSettings.Favorites._ID, entryId), null);
|
||||
private static void removeEntryFromDb(SQLiteDatabase db, String tableName, IntArray entryId) {
|
||||
db.delete(tableName,
|
||||
Utilities.createDbSelectionQuery(LauncherSettings.Favorites._ID, entryId), null);
|
||||
}
|
||||
|
||||
private static HashSet<String> getValidPackages(Context context) {
|
||||
@@ -325,6 +350,7 @@ public class GridSizeMigrationTaskV2 {
|
||||
|
||||
private final SQLiteDatabase mDb;
|
||||
private final DbReader mSrcReader;
|
||||
private final DbReader mDestReader;
|
||||
private final Context mContext;
|
||||
private final GridOccupancy mOccupied;
|
||||
private final int mScreenId;
|
||||
@@ -335,11 +361,12 @@ public class GridSizeMigrationTaskV2 {
|
||||
private int mNextStartX;
|
||||
private int mNextStartY;
|
||||
|
||||
GridPlacementSolution(SQLiteDatabase db, DbReader srcReader, Context context,
|
||||
List<DbEntry> placedWorkspaceItems, int screenId, int trgX,
|
||||
GridPlacementSolution(SQLiteDatabase db, DbReader srcReader, DbReader destReader,
|
||||
Context context, List<DbEntry> placedWorkspaceItems, int screenId, int trgX,
|
||||
int trgY, List<DbEntry> itemsToPlace) {
|
||||
mDb = db;
|
||||
mSrcReader = srcReader;
|
||||
mDestReader = destReader;
|
||||
mContext = context;
|
||||
mOccupied = new GridOccupancy(trgX, trgY);
|
||||
mScreenId = screenId;
|
||||
@@ -362,7 +389,8 @@ public class GridSizeMigrationTaskV2 {
|
||||
continue;
|
||||
}
|
||||
if (findPlacement(entry)) {
|
||||
insertEntryInDb(mDb, mContext, mSrcReader.mWorkspaceEntries, entry);
|
||||
insertEntryInDb(mDb, mContext, mSrcReader.mWorkspaceEntries, entry,
|
||||
mSrcReader.mTableName, mDestReader.mTableName);
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
@@ -397,14 +425,17 @@ public class GridSizeMigrationTaskV2 {
|
||||
|
||||
private final SQLiteDatabase mDb;
|
||||
private final DbReader mSrcReader;
|
||||
private final DbReader mDestReader;
|
||||
private final Context mContext;
|
||||
private final HotseatOccupancy mOccupied;
|
||||
private final List<DbEntry> mItemsToPlace;
|
||||
|
||||
HotseatPlacementSolution(SQLiteDatabase db, DbReader srcReader, Context context,
|
||||
int hotseatSize, List<DbEntry> placedHotseatItems, List<DbEntry> itemsToPlace) {
|
||||
HotseatPlacementSolution(SQLiteDatabase db, DbReader srcReader, DbReader destReader,
|
||||
Context context, int hotseatSize, List<DbEntry> placedHotseatItems,
|
||||
List<DbEntry> itemsToPlace) {
|
||||
mDb = db;
|
||||
mSrcReader = srcReader;
|
||||
mDestReader = destReader;
|
||||
mContext = context;
|
||||
mOccupied = new HotseatOccupancy(hotseatSize);
|
||||
for (DbEntry entry : placedHotseatItems) {
|
||||
@@ -422,7 +453,8 @@ public class GridSizeMigrationTaskV2 {
|
||||
// to something other than -1.
|
||||
entry.cellX = i;
|
||||
entry.cellY = 0;
|
||||
insertEntryInDb(mDb, mContext, mSrcReader.mHotseatEntries, entry);
|
||||
insertEntryInDb(mDb, mContext, mSrcReader.mHotseatEntries, entry,
|
||||
mSrcReader.mTableName, mDestReader.mTableName);
|
||||
mOccupied.markCells(entry, true);
|
||||
}
|
||||
}
|
||||
@@ -519,7 +551,7 @@ public class GridSizeMigrationTaskV2 {
|
||||
}
|
||||
mHotseatEntries.add(entry);
|
||||
}
|
||||
removeEntryFromDb(mDb, entriesToRemove);
|
||||
removeEntryFromDb(mDb, mTableName, entriesToRemove);
|
||||
c.close();
|
||||
return mHotseatEntries;
|
||||
}
|
||||
@@ -639,7 +671,7 @@ public class GridSizeMigrationTaskV2 {
|
||||
}
|
||||
mWorkspaceEntries.add(entry);
|
||||
}
|
||||
removeEntryFromDb(mDb, entriesToRemove);
|
||||
removeEntryFromDb(mDb, mTableName, entriesToRemove);
|
||||
c.close();
|
||||
return mWorkspaceEntries;
|
||||
}
|
||||
@@ -657,7 +689,7 @@ public class GridSizeMigrationTaskV2 {
|
||||
total++;
|
||||
entry.mFolderItems.add(intent);
|
||||
} catch (Exception e) {
|
||||
removeEntryFromDb(mDb, IntArray.wrap(c.getInt(0)));
|
||||
removeEntryFromDb(mDb, mTableName, IntArray.wrap(c.getInt(0)));
|
||||
}
|
||||
}
|
||||
c.close();
|
||||
|
||||
@@ -35,6 +35,8 @@ import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.util.LongSparseArray;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
|
||||
import com.android.launcher3.AppInfo;
|
||||
import com.android.launcher3.InvariantDeviceProfile;
|
||||
import com.android.launcher3.ItemInfo;
|
||||
@@ -150,8 +152,10 @@ public class LoaderCursor extends CursorWrapper {
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public WorkspaceItemInfo loadSimpleWorkspaceItem() {
|
||||
final WorkspaceItemInfo info = new WorkspaceItemInfo();
|
||||
info.intent = new Intent();
|
||||
// Non-app shortcuts are only supported for current user.
|
||||
info.user = user;
|
||||
info.itemType = itemType;
|
||||
|
||||
@@ -95,7 +95,7 @@ public class UserCache {
|
||||
|
||||
private void removeUserChangeListener(Runnable command) {
|
||||
synchronized (this) {
|
||||
mUserChangeListeners.add(command);
|
||||
mUserChangeListeners.remove(command);
|
||||
if (mUserChangeListeners.isEmpty()) {
|
||||
// Disable cache and stop listening
|
||||
mContext.unregisterReceiver(mUserChangeReceiver);
|
||||
|
||||
@@ -129,6 +129,7 @@ public class LauncherDbUtils {
|
||||
toDb.execSQL("ATTACH DATABASE '" + fromDb.getPath() + "' AS from_db");
|
||||
toDb.execSQL(
|
||||
"INSERT INTO " + toTable + " SELECT * FROM from_db." + fromTable);
|
||||
toDb.execSQL("DETACH DATABASE 'from_db'");
|
||||
} else {
|
||||
toDb.execSQL("INSERT INTO " + toTable + " SELECT * FROM " + fromTable);
|
||||
}
|
||||
|
||||
@@ -15,10 +15,12 @@
|
||||
*/
|
||||
package com.android.launcher3.states;
|
||||
|
||||
import static android.Manifest.permission.WRITE_SECURE_SETTINGS;
|
||||
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LOCKED;
|
||||
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
|
||||
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
|
||||
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
|
||||
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
|
||||
import static android.util.DisplayMetrics.DENSITY_DEVICE_STABLE;
|
||||
|
||||
import static com.android.launcher3.config.FeatureFlags.FLAG_ENABLE_FIXED_ROTATION_TRANSFORM;
|
||||
@@ -37,7 +39,6 @@ import android.view.Surface;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.PagedView;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.config.FeatureFlags;
|
||||
@@ -142,9 +143,12 @@ public class RotationHelper implements OnSharedPreferenceChangeListener {
|
||||
if (setValueFromPrefs) {
|
||||
mForcedRotation = isForcedRotation;
|
||||
}
|
||||
UI_HELPER_EXECUTOR.execute(
|
||||
() -> Settings.Global.putInt(mContentResolver, FIXED_ROTATION_TRANSFORM_SETTING_NAME,
|
||||
mForcedRotation ? 1 : 0));
|
||||
UI_HELPER_EXECUTOR.execute(() -> {
|
||||
if (mLauncher.checkSelfPermission(WRITE_SECURE_SETTINGS) == PERMISSION_GRANTED) {
|
||||
Settings.Global.putInt(mContentResolver, FIXED_ROTATION_TRANSFORM_SETTING_NAME,
|
||||
mForcedRotation ? 1 : 0);
|
||||
}
|
||||
});
|
||||
for (ForcedRotationChangedListener listener : mForcedRotationChangedListeners) {
|
||||
listener.onForcedRotationChanged(mForcedRotation);
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ package com.android.launcher3.states;
|
||||
|
||||
import static com.android.launcher3.states.RotationHelper.REQUEST_LOCK;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Rect;
|
||||
|
||||
import com.android.launcher3.DeviceProfile;
|
||||
@@ -76,6 +77,11 @@ public class SpringLoadedState extends LauncherState {
|
||||
return new ScaleAndTranslation(scale, 0, (desiredCellTop - actualCellTop) / scale);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getDepth(Context context) {
|
||||
return 0.5f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScaleAndTranslation getHotseatScaleAndTranslation(Launcher launcher) {
|
||||
return new ScaleAndTranslation(1, 0, 0);
|
||||
|
||||
@@ -35,6 +35,7 @@ public final class TestProtocol {
|
||||
public static final String TAPL_EVENTS_TAG = "TaplEvents";
|
||||
public static final String SEQUENCE_MAIN = "Main";
|
||||
public static final String SEQUENCE_TIS = "TIS";
|
||||
public static final String SEQUENCE_PILFER = "Pilfer";
|
||||
|
||||
public static String stateOrdinalToString(int ordinal) {
|
||||
switch (ordinal) {
|
||||
@@ -95,4 +96,6 @@ public final class TestProtocol {
|
||||
|
||||
public static final String NO_BACKGROUND_TO_OVERVIEW_TAG = "b/138251824";
|
||||
public static final String APP_NOT_DISABLED = "b/139891609";
|
||||
public static final String NO_SCROLL_END_WIDGETS = "b/152354290";
|
||||
public static final String NO_START_FROM_RECENTS = "b/152658211";
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user