Snap for 7863959 from 92a6bccb4c to tm-release

Change-Id: I1a2b1fc9a95f7029512f450525ff8c7e9c3cec79
This commit is contained in:
Android Build Coastguard Worker
2021-10-29 01:08:35 +00:00
18 changed files with 265 additions and 112 deletions
@@ -73,6 +73,7 @@
launcher:containerType="hotseat" />
<LinearLayout
android:id="@+id/button_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="@dimen/bottom_sheet_edu_padding"
+2
View File
@@ -193,6 +193,8 @@
<string name="action_split">Split</string>
<!-- Label for toast with instructions for split screen selection mode. [CHAR_LIMIT=50] -->
<string name="toast_split_select_app">Tap another app to use splitscreen</string>
<!-- Label for toast when app selected for split isn't supported. [CHAR_LIMIT=50] -->
<string name="toast_split_app_unsupported">App does not support split-screen.</string>
<!-- Message shown when an action is blocked by a policy enforced by the app or the organization managing the device. [CHAR_LIMIT=NONE] -->
<string name="blocked_by_policy">This action isn\'t allowed by the app or your organization</string>
@@ -28,17 +28,20 @@ import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.CellLayout;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Insettable;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.Launcher;
import com.android.launcher3.R;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.uioverrides.ApiWrapper;
import com.android.launcher3.uioverrides.PredictedAppIcon;
import com.android.launcher3.views.AbstractSlideInView;
@@ -89,8 +92,9 @@ public class HotseatEduDialog extends AbstractSlideInView<Launcher> implements I
mHotseatWrapper = findViewById(R.id.hotseat_wrapper);
mSampleHotseat = findViewById(R.id.sample_prediction);
Context context = getContext();
DeviceProfile grid = mActivityContext.getDeviceProfile();
Rect padding = grid.getHotseatLayoutPadding(getContext());
Rect padding = grid.getHotseatLayoutPadding(context);
mSampleHotseat.getLayoutParams().height = grid.cellHeightPx;
mSampleHotseat.setGridSize(grid.numShownHotseatIcons, 1);
@@ -102,6 +106,15 @@ public class HotseatEduDialog extends AbstractSlideInView<Launcher> implements I
mDismissBtn = findViewById(R.id.no_thanks);
mDismissBtn.setOnClickListener(this::onDismiss);
LinearLayout buttonContainer = findViewById(R.id.button_container);
int adjustedMarginEnd = ApiWrapper.getHotseatEndOffset(context)
- buttonContainer.getPaddingEnd();
if (InvariantDeviceProfile.INSTANCE.get(context)
.getDeviceProfile(context).isTaskbarPresent && adjustedMarginEnd > 0) {
((LinearLayout.LayoutParams) buttonContainer.getLayoutParams()).setMarginEnd(
adjustedMarginEnd);
}
// update ui to reflect which migration method is going to be used
if (FeatureFlags.HOTSEAT_MIGRATE_TO_FOLDER.get()) {
((TextView) findViewById(R.id.hotseat_edu_content)).setText(
@@ -16,33 +16,25 @@
package com.android.launcher3.hybridhotseat;
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION;
import static com.android.launcher3.model.PredictionHelper.getAppTargetFromItemInfo;
import static com.android.launcher3.model.PredictionHelper.isTrackedForHotseatPrediction;
import static com.android.launcher3.model.PredictionHelper.wrapAppTargetWithItemLocation;
import android.app.prediction.AppTarget;
import android.app.prediction.AppTargetEvent;
import android.app.prediction.AppTargetId;
import android.content.ComponentName;
import android.content.Context;
import android.os.Bundle;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.Workspace;
import com.android.launcher3.model.BgDataModel;
import com.android.launcher3.model.BgDataModel.FixedContainerItems;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.shortcuts.ShortcutKey;
import java.util.ArrayList;
import java.util.Locale;
/**
* Model helper for app predictions in workspace
*/
public class HotseatPredictionModel {
private static final String APP_LOCATION_HOTSEAT = "hotseat";
private static final String APP_LOCATION_WORKSPACE = "workspace";
private static final String BUNDLE_KEY_PIN_EVENTS = "pin_events";
private static final String BUNDLE_KEY_CURRENT_ITEMS = "current_items";
@@ -54,15 +46,15 @@ public class HotseatPredictionModel {
ArrayList<AppTargetEvent> events = new ArrayList<>();
ArrayList<ItemInfo> workspaceItems = dataModel.getAllWorkspaceItems();
for (ItemInfo item : workspaceItems) {
AppTarget target = getAppTargetFromInfo(context, item);
if (target != null && !isTrackedForPrediction(item)) continue;
events.add(wrapAppTargetWithLocation(target, AppTargetEvent.ACTION_PIN, item));
AppTarget target = getAppTargetFromItemInfo(context, item);
if (target != null && !isTrackedForHotseatPrediction(item)) continue;
events.add(wrapAppTargetWithItemLocation(target, AppTargetEvent.ACTION_PIN, item));
}
ArrayList<AppTarget> currentTargets = new ArrayList<>();
FixedContainerItems hotseatItems = dataModel.extraItems.get(CONTAINER_HOTSEAT_PREDICTION);
if (hotseatItems != null) {
for (ItemInfo itemInfo : hotseatItems.items) {
AppTarget target = getAppTargetFromInfo(context, itemInfo);
AppTarget target = getAppTargetFromItemInfo(context, itemInfo);
if (target != null) currentTargets.add(target);
}
}
@@ -70,56 +62,4 @@ public class HotseatPredictionModel {
bundle.putParcelableArrayList(BUNDLE_KEY_CURRENT_ITEMS, currentTargets);
return bundle;
}
/**
* Creates and returns for {@link AppTarget} object given an {@link ItemInfo}. Returns null
* if item is not supported prediction
*/
public static AppTarget getAppTargetFromInfo(Context context, ItemInfo info) {
if (info == null) return null;
if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET
&& info instanceof LauncherAppWidgetInfo
&& ((LauncherAppWidgetInfo) info).providerName != null) {
ComponentName cn = ((LauncherAppWidgetInfo) info).providerName;
return new AppTarget.Builder(new AppTargetId("widget:" + cn.getPackageName()),
cn.getPackageName(), info.user).setClassName(cn.getClassName()).build();
} else if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION
&& info.getTargetComponent() != null) {
ComponentName cn = info.getTargetComponent();
return new AppTarget.Builder(new AppTargetId("app:" + cn.getPackageName()),
cn.getPackageName(), info.user).setClassName(cn.getClassName()).build();
} else if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT
&& info instanceof WorkspaceItemInfo) {
ShortcutKey shortcutKey = ShortcutKey.fromItemInfo(info);
//TODO: switch to using full shortcut info
return new AppTarget.Builder(new AppTargetId("shortcut:" + shortcutKey.getId()),
shortcutKey.componentName.getPackageName(), shortcutKey.user).build();
} else if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_FOLDER) {
return new AppTarget.Builder(new AppTargetId("folder:" + info.id),
context.getPackageName(), info.user).build();
}
return null;
}
/**
* Creates and returns {@link AppTargetEvent} from an {@link AppTarget}, action, and item
* location using {@link ItemInfo}
*/
public static AppTargetEvent wrapAppTargetWithLocation(
AppTarget target, int action, ItemInfo info) {
String location = String.format(Locale.ENGLISH, "%s/%d/[%d,%d]/[%d,%d]",
info.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT
? APP_LOCATION_HOTSEAT : APP_LOCATION_WORKSPACE,
info.screenId, info.cellX, info.cellY, info.spanX, info.spanY);
return new AppTargetEvent.Builder(target, action).setLaunchLocation(location).build();
}
/**
* Helper method to determine if {@link ItemInfo} should be tracked and reported to predictors
*/
public static boolean isTrackedForPrediction(ItemInfo info) {
return info.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT || (
info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP
&& info.screenId == Workspace.FIRST_SCREEN_ID);
}
}
@@ -22,6 +22,7 @@ import static android.app.prediction.AppTargetEvent.ACTION_UNPIN;
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION;
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_PREDICTION;
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_WIDGETS_PREDICTION;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_APP_LAUNCH_TAP;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_FOLDER_CONVERTED_TO_ICON;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_HOTSEAT_PREDICTION_PINNED;
@@ -35,6 +36,8 @@ import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCH
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_QUICKSWITCH_RIGHT;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_LAUNCH_SWIPE_DOWN;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_LAUNCH_TAP;
import static com.android.launcher3.model.PredictionHelper.isTrackedForHotseatPrediction;
import static com.android.launcher3.model.PredictionHelper.isTrackedForWidgetPrediction;
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
import android.annotation.TargetApi;
@@ -62,7 +65,6 @@ import com.android.launcher3.logger.LauncherAtom.FolderContainer;
import com.android.launcher3.logger.LauncherAtom.HotseatContainer;
import com.android.launcher3.logger.LauncherAtom.WorkspaceContainer;
import com.android.launcher3.logging.StatsLogManager.EventEnum;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.pm.UserCache;
import com.android.launcher3.shortcuts.ShortcutRequest;
import com.android.quickstep.logging.StatsLogCompatManager.StatsLogConsumer;
@@ -141,6 +143,9 @@ public class AppEventProducer implements StatsLogConsumer {
if (isTrackedForHotseatPrediction(mLastDragItem)) {
sendEvent(mLastDragItem, ACTION_UNPIN, CONTAINER_HOTSEAT_PREDICTION);
}
if (isTrackedForWidgetPrediction(atomInfo)) {
sendEvent(atomInfo, ACTION_PIN, CONTAINER_WIDGETS_PREDICTION);
}
mLastDragItem = null;
} else if (event == LAUNCHER_ITEM_DROP_FOLDER_CREATED) {
if (isTrackedForHotseatPrediction(atomInfo)) {
@@ -158,12 +163,15 @@ public class AppEventProducer implements StatsLogConsumer {
if (mLastDragItem != null && isTrackedForHotseatPrediction(mLastDragItem)) {
sendEvent(mLastDragItem, ACTION_UNPIN, CONTAINER_HOTSEAT_PREDICTION);
}
if (mLastDragItem != null && isTrackedForWidgetPrediction(mLastDragItem)) {
sendEvent(mLastDragItem, ACTION_UNPIN, CONTAINER_WIDGETS_PREDICTION);
}
} else if (event == LAUNCHER_HOTSEAT_PREDICTION_PINNED) {
if (isTrackedForHotseatPrediction(atomInfo)) {
sendEvent(atomInfo, ACTION_PIN, CONTAINER_HOTSEAT_PREDICTION);
}
} else if (event == LAUNCHER_ONRESUME) {
AppTarget target = new AppTarget.Builder(new AppTargetId("id:launcher"),
AppTarget target = new AppTarget.Builder(new AppTargetId("launcher:launcher"),
mContext.getPackageName(), Process.myUserHandle())
.build();
sendEvent(target, atomInfo, ACTION_LAUNCH, CONTAINER_PREDICTION);
@@ -302,19 +310,4 @@ public class AppEventProducer implements StatsLogConsumer {
return TextUtils.isEmpty(componentNameString)
? null : ComponentName.unflattenFromString(componentNameString);
}
/**
* Helper method to determine if {@link ItemInfo} should be tracked and reported to predictors
*/
private static boolean isTrackedForHotseatPrediction(LauncherAtom.ItemInfo info) {
ContainerInfo ci = info.getContainerInfo();
switch (ci.getContainerCase()) {
case HOTSEAT:
return true;
case WORKSPACE:
return ci.getWorkspace().getPageIndex() == 0;
default:
return false;
}
}
}
@@ -0,0 +1,130 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.launcher3.model;
import static com.android.launcher3.logger.LauncherAtom.ContainerInfo.ContainerCase.WORKSPACE;
import android.app.prediction.AppTarget;
import android.app.prediction.AppTargetEvent;
import android.app.prediction.AppTargetId;
import android.content.ComponentName;
import android.content.Context;
import androidx.annotation.Nullable;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.Workspace;
import com.android.launcher3.logger.LauncherAtom;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.shortcuts.ShortcutKey;
import java.util.Locale;
/** Helper class with methods for converting launcher items to form usable by predictors */
public final class PredictionHelper {
private static final String APP_LOCATION_HOTSEAT = "hotseat";
private static final String APP_LOCATION_WORKSPACE = "workspace";
/**
* Creates and returns an {@link AppTarget} object for an {@link ItemInfo}. Returns null
* if item type is not supported in predictions
*/
@Nullable
public static AppTarget getAppTargetFromItemInfo(Context context, ItemInfo info) {
if (info == null) return null;
if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET
&& info instanceof LauncherAppWidgetInfo
&& ((LauncherAppWidgetInfo) info).providerName != null) {
ComponentName cn = ((LauncherAppWidgetInfo) info).providerName;
return new AppTarget.Builder(new AppTargetId("widget:" + cn.getPackageName()),
cn.getPackageName(), info.user).setClassName(cn.getClassName()).build();
} else if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION
&& info.getTargetComponent() != null) {
ComponentName cn = info.getTargetComponent();
return new AppTarget.Builder(new AppTargetId("app:" + cn.getPackageName()),
cn.getPackageName(), info.user).setClassName(cn.getClassName()).build();
} else if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT
&& info instanceof WorkspaceItemInfo) {
ShortcutKey shortcutKey = ShortcutKey.fromItemInfo(info);
//TODO: switch to using full shortcut info
return new AppTarget.Builder(new AppTargetId("shortcut:" + shortcutKey.getId()),
shortcutKey.componentName.getPackageName(), shortcutKey.user).build();
} else if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_FOLDER) {
return new AppTarget.Builder(new AppTargetId("folder:" + info.id),
context.getPackageName(), info.user).build();
}
return null;
}
/**
* Creates and returns {@link AppTargetEvent} from an {@link AppTarget}, action, and item
* location using {@link ItemInfo}
*/
public static AppTargetEvent wrapAppTargetWithItemLocation(
AppTarget target, int action, ItemInfo info) {
String location = String.format(Locale.ENGLISH, "%s/%d/[%d,%d]/[%d,%d]",
info.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT
? APP_LOCATION_HOTSEAT : APP_LOCATION_WORKSPACE,
info.screenId, info.cellX, info.cellY, info.spanX, info.spanY);
return new AppTargetEvent.Builder(target, action).setLaunchLocation(location).build();
}
/**
* Helper method to determine if {@link ItemInfo} should be tracked and reported to hotseat
* predictors
*/
public static boolean isTrackedForHotseatPrediction(ItemInfo info) {
return info.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT || (
info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP
&& info.screenId == Workspace.FIRST_SCREEN_ID);
}
/**
* Helper method to determine if {@link LauncherAtom.ItemInfo} should be tracked and reported to
* hotseat predictors
*/
public static boolean isTrackedForHotseatPrediction(LauncherAtom.ItemInfo info) {
LauncherAtom.ContainerInfo ci = info.getContainerInfo();
switch (ci.getContainerCase()) {
case HOTSEAT:
return true;
case WORKSPACE:
return ci.getWorkspace().getPageIndex() == 0;
default:
return false;
}
}
/**
* Helper method to determine if {@link ItemInfo} should be tracked and reported to widget
* predictors
*/
public static boolean isTrackedForWidgetPrediction(ItemInfo info) {
return info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET
&& info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP;
}
/**
* Helper method to determine if {@link LauncherAtom.ItemInfo} should be tracked and reported
* to widget predictors
*/
public static boolean isTrackedForWidgetPrediction(LauncherAtom.ItemInfo info) {
return info.getItemCase() == LauncherAtom.ItemInfo.ItemCase.WIDGET
&& info.getContainerInfo().getContainerCase() == WORKSPACE;
}
}
@@ -25,8 +25,12 @@ import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICA
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT;
import static com.android.launcher3.Utilities.getDevicePrefs;
import static com.android.launcher3.hybridhotseat.HotseatPredictionModel.convertDataModelToAppTargetBundle;
import static com.android.launcher3.model.PredictionHelper.getAppTargetFromItemInfo;
import static com.android.launcher3.model.PredictionHelper.wrapAppTargetWithItemLocation;
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
import static java.util.stream.Collectors.toCollection;
import android.app.StatsManager;
import android.app.prediction.AppPredictionContext;
import android.app.prediction.AppPredictionManager;
@@ -39,6 +43,7 @@ import android.content.SharedPreferences;
import android.content.pm.LauncherActivityInfo;
import android.content.pm.LauncherApps;
import android.content.pm.ShortcutInfo;
import android.os.Bundle;
import android.os.UserHandle;
import android.util.Log;
import android.util.StatsEvent;
@@ -62,6 +67,7 @@ import com.android.launcher3.util.PersistedItemArray;
import com.android.quickstep.logging.StatsLogCompatManager;
import com.android.systemui.shared.system.SysUiStatsLog;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@@ -75,6 +81,7 @@ public class QuickstepModelDelegate extends ModelDelegate {
public static final String LAST_PREDICTION_ENABLED_STATE = "last_prediction_enabled_state";
private static final String LAST_SNAPSHOT_TIME_MILLIS = "LAST_SNAPSHOT_TIME_MILLIS";
private static final String BUNDLE_KEY_ADDED_APP_WIDGETS = "added_app_widgets";
private static final int NUM_OF_RECOMMENDED_WIDGETS_PREDICATION = 20;
private static final boolean IS_DEBUG = false;
@@ -272,6 +279,7 @@ public class QuickstepModelDelegate extends ModelDelegate {
registerWidgetsPredictor(apm.createAppPredictionSession(
new AppPredictionContext.Builder(context)
.setUiSurface("widgets")
.setExtras(getBundleForWidgetsOnWorkspace(context, mDataModel))
.setPredictedTargetCount(NUM_OF_RECOMMENDED_WIDGETS_PREDICATION)
.build()));
}
@@ -306,12 +314,41 @@ public class QuickstepModelDelegate extends ModelDelegate {
}
private void onAppTargetEvent(AppTargetEvent event, int client) {
PredictorState state = client == CONTAINER_PREDICTION ? mAllAppsState : mHotseatState;
PredictorState state;
switch(client) {
case CONTAINER_PREDICTION:
state = mAllAppsState;
break;
case CONTAINER_WIDGETS_PREDICTION:
state = mWidgetsRecommendationState;
break;
case CONTAINER_HOTSEAT_PREDICTION:
default:
state = mHotseatState;
break;
}
if (state.predictor != null) {
state.predictor.notifyAppTargetEvent(event);
}
}
private Bundle getBundleForWidgetsOnWorkspace(Context context, BgDataModel dataModel) {
Bundle bundle = new Bundle();
ArrayList<AppTargetEvent> widgetEvents =
dataModel.getAllWorkspaceItems().stream()
.filter(PredictionHelper::isTrackedForWidgetPrediction)
.map(item -> {
AppTarget target = getAppTargetFromItemInfo(context, item);
if (target == null) return null;
return wrapAppTargetWithItemLocation(
target, AppTargetEvent.ACTION_PIN, item);
})
.filter(Objects::nonNull)
.collect(toCollection(ArrayList::new));
bundle.putParcelableArrayList(BUNDLE_KEY_ADDED_APP_WIDGETS, widgetEvents);
return bundle;
}
static class PredictorState {
public final FixedContainerItems items;
@@ -444,6 +444,10 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>,
mAnimationFactory = mActivityInterface.prepareRecentsUI(mDeviceState,
mWasLauncherAlreadyVisible, this::onAnimatorPlaybackControllerCreated);
maybeUpdateRecentsAttachedState(false /* animate */);
if (mGestureState.getEndTarget() != null) {
// Update the end target in case the gesture ended before we init.
mAnimationFactory.setEndTarget(mGestureState.getEndTarget());
}
};
if (mWasLauncherAlreadyVisible) {
// Launcher is visible, but might be about to stop. Thus, if we prepare recents
@@ -59,7 +59,6 @@ import android.os.SystemProperties;
import android.os.UserManager;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.view.MotionEvent;
import android.view.Surface;
@@ -581,8 +580,7 @@ public class RecentsAnimationDeviceState implements
final Info displayInfo = mDisplayController.getInfo();
return (mRotationTouchHelper.touchInOneHandedModeRegion(ev)
&& displayInfo.rotation != Surface.ROTATION_90
&& displayInfo.rotation != Surface.ROTATION_270
&& displayInfo.densityDpi < DisplayMetrics.DENSITY_600);
&& displayInfo.rotation != Surface.ROTATION_270);
}
return false;
}
@@ -274,7 +274,6 @@ abstract class TutorialController implements BackGestureAttemptCallback,
mFeedbackView.findViewById(R.id.gesture_tutorial_fragment_feedback_subtitle);
subtitle.setText(subtitleResId);
if (isGestureSuccessful) {
hideCloseButton();
if (mTutorialFragment.isAtFinalStep()) {
showActionButton();
}
@@ -402,6 +401,7 @@ abstract class TutorialController implements BackGestureAttemptCallback,
void transitToController() {
hideFeedback();
hideActionButton();
updateCloseButton();
updateSubtext();
updateDrawables();
updateLayout();
@@ -412,26 +412,21 @@ abstract class TutorialController implements BackGestureAttemptCallback,
}
}
void hideCloseButton() {
mCloseButton.setVisibility(GONE);
}
void showCloseButton() {
mCloseButton.setVisibility(View.VISIBLE);
void updateCloseButton() {
mCloseButton.setTextAppearance(Utilities.isDarkTheme(mContext)
? R.style.TextAppearance_GestureTutorial_Feedback_Subtext
: R.style.TextAppearance_GestureTutorial_Feedback_Subtext_Dark);
}
void hideActionButton() {
showCloseButton();
mCloseButton.setVisibility(View.VISIBLE);
// Invisible to maintain the layout.
mActionButton.setVisibility(View.INVISIBLE);
mActionButton.setOnClickListener(null);
}
void showActionButton() {
hideCloseButton();
mCloseButton.setVisibility(GONE);
mActionButton.setVisibility(View.VISIBLE);
mActionButton.setOnClickListener(this::onActionButtonClicked);
}
@@ -599,6 +599,8 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
private SplitConfigurationOptions.StagedSplitBounds mSplitBoundsConfig;
private final Toast mSplitToast = Toast.makeText(getContext(),
R.string.toast_split_select_app, Toast.LENGTH_SHORT);
private final Toast mSplitUnsupportedToast = Toast.makeText(getContext(),
R.string.toast_split_app_unsupported, Toast.LENGTH_SHORT);
/**
* Keeps track of the index of the TaskView that split screen was initialized with so we know
@@ -3878,6 +3880,11 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
public void confirmSplitSelect(TaskView taskView) {
mSplitToast.cancel();
if (!taskView.getTask().isDockable) {
// Task not split screen supported
mSplitUnsupportedToast.show();
return;
}
RectF secondTaskStartingBounds = new RectF();
Rect secondTaskEndingBounds = new Rect();
// TODO(194414938) starting bounds seem slightly off, investigate
@@ -3920,6 +3927,7 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
int duration = mActivity.getStateManager().getState().getTransitionDuration(getContext());
PendingAnimation pendingAnim = new PendingAnimation(duration);
mSplitToast.cancel();
mSplitUnsupportedToast.cancel();
if (!animate) {
resetFromSplitSelectionState();
return pendingAnim;
@@ -44,7 +44,7 @@ public abstract class AbstractQuickStepTest extends AbstractLauncherUiTest {
protected void onLauncherActivityClose(Launcher launcher) {
RecentsView recentsView = launcher.getOverviewPanel();
if (recentsView != null) {
recentsView.finishRecentsAnimation(true, null);
recentsView.finishRecentsAnimation(false /* toRecents */, null);
}
}
@@ -43,7 +43,6 @@ import com.android.quickstep.views.RecentsView;
import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -289,7 +288,6 @@ public class TaplTestsQuickstep extends AbstractQuickStepTest {
@Test
@PortraitLandscape
@Ignore("b/203781041")
public void testOverviewForTablet() throws Exception {
if (!mLauncher.isTablet()) {
return;
+6 -2
View File
@@ -275,8 +275,12 @@ public class DropTargetBar extends FrameLayout
@Override
protected void onVisibilityChanged(@NonNull View changedView, int visibility) {
super.onVisibilityChanged(changedView, visibility);
if (TestProtocol.sDebugTracing && visibility == VISIBLE) {
Log.d(TestProtocol.NO_DROP_TARGET, "9");
if (TestProtocol.sDebugTracing) {
if (visibility == VISIBLE) {
Log.d(TestProtocol.NO_DROP_TARGET, "9");
} else {
Log.d(TestProtocol.NO_DROP_TARGET, "Hiding drop target", new Exception());
}
}
}
}
@@ -40,6 +40,7 @@ import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.core.content.ContextCompat;
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.R;
@@ -220,6 +221,11 @@ public class OptionsPopupView extends ArrowPopup<Launcher>
Toast.makeText(launcher, R.string.safemode_widget_error, Toast.LENGTH_SHORT).show();
return null;
} else {
AbstractFloatingView floatingView = AbstractFloatingView.getTopOpenViewWithType(
launcher, TYPE_WIDGETS_FULL_SHEET);
if (floatingView != null) {
return (WidgetsFullSheet) floatingView;
}
return WidgetsFullSheet.show(launcher, true /* animated */);
}
}
@@ -279,7 +285,7 @@ public class OptionsPopupView extends ArrowPopup<Launcher>
public final OnLongClickListener clickListener;
public OptionItem(Context context, int labelRes, int iconRes, EventEnum eventId,
OnLongClickListener clickListener) {
OnLongClickListener clickListener) {
this.labelRes = labelRes;
this.label = context.getText(labelRes);
this.icon = ContextCompat.getDrawable(context, iconRes);
@@ -288,7 +294,7 @@ public class OptionsPopupView extends ArrowPopup<Launcher>
}
public OptionItem(CharSequence label, Drawable icon, EventEnum eventId,
OnLongClickListener clickListener) {
OnLongClickListener clickListener) {
this.labelRes = 0;
this.label = label;
this.icon = icon;
@@ -54,18 +54,14 @@ public class BaseOverview extends LauncherInstrumentation.VisibleContainer {
}
private void flingForwardImpl() {
flingForwardImpl(0);
}
private void flingForwardImpl(int rightMargin) {
try (LauncherInstrumentation.Closable c =
mLauncher.addContextLayer("want to fling forward in overview")) {
LauncherInstrumentation.log("Overview.flingForward before fling");
final UiObject2 overview = verifyActiveContainer();
final int leftMargin =
mLauncher.getTargetInsets().left + mLauncher.getEdgeSensitivityWidth();
mLauncher.scroll(overview, Direction.LEFT, new Rect(leftMargin + 1, 0, rightMargin, 0),
20, false);
mLauncher.scroll(overview, Direction.LEFT, new Rect(leftMargin + 1, 0, 0, 0), 20,
false);
try (LauncherInstrumentation.Closable c2 =
mLauncher.addContextLayer("flung forwards")) {
verifyActiveContainer();
@@ -131,7 +127,7 @@ public class BaseOverview extends LauncherInstrumentation.VisibleContainer {
OverviewTask task = getCurrentTask();
mLauncher.assertNotNull("current task is null", task);
flingForwardImpl(task.getTaskCenterX());
mLauncher.scrollLeftByDistance(verifyActiveContainer(), task.getVisibleWidth());
try (LauncherInstrumentation.Closable c2 =
mLauncher.addContextLayer("scrolled task off screen")) {
@@ -1190,10 +1190,19 @@ public final class LauncherInstrumentation {
return getVisibleBounds(container).bottom - bottomGestureStartOnScreen;
}
int getRightGestureMarginInContainer(UiObject2 container) {
final int rightGestureStartOnScreen = getRightGestureStartOnScreen();
return getVisibleBounds(container).right - rightGestureStartOnScreen;
}
int getBottomGestureStartOnScreen() {
return getRealDisplaySize().y - getBottomGestureSize();
}
int getRightGestureStartOnScreen() {
return getRealDisplaySize().x - getWindowInsets().right;
}
void clickLauncherObject(UiObject2 object) {
waitForObjectEnabled(object, "clickLauncherObject");
expectEvent(TestProtocol.SEQUENCE_MAIN, LauncherInstrumentation.EVENT_TOUCH_DOWN);
@@ -1235,6 +1244,21 @@ public final class LauncherInstrumentation {
true);
}
void scrollLeftByDistance(UiObject2 container, int distance) {
final Rect containerRect = getVisibleBounds(container);
final int rightGestureMarginInContainer = getRightGestureMarginInContainer(container);
scroll(
container,
Direction.LEFT,
new Rect(
0,
containerRect.width() - distance - rightGestureMarginInContainer,
0,
rightGestureMarginInContainer),
10,
true);
}
void scroll(
UiObject2 container, Direction direction, Rect margins, int steps, boolean slowDown) {
final Rect rect = getVisibleBounds(container);
@@ -53,6 +53,10 @@ public final class OverviewTask {
return mTask.getVisibleBounds().height();
}
int getVisibleWidth() {
return mTask.getVisibleBounds().width();
}
int getTaskCenterX() {
return mTask.getVisibleCenter().x;
}