Snap for 7941279 from 9119e1fab3 to tm-release

Change-Id: Iefadbd16c1def8924fc8d1a7de3395aa255a78ae
This commit is contained in:
Android Build Coastguard Worker
2021-11-24 02:09:01 +00:00
18 changed files with 295 additions and 111 deletions
@@ -17,7 +17,6 @@ package com.android.launcher3.taskbar;
import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X;
import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_A11Y;
import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_A11Y_LONG_CLICK;
import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_BACK;
import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_HOME;
import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_IME_SWITCH;
@@ -90,7 +89,6 @@ public class NavbarButtonsViewController {
private static final int MASK_IME_SWITCHER_VISIBLE = FLAG_SWITCHER_SUPPORTED | FLAG_IME_VISIBLE;
private View.OnLongClickListener mA11yLongClickListener;
private final ArrayList<StatePropertyHolder> mPropertyHolders = new ArrayList<>();
private final ArrayList<ImageView> mAllButtons = new ArrayList<>();
private int mState;
@@ -142,11 +140,6 @@ public class NavbarButtonsViewController {
mNavButtonsView.getLayoutParams().height = mContext.getDeviceProfile().taskbarSize;
mNavButtonTranslationYMultiplier.value = 1;
mA11yLongClickListener = view -> {
mControllers.navButtonController.onButtonClick(BUTTON_A11Y_LONG_CLICK);
return true;
};
mPropertyHolders.add(new StatePropertyHolder(
mControllers.taskbarViewController.getTaskbarIconAlpha()
.getProperty(ALPHA_INDEX_IME),
@@ -285,7 +278,6 @@ public class NavbarButtonsViewController {
mPropertyHolders.add(new StatePropertyHolder(mA11yButton,
flags -> (flags & FLAG_A11Y_VISIBLE) != 0
&& (flags & FLAG_ROTATION_BUTTON_VISIBLE) == 0));
mA11yButton.setOnLongClickListener(mA11yLongClickListener);
}
private void parseSystemUiFlags(int sysUiStateFlags) {
@@ -441,6 +433,8 @@ public class NavbarButtonsViewController {
ImageView buttonView = addButton(parent, id, layoutId);
buttonView.setImageResource(drawableId);
buttonView.setOnClickListener(view -> navButtonController.onButtonClick(buttonType));
buttonView.setOnLongClickListener(view ->
navButtonController.onButtonLongClick(buttonType));
return buttonView;
}
@@ -16,9 +16,11 @@
package com.android.launcher3.taskbar;
import static android.view.Display.DEFAULT_DISPLAY;
import android.view.inputmethod.InputMethodManager;
import static com.android.internal.app.AssistUtils.INVOCATION_TYPE_HOME_BUTTON_LONG_PRESS;
import static com.android.internal.app.AssistUtils.INVOCATION_TYPE_KEY;
import android.os.Bundle;
import androidx.annotation.IntDef;
@@ -35,11 +37,9 @@ import java.lang.annotation.RetentionPolicy;
* Controller for 3 button mode in the taskbar.
* Handles all the functionality of the various buttons, making/routing the right calls into
* launcher or sysui/system.
*
* TODO: Create callbacks to hook into UI layer since state will change for more context buttons/
* assistant invocation.
*/
public class TaskbarNavButtonController {
@Retention(RetentionPolicy.SOURCE)
@IntDef(value = {
BUTTON_BACK,
@@ -47,7 +47,6 @@ public class TaskbarNavButtonController {
BUTTON_RECENTS,
BUTTON_IME_SWITCH,
BUTTON_A11Y,
BUTTON_A11Y_LONG_CLICK
})
public @interface TaskbarButton {}
@@ -57,7 +56,6 @@ public class TaskbarNavButtonController {
static final int BUTTON_RECENTS = BUTTON_HOME << 1;
static final int BUTTON_IME_SWITCH = BUTTON_RECENTS << 1;
static final int BUTTON_A11Y = BUTTON_IME_SWITCH << 1;
static final int BUTTON_A11Y_LONG_CLICK = BUTTON_A11Y << 1;
private final TouchInteractionService mService;
@@ -82,9 +80,22 @@ public class TaskbarNavButtonController {
case BUTTON_A11Y:
notifyImeClick(false /* longClick */);
break;
case BUTTON_A11Y_LONG_CLICK:
}
}
public boolean onButtonLongClick(@TaskbarButton int buttonType) {
switch (buttonType) {
case BUTTON_HOME:
startAssistant();
return true;
case BUTTON_A11Y:
notifyImeClick(true /* longClick */);
break;
return true;
case BUTTON_BACK:
case BUTTON_IME_SWITCH:
case BUTTON_RECENTS:
default:
return false;
}
}
@@ -113,4 +124,11 @@ public class TaskbarNavButtonController {
systemUiProxy.notifyAccessibilityButtonClicked(mService.getDisplayId());
}
}
private void startAssistant() {
Bundle args = new Bundle();
args.putInt(INVOCATION_TYPE_KEY, INVOCATION_TYPE_HOME_BUTTON_LONG_PRESS);
SystemUiProxy systemUiProxy = SystemUiProxy.INSTANCE.getNoCreate();
systemUiProxy.startAssistant(args);
}
}
@@ -36,6 +36,7 @@ import com.android.wm.shell.recents.IRecentTasksListener;
import com.android.wm.shell.util.GroupedRecentTaskInfo;
import com.android.wm.shell.util.StagedSplitBounds;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.function.Consumer;
@@ -219,6 +220,26 @@ public class RecentTasksList {
return newTasks;
}
public void dump(String prefix, PrintWriter writer) {
writer.println(prefix + "RecentTasksList:");
writer.println(prefix + " mChangeId=" + mChangeId);
writer.println(prefix + " mResultsUi=[id=" + mResultsUi.mRequestId + ", tasks=");
for (GroupTask task : mResultsUi) {
writer.println(prefix + " t1=" + task.task1.key.id
+ " t2=" + (task.hasMultipleTasks() ? task.task2.key.id : "-1"));
}
writer.println(prefix + " ]");
int currentUserId = Process.myUserHandle().getIdentifier();
ArrayList<GroupedRecentTaskInfo> rawTasks =
mSysUiProxy.getRecentTasks(Integer.MAX_VALUE, currentUserId);
writer.println(prefix + " rawTasks=[");
for (GroupedRecentTaskInfo task : rawTasks) {
writer.println(prefix + " t1=" + task.mTaskInfo1.taskId
+ " t2=" + (task.mTaskInfo2 != null ? task.mTaskInfo2.taskId : "-1"));
}
writer.println(prefix + " ]");
}
private static class TaskLoadResult extends ArrayList<GroupTask> {
final int mRequestId;
@@ -43,6 +43,7 @@ import com.android.systemui.shared.system.KeyguardManagerCompat;
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.shared.system.TaskStackChangeListeners;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executor;
@@ -220,6 +221,11 @@ public class RecentsModel extends TaskStackChangeListener implements IconChangeL
mThumbnailChangeListeners.remove(listener);
}
public void dump(String prefix, PrintWriter writer) {
writer.println(prefix + "RecentsModel:");
mTaskList.dump(" ", writer);
}
/**
* Listener for receiving various task properties changes
*/
@@ -83,14 +83,16 @@ public class SystemUiProxy implements ISystemUiProxy,
MAIN_EXECUTOR.execute(() -> clearProxy());
};
// Save the listeners passed into the proxy since when set/register these listeners,
// setProxy may not have been called, eg. OverviewProxyService is not connected yet.
private IPipAnimationListener mPendingPipAnimationListener;
private ISplitScreenListener mPendingSplitScreenListener;
private IStartingWindowListener mPendingStartingWindowListener;
private ISmartspaceCallback mPendingSmartspaceCallback;
private IRecentTasksListener mPendingRecentTasksListener;
private final ArrayList<RemoteTransitionCompat> mPendingRemoteTransitions = new ArrayList<>();
// Save the listeners passed into the proxy since OverviewProxyService may not have been bound
// yet, and we'll need to set/register these listeners with SysUI when they do. Note that it is
// up to the caller to clear the listeners to prevent leaks as these can be held indefinitely
// in case SysUI needs to rebind.
private IPipAnimationListener mPipAnimationListener;
private ISplitScreenListener mSplitScreenListener;
private IStartingWindowListener mStartingWindowListener;
private ISmartspaceCallback mSmartspaceCallback;
private IRecentTasksListener mRecentTasksListener;
private final ArrayList<RemoteTransitionCompat> mRemoteTransitions = new ArrayList<>();
// Used to dedupe calls to SystemUI
private int mLastShelfHeight;
@@ -167,29 +169,23 @@ public class SystemUiProxy implements ISystemUiProxy,
mRecentTasks = recentTasks;
linkToDeath();
// re-attach the listeners once missing due to setProxy has not been initialized yet.
if (mPendingPipAnimationListener != null && mPip != null) {
setPinnedStackAnimationListener(mPendingPipAnimationListener);
mPendingPipAnimationListener = null;
if (mPipAnimationListener != null && mPip != null) {
setPinnedStackAnimationListener(mPipAnimationListener);
}
if (mPendingSplitScreenListener != null && mSplitScreen != null) {
registerSplitScreenListener(mPendingSplitScreenListener);
mPendingSplitScreenListener = null;
if (mSplitScreenListener != null && mSplitScreen != null) {
registerSplitScreenListener(mSplitScreenListener);
}
if (mPendingStartingWindowListener != null && mStartingWindow != null) {
setStartingWindowListener(mPendingStartingWindowListener);
mPendingStartingWindowListener = null;
if (mStartingWindowListener != null && mStartingWindow != null) {
setStartingWindowListener(mStartingWindowListener);
}
if (mPendingSmartspaceCallback != null && mSmartspaceTransitionController != null) {
setSmartspaceCallback(mPendingSmartspaceCallback);
mPendingSmartspaceCallback = null;
if (mSmartspaceCallback != null && mSmartspaceTransitionController != null) {
setSmartspaceCallback(mSmartspaceCallback);
}
for (int i = mPendingRemoteTransitions.size() - 1; i >= 0; --i) {
registerRemoteTransition(mPendingRemoteTransitions.get(i));
for (int i = mRemoteTransitions.size() - 1; i >= 0; --i) {
registerRemoteTransition(mRemoteTransitions.get(i));
}
mPendingRemoteTransitions.clear();
if (mPendingRecentTasksListener != null && mRecentTasks != null) {
registerRecentTasksListener(mPendingRecentTasksListener);
mPendingRecentTasksListener = null;
if (mRecentTasksListener != null && mRecentTasks != null) {
registerRecentTasksListener(mRecentTasksListener);
}
if (mPendingSetNavButtonAlpha != null) {
@@ -513,9 +509,8 @@ public class SystemUiProxy implements ISystemUiProxy,
} catch (RemoteException e) {
Log.w(TAG, "Failed call setPinnedStackAnimationListener", e);
}
} else {
mPendingPipAnimationListener = listener;
}
mPipAnimationListener = listener;
}
public Rect startSwipePipToHome(ComponentName componentName, ActivityInfo activityInfo,
@@ -553,9 +548,8 @@ public class SystemUiProxy implements ISystemUiProxy,
} catch (RemoteException e) {
Log.w(TAG, "Failed call registerSplitScreenListener");
}
} else {
mPendingSplitScreenListener = listener;
}
mSplitScreenListener = listener;
}
public void unregisterSplitScreenListener(ISplitScreenListener listener) {
@@ -566,7 +560,7 @@ public class SystemUiProxy implements ISystemUiProxy,
Log.w(TAG, "Failed call unregisterSplitScreenListener");
}
}
mPendingSplitScreenListener = null;
mSplitScreenListener = null;
}
/** Start multiple tasks in split-screen simultaneously. */
@@ -687,9 +681,8 @@ public class SystemUiProxy implements ISystemUiProxy,
} catch (RemoteException e) {
Log.w(TAG, "Failed call registerRemoteTransition");
}
} else {
mPendingRemoteTransitions.add(remoteTransition);
}
mRemoteTransitions.add(remoteTransition);
}
public void unregisterRemoteTransition(RemoteTransitionCompat remoteTransition) {
@@ -700,7 +693,7 @@ public class SystemUiProxy implements ISystemUiProxy,
Log.w(TAG, "Failed call registerRemoteTransition");
}
}
mPendingRemoteTransitions.remove(remoteTransition);
mRemoteTransitions.remove(remoteTransition);
}
//
@@ -717,9 +710,8 @@ public class SystemUiProxy implements ISystemUiProxy,
} catch (RemoteException e) {
Log.w(TAG, "Failed call setStartingWindowListener", e);
}
} else {
mPendingStartingWindowListener = listener;
}
mStartingWindowListener = listener;
}
//
@@ -733,9 +725,8 @@ public class SystemUiProxy implements ISystemUiProxy,
} catch (RemoteException e) {
Log.w(TAG, "Failed call setStartingWindowListener", e);
}
} else {
mPendingSmartspaceCallback = callback;
}
mSmartspaceCallback = callback;
}
//
@@ -749,9 +740,8 @@ public class SystemUiProxy implements ISystemUiProxy,
} catch (RemoteException e) {
Log.w(TAG, "Failed call registerRecentTasksListener", e);
}
} else {
mPendingRecentTasksListener = listener;
}
mRecentTasksListener = listener;
}
public void unregisterRecentTasksListener(IRecentTasksListener listener) {
@@ -762,7 +752,7 @@ public class SystemUiProxy implements ISystemUiProxy,
Log.w(TAG, "Failed call unregisterRecentTasksListener");
}
}
mPendingRecentTasksListener = null;
mRecentTasksListener = null;
}
public ArrayList<GroupedRecentTaskInfo> getRecentTasks(int numTasks, int userId) {
@@ -72,7 +72,13 @@ public interface TaskShortcutFactory {
@Override
public SystemShortcut getShortcut(BaseDraggingActivity activity,
TaskIdAttributeContainer taskContainer) {
return new AppInfo(activity, taskContainer.getItemInfo());
TaskView taskView = taskContainer.getTaskView();
AppInfo.SplitAccessibilityInfo accessibilityInfo =
new AppInfo.SplitAccessibilityInfo(taskView.containsMultipleTasks(),
TaskUtils.getTitle(taskView.getContext(), taskContainer.getTask()),
taskContainer.getA11yNodeId()
);
return new AppInfo(activity, taskContainer.getItemInfo(), accessibilityInfo);
}
@Override
@@ -951,6 +951,7 @@ public class TouchInteractionService extends Service
pw.println(" resumed=" + resumed);
pw.println(" mConsumer=" + mConsumer.getName());
ActiveGestureLog.INSTANCE.dump("", pw);
RecentsModel.INSTANCE.get(this).dump("", pw);
pw.println("ProtoTrace:");
pw.println(" file=" + ProtoTracer.INSTANCE.get(this).getTraceFile());
}
@@ -15,8 +15,10 @@
*/
package com.android.quickstep;
import android.graphics.HardwareRenderer;
import android.os.Handler;
import android.view.View;
import android.view.ViewRootImpl;
import com.android.launcher3.Utilities;
import com.android.systemui.shared.system.ViewRootImplCompat;
@@ -45,9 +47,9 @@ public class ViewUtils {
return new FrameHandler(view, onFinishRunnable, canceled).schedule();
}
private static class FrameHandler implements LongConsumer {
private static class FrameHandler implements HardwareRenderer.FrameDrawingCallback {
final ViewRootImplCompat mViewRoot;
final ViewRootImpl mViewRoot;
final Runnable mFinishCallback;
final BooleanSupplier mCancelled;
final Handler mHandler;
@@ -55,14 +57,14 @@ public class ViewUtils {
int mDeferFrameCount = 1;
FrameHandler(View view, Runnable finishCallback, BooleanSupplier cancelled) {
mViewRoot = new ViewRootImplCompat(view);
mViewRoot = view.getViewRootImpl();
mFinishCallback = finishCallback;
mCancelled = cancelled;
mHandler = new Handler();
}
@Override
public void accept(long l) {
public void onFrameDraw(long frame) {
Utilities.postAsyncCallback(mHandler, this::onFrame);
}
@@ -83,7 +85,7 @@ public class ViewUtils {
}
private boolean schedule() {
if (mViewRoot.isValid()) {
if (mViewRoot.getView() != null) {
mViewRoot.registerRtFrameCallback(this);
mViewRoot.getView().invalidate();
return true;
@@ -24,6 +24,8 @@ import static android.view.MotionEvent.ACTION_POINTER_DOWN;
import static android.view.MotionEvent.ACTION_POINTER_UP;
import static android.view.MotionEvent.ACTION_UP;
import static com.android.internal.app.AssistUtils.INVOCATION_TYPE_GESTURE;
import static com.android.internal.app.AssistUtils.INVOCATION_TYPE_KEY;
import static com.android.launcher3.Utilities.squaredHypot;
import android.animation.Animator;
@@ -64,8 +66,6 @@ public class AssistantInputConsumer extends DelegateInputConsumer {
private static final String OPA_BUNDLE_TRIGGER = "triggered_by";
// From //java/com/google/android/apps/gsa/assistant/shared/proto/opa_trigger.proto.
private static final int OPA_BUNDLE_TRIGGER_DIAG_SWIPE_GESTURE = 83;
private static final String INVOCATION_TYPE_KEY = "invocation_type";
private static final int INVOCATION_TYPE_GESTURE = 1;
private final PointF mDownPos = new PointF();
private final PointF mLastPos = new PointF();
@@ -22,10 +22,10 @@ import android.os.Message;
import android.view.SurfaceControl;
import android.view.SurfaceControl.Transaction;
import android.view.View;
import android.view.ViewRootImpl;
import com.android.quickstep.RemoteAnimationTargets.ReleaseCheck;
import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams;
import com.android.systemui.shared.system.ViewRootImplCompat;
import java.util.function.Consumer;
@@ -41,7 +41,7 @@ public class SurfaceTransactionApplier extends ReleaseCheck {
private static final int MSG_UPDATE_SEQUENCE_NUMBER = 0;
private final SurfaceControl mBarrierSurfaceControl;
private final ViewRootImplCompat mTargetViewRootImpl;
private final ViewRootImpl mTargetViewRootImpl;
private final Handler mApplyHandler;
private int mLastSequenceNumber = 0;
@@ -50,8 +50,8 @@ public class SurfaceTransactionApplier extends ReleaseCheck {
* @param targetView The view in the surface that acts as synchronization anchor.
*/
public SurfaceTransactionApplier(View targetView) {
mTargetViewRootImpl = new ViewRootImplCompat(targetView);
mBarrierSurfaceControl = mTargetViewRootImpl.getRenderSurfaceControl();
mTargetViewRootImpl = targetView.getViewRootImpl();
mBarrierSurfaceControl = mTargetViewRootImpl.getSurfaceControl();
mApplyHandler = new Handler(this::onApplyMessage);
}
@@ -109,7 +109,7 @@ public class SurfaceTransactionApplier extends ReleaseCheck {
if (targetView == null) {
// No target view, no applier
callback.accept(null);
} else if (new ViewRootImplCompat(targetView).isValid()) {
} else if (targetView.isAttachedToWindow()) {
// Already attached, we're good to go
callback.accept(new SurfaceTransactionApplier(targetView));
} else {
@@ -136,7 +136,7 @@ final class FloatingWidgetBackgroundView extends View {
}
/** Returns the maximum corner radius of {@param drawable}. */
private static float getMaxRadius(Drawable drawable) {
private static float getMaxRadius(@Nullable Drawable drawable) {
if (!(drawable instanceof GradientDrawable)) return 0;
float[] cornerRadii = ((GradientDrawable) drawable).getCornerRadii();
float cornerRadius = ((GradientDrawable) drawable).getCornerRadius();
@@ -87,6 +87,14 @@ public class IconView extends View {
return mDrawable;
}
public int getDrawableWidth() {
return mDrawableWidth;
}
public int getDrawableHeight() {
return mDrawableHeight;
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
@@ -2612,10 +2612,8 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
clampToProgress(FINAL_FRAME, 0, 0.5f));
});
}
boolean isTaskInBottomGridRow = showAsGrid() && !mTopRowIdSet.contains(
taskView.getTaskViewId()) && taskView.getTaskViewId() != mFocusedTaskViewId;
anim.setFloat(taskView, VIEW_ALPHA, 0,
clampToProgress(isTaskInBottomGridRow ? ACCEL : FINAL_FRAME, 0, 0.5f));
clampToProgress(isOnGridBottomRow(taskView) ? ACCEL : FINAL_FRAME, 0, 0.5f));
FloatProperty<TaskView> secondaryViewTranslate =
taskView.getSecondaryDissmissTranslationProperty();
int secondaryTaskDimension = mOrientationHandler.getSecondaryDimension(taskView);
@@ -4681,6 +4679,15 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
return position != -1 ? position : bottomRowIdArray.indexOf(taskView.getTaskViewId());
}
/**
* @return true if the task in on the top of the grid
*/
public boolean isOnGridBottomRow(TaskView taskView) {
return showAsGrid()
&& !mTopRowIdSet.contains(taskView.getTaskViewId())
&& taskView.getTaskViewId() != mFocusedTaskViewId;
}
public Consumer<MotionEvent> getEventDispatcher(float navbarRotation) {
float degreesRotated;
if (navbarRotation == 0) {
@@ -45,7 +45,10 @@ class TaskMenuViewWithArrow<T : BaseDraggingActivity> : ArrowPopup<T> {
companion object {
const val TAG = "TaskMenuViewWithArrow"
fun showForTask(taskContainer: TaskIdAttributeContainer): Boolean {
fun showForTask(
taskContainer: TaskIdAttributeContainer,
alignSecondRow: Boolean = false
): Boolean {
val activity = BaseDraggingActivity
.fromContext<BaseDraggingActivity>(taskContainer.taskView.context)
val taskMenuViewWithArrow = activity.layoutInflater
@@ -55,7 +58,7 @@ class TaskMenuViewWithArrow<T : BaseDraggingActivity> : ArrowPopup<T> {
false
) as TaskMenuViewWithArrow<*>
return taskMenuViewWithArrow.populateAndShowForTask(taskContainer)
return taskMenuViewWithArrow.populateAndShowForTask(taskContainer, alignSecondRow)
}
}
@@ -78,6 +81,9 @@ class TaskMenuViewWithArrow<T : BaseDraggingActivity> : ArrowPopup<T> {
CLOSE_FADE_DURATION = CLOSE_CHILD_FADE_DURATION
}
private var alignSecondRow: Boolean = false
private val extraSpaceForSecondRowAlignment: Int
get() = if (alignSecondRow) optionMeasuredHeight else 0
private val menuWidth = context.resources.getDimensionPixelSize(R.dimen.task_menu_width_grid)
private lateinit var taskView: TaskView
@@ -91,6 +97,10 @@ class TaskMenuViewWithArrow<T : BaseDraggingActivity> : ArrowPopup<T> {
else
0
private var iconView: IconView? = null
private var scrim: View? = null
private val scrimAlpha = 0.8f
override fun isOfType(type: Int): Boolean = type and TYPE_TASK_MENU != 0
override fun getTargetObjectLocation(outPos: Rect?) {
@@ -112,18 +122,35 @@ class TaskMenuViewWithArrow<T : BaseDraggingActivity> : ArrowPopup<T> {
optionLayout = findViewById(KtR.id.menu_option_layout)
}
private fun populateAndShowForTask(taskContainer: TaskIdAttributeContainer): Boolean {
private fun populateAndShowForTask(
taskContainer: TaskIdAttributeContainer,
alignSecondRow: Boolean
): Boolean {
if (isAttachedToWindow) {
return false
}
taskView = taskContainer.taskView
this.taskContainer = taskContainer
this.alignSecondRow = alignSecondRow
if (!populateMenu()) return false
addScrim()
show()
return true
}
private fun addScrim() {
scrim = View(context).apply {
layoutParams = FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT
)
setBackgroundColor(Themes.getAttrColor(context, R.attr.overviewScrimColor))
alpha = 0f
}
popupContainer.addView(scrim)
}
/** @return true if successfully able to populate task view menu, false otherwise
*/
private fun populateMenu(): Boolean {
@@ -180,18 +207,50 @@ class TaskMenuViewWithArrow<T : BaseDraggingActivity> : ArrowPopup<T> {
}
override fun onCreateOpenAnimation(anim: AnimatorSet) {
anim.play(
ObjectAnimator.ofFloat(
taskContainer.thumbnailView, TaskThumbnailView.DIM_ALPHA,
TaskView.MAX_PAGE_SCRIM_ALPHA
scrim?.let {
anim.play(
ObjectAnimator.ofFloat(it, View.ALPHA, 0f, scrimAlpha)
.setDuration(OPEN_DURATION.toLong())
)
)
}
}
override fun onCreateCloseAnimation(anim: AnimatorSet) {
anim.play(
ObjectAnimator.ofFloat(taskContainer.thumbnailView, TaskThumbnailView.DIM_ALPHA, 0f)
)
scrim?.let {
anim.play(
ObjectAnimator.ofFloat(it, View.ALPHA, scrimAlpha, 0f)
.setDuration(CLOSE_DURATION.toLong())
)
}
}
override fun closeComplete() {
super.closeComplete()
popupContainer.removeView(scrim)
popupContainer.removeView(iconView)
}
/**
* Copy the iconView from taskView to dragLayer so it can stay on top of the scrim.
* It needs to be called after [getTargetObjectLocation] because [mTempRect] needs to be
* populated.
*/
private fun copyIconToDragLayer(insets: Rect) {
iconView = IconView(context).apply {
layoutParams = FrameLayout.LayoutParams(
taskContainer.iconView.width,
taskContainer.iconView.height
)
x = mTempRect.left.toFloat() - insets.left
y = mTempRect.top.toFloat() - insets.top
drawable = taskContainer.iconView.drawable
setDrawableSize(
taskContainer.iconView.drawableWidth,
taskContainer.iconView.drawableHeight
)
}
popupContainer.addView(iconView)
}
/**
@@ -217,7 +276,10 @@ class TaskMenuViewWithArrow<T : BaseDraggingActivity> : ArrowPopup<T> {
val dragLayer: InsettableFrameLayout = popupContainer
val insets = dragLayer.insets
// Put to the right of the icon if there is space, which means left aligned with the menu
copyIconToDragLayer(insets)
// Put this menu to the right of the icon if there is space,
// which means the arrow is left aligned with the menu
val rightAlignedMenuStartX = mTempRect.left - widthWithArrow
val leftAlignedMenuStartX = mTempRect.right + extraHorizontalSpace
mIsLeftAligned = if (mIsRtl) {
@@ -229,18 +291,17 @@ class TaskMenuViewWithArrow<T : BaseDraggingActivity> : ArrowPopup<T> {
var menuStartX = if (mIsLeftAligned) leftAlignedMenuStartX else rightAlignedMenuStartX
// Offset y so that the arrow and first row are center-aligned with the original icon.
// Offset y so that the arrow and row are center-aligned with the original icon.
val iconHeight = mTempRect.height()
val optionHeight = optionMeasuredHeight
val yOffset = (optionHeight - iconHeight) / 2
var menuStartY = mTempRect.top - yOffset
val yOffset = (optionMeasuredHeight - iconHeight) / 2
var menuStartY = mTempRect.top - yOffset - extraSpaceForSecondRowAlignment
// Insets are added later, so subtract them now.
menuStartX -= insets.left
menuStartY -= insets.top
setX(menuStartX.toFloat())
setY(menuStartY.toFloat())
x = menuStartX.toFloat()
y = menuStartY.toFloat()
val lp = layoutParams as FrameLayout.LayoutParams
val arrowLp = mArrow.layoutParams as FrameLayout.LayoutParams
@@ -251,7 +312,8 @@ class TaskMenuViewWithArrow<T : BaseDraggingActivity> : ArrowPopup<T> {
override fun addArrow() {
popupContainer.addView(mArrow)
mArrow.x = getArrowX()
mArrow.y = y + (optionMeasuredHeight / 2) - (mArrowHeight / 2)
mArrow.y = y + (optionMeasuredHeight / 2) - (mArrowHeight / 2) +
extraSpaceForSecondRowAlignment
updateArrowColor()
@@ -30,6 +30,7 @@ import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCH
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_LAUNCH_TAP;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_UNDEFINED;
import static java.lang.annotation.RetentionPolicy.SOURCE;
@@ -38,6 +39,7 @@ import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.annotation.IdRes;
import android.app.ActivityOptions;
import android.content.Context;
import android.content.Intent;
@@ -840,7 +842,9 @@ public class TaskView extends FrameLayout implements Reusable {
TaskIdAttributeContainer menuContainer =
mTaskIdAttributeContainer[iconView == mIconView ? 0 : 1];
if (mActivity.getDeviceProfile().overviewShowAsGrid) {
return TaskMenuViewWithArrow.Companion.showForTask(menuContainer);
boolean alignSecondRow = getRecentsView().isOnGridBottomRow(menuContainer.getTaskView())
&& mActivity.getDeviceProfile().isLandscape;
return TaskMenuViewWithArrow.Companion.showForTask(menuContainer, alignSecondRow);
} else {
return TaskMenuView.showForTask(menuContainer);
}
@@ -1302,10 +1306,14 @@ public class TaskView extends FrameLayout implements Reusable {
getContext().getText(R.string.accessibility_close)));
final Context context = getContext();
// TODO(b/200609838) Determine which task to run A11y action on when in split screen
for (SystemShortcut s : TaskOverlayFactory.getEnabledShortcuts(this,
mActivity.getDeviceProfile(), mTaskIdAttributeContainer[0])) {
info.addAction(s.createAccessibilityAction(context));
for (TaskIdAttributeContainer taskContainer : mTaskIdAttributeContainer) {
if (taskContainer == null) {
continue;
}
for (SystemShortcut s : TaskOverlayFactory.getEnabledShortcuts(this,
mActivity.getDeviceProfile(), taskContainer)) {
info.addAction(s.createAccessibilityAction(context));
}
}
if (mDigitalWellBeingToast.hasLimit()) {
@@ -1336,12 +1344,16 @@ public class TaskView extends FrameLayout implements Reusable {
return true;
}
// TODO(b/200609838) Determine which task to run A11y action on when in split screen
for (SystemShortcut s : TaskOverlayFactory.getEnabledShortcuts(this,
mActivity.getDeviceProfile(), mTaskIdAttributeContainer[0])) {
if (s.hasHandlerForAction(action)) {
s.onClick(this);
return true;
for (TaskIdAttributeContainer taskContainer : mTaskIdAttributeContainer) {
if (taskContainer == null) {
continue;
}
for (SystemShortcut s : TaskOverlayFactory.getEnabledShortcuts(this,
mActivity.getDeviceProfile(), taskContainer)) {
if (s.hasHandlerForAction(action)) {
s.onClick(this);
return true;
}
}
}
@@ -1558,7 +1570,6 @@ public class TaskView extends FrameLayout implements Reusable {
mScale = previewWidth / (previewWidth + currentInsetsLeft + currentInsetsRight);
}
}
}
public class TaskIdAttributeContainer {
@@ -1567,6 +1578,8 @@ public class TaskView extends FrameLayout implements Reusable {
private final IconView mIconView;
/** Defaults to STAGE_POSITION_UNDEFINED if in not a split screen task view */
private @SplitConfigurationOptions.StagePosition int mStagePosition;
@IdRes
private final int mA11yNodeId;
public TaskIdAttributeContainer(Task task, TaskThumbnailView thumbnailView,
IconView iconView, int stagePosition) {
@@ -1574,6 +1587,8 @@ public class TaskView extends FrameLayout implements Reusable {
this.mThumbnailView = thumbnailView;
this.mIconView = iconView;
this.mStagePosition = stagePosition;
this.mA11yNodeId = (stagePosition == STAGE_POSITION_BOTTOM_OR_RIGHT) ?
R.id.split_bottomRight_appInfo : R.id.split_topLeft_appInfo;
}
public TaskThumbnailView getThumbnailView() {
@@ -1603,5 +1618,9 @@ public class TaskView extends FrameLayout implements Reusable {
void setStagePosition(@SplitConfigurationOptions.StagePosition int stagePosition) {
this.mStagePosition = stagePosition;
}
public int getA11yNodeId() {
return mA11yNodeId;
}
}
}
+4
View File
@@ -21,6 +21,10 @@
<item type="id" name="view_type_widgets_list" />
<item type="id" name="view_type_widgets_header" />
<item type="id" name="view_type_widgets_search_header" />
<!-- Used for A11y actions in staged split to identify each task uniquely -->
<item type="id" name="split_topLeft_appInfo" />
<item type="id" name="split_bottomRight_appInfo" />
<!-- Do not change, must be kept in sync with sysui navbar button IDs for tests! -->
<item type="id" name="home" />
+4 -3
View File
@@ -40,9 +40,10 @@
<!-- Options for recent tasks -->
<!-- Title for an option to enter split screen mode for a given app -->
<string name="recent_task_option_split_screen">Split screen</string>
<string translatable="false" name="split_screen_position_top">Split top</string>
<string translatable="false" name="split_screen_position_left">Split left</string>
<string translatable="false" name="split_screen_position_right">Split right</string>
<string name="split_screen_position_top">Split top</string>
<string name="split_screen_position_left">Split left</string>
<string name="split_screen_position_right">Split right</string>
<string name="split_app_info_accessibility">App info for %1$s</string>
<!-- Widgets -->
<!-- Message to tell the user to press and hold on a widget to add it [CHAR_LIMIT=50] -->
@@ -41,8 +41,8 @@ public abstract class SystemShortcut<T extends Context & ActivityContext> extend
implements View.OnClickListener {
private final int mIconResId;
private final int mLabelResId;
private final int mAccessibilityActionId;
protected final int mLabelResId;
protected int mAccessibilityActionId;
protected final T mTarget;
protected final ItemInfo mItemInfo;
@@ -142,11 +142,43 @@ public abstract class SystemShortcut<T extends Context & ActivityContext> extend
public static class AppInfo<T extends Context & ActivityContext> extends SystemShortcut<T> {
@Nullable
private SplitAccessibilityInfo mSplitA11yInfo;
public AppInfo(T target, ItemInfo itemInfo) {
super(R.drawable.ic_info_no_shadow, R.string.app_info_drop_target_label, target,
itemInfo);
}
/**
* Constructor used by overview for staged split to provide custom A11y information.
*
* Future improvements considerations:
* Have the logic in {@link #createAccessibilityAction(Context)} be moved to super
* call in {@link SystemShortcut#createAccessibilityAction(Context)} by having
* SystemShortcut be aware of TaskContainers and staged split.
* That way it could directly create the correct node info for any shortcut that supports
* split, but then we'll need custom resIDs for each pair of shortcuts.
*/
public AppInfo(T target, ItemInfo itemInfo, SplitAccessibilityInfo accessibilityInfo) {
this(target, itemInfo);
mSplitA11yInfo = accessibilityInfo;
mAccessibilityActionId = accessibilityInfo.nodeId;
}
@Override
public AccessibilityNodeInfo.AccessibilityAction createAccessibilityAction(
Context context) {
if (mSplitA11yInfo != null && mSplitA11yInfo.containsMultipleTasks) {
String accessibilityLabel = context.getString(R.string.split_app_info_accessibility,
mSplitA11yInfo.taskTitle);
return new AccessibilityNodeInfo.AccessibilityAction(mAccessibilityActionId,
accessibilityLabel);
} else {
return super.createAccessibilityAction(context);
}
}
@Override
public void onClick(View view) {
dismissTaskMenuView(mTarget);
@@ -156,6 +188,19 @@ public abstract class SystemShortcut<T extends Context & ActivityContext> extend
mTarget.getStatsLogManager().logger().withItemInfo(mItemInfo)
.log(LAUNCHER_SYSTEM_SHORTCUT_APP_INFO_TAP);
}
public static class SplitAccessibilityInfo {
public final boolean containsMultipleTasks;
public final CharSequence taskTitle;
public final int nodeId;
public SplitAccessibilityInfo(boolean containsMultipleTasks,
CharSequence taskTitle, int nodeId) {
this.containsMultipleTasks = containsMultipleTasks;
this.taskTitle = taskTitle;
this.nodeId = nodeId;
}
}
}
public static final Factory<BaseDraggingActivity> INSTALL = (activity, itemInfo) -> {