Snap for 7688365 from cf1f1d1966 to tm-release
Change-Id: I9b04e1af4c6ed6d47574d6a1c0d455f4b581911d
This commit is contained in:
@@ -104,6 +104,23 @@
|
||||
</LinearLayout>
|
||||
|
||||
<!-- Unused. Included only for compatibility with parent class. -->
|
||||
<Button
|
||||
android:id="@+id/action_split"
|
||||
style="@style/GoOverviewActionButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:drawableStart="@drawable/ic_split_screen"
|
||||
android:text="@string/action_split"
|
||||
android:theme="@style/ThemeControlHighlightWorkspaceColor"
|
||||
android:visibility="gone" />
|
||||
|
||||
<Space
|
||||
android:id="@+id/action_split_space"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="1dp"
|
||||
android:layout_weight="1"
|
||||
android:visibility="gone" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/action_share"
|
||||
style="@style/GoOverviewActionButton"
|
||||
|
||||
@@ -96,7 +96,11 @@ public class DepthController implements StateHandler<LauncherState>,
|
||||
public void onDraw() {
|
||||
View view = mLauncher.getDragLayer();
|
||||
ViewRootImpl viewRootImpl = view.getViewRootImpl();
|
||||
setSurface(viewRootImpl != null ? viewRootImpl.getSurfaceControl() : null);
|
||||
boolean applied = setSurface(
|
||||
viewRootImpl != null ? viewRootImpl.getSurfaceControl() : null);
|
||||
if (!applied) {
|
||||
dispatchTransactionSurface(mDepth);
|
||||
}
|
||||
view.post(() -> view.getViewTreeObserver().removeOnDrawListener(this));
|
||||
}
|
||||
};
|
||||
@@ -202,20 +206,22 @@ public class DepthController implements StateHandler<LauncherState>,
|
||||
|
||||
/**
|
||||
* Sets the specified app target surface to apply the blur to.
|
||||
* @return true when surface was valid and transaction was dispatched.
|
||||
*/
|
||||
public void setSurface(SurfaceControl surface) {
|
||||
public boolean setSurface(SurfaceControl surface) {
|
||||
// Set launcher as the SurfaceControl when we don't need an external target anymore.
|
||||
if (surface == null) {
|
||||
ViewRootImpl viewRootImpl = mLauncher.getDragLayer().getViewRootImpl();
|
||||
surface = viewRootImpl != null ? viewRootImpl.getSurfaceControl() : null;
|
||||
}
|
||||
|
||||
if (mSurface != surface) {
|
||||
mSurface = surface;
|
||||
if (surface != null) {
|
||||
dispatchTransactionSurface(mDepth);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -229,6 +235,8 @@ public class DepthController implements StateHandler<LauncherState>,
|
||||
setDepth(toDepth);
|
||||
} else if (toState == LauncherState.OVERVIEW) {
|
||||
dispatchTransactionSurface(mDepth);
|
||||
} else if (toState == LauncherState.BACKGROUND_APP) {
|
||||
mLauncher.getDragLayer().getViewTreeObserver().addOnDrawListener(mOnDrawListener);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -123,11 +123,9 @@ public class TaskbarDragLayerController {
|
||||
*/
|
||||
public void updateInsetsTouchability(InsetsInfo insetsInfo) {
|
||||
insetsInfo.touchableRegion.setEmpty();
|
||||
if (mActivity.isThreeButtonNav()) {
|
||||
// Always have nav buttons be touchable
|
||||
mControllers.navbarButtonsViewController.addVisibleButtonsRegion(
|
||||
mTaskbarDragLayer, insetsInfo.touchableRegion);
|
||||
}
|
||||
// Always have nav buttons be touchable
|
||||
mControllers.navbarButtonsViewController.addVisibleButtonsRegion(
|
||||
mTaskbarDragLayer, insetsInfo.touchableRegion);
|
||||
|
||||
if (mTaskbarDragLayer.getAlpha() < AlphaUpdateListener.ALPHA_CUTOFF_THRESHOLD) {
|
||||
// Let touches pass through us.
|
||||
|
||||
@@ -71,7 +71,7 @@ class QuickstepInteractionHandler implements RemoteViews.InteractionHandler {
|
||||
}
|
||||
}
|
||||
activityOptions.options.setPendingIntentLaunchFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
activityOptions.options.setSplashscreenStyle(SplashScreen.SPLASH_SCREEN_STYLE_ICON);
|
||||
activityOptions.options.setSplashscreenStyle(SplashScreen.SPLASH_SCREEN_STYLE_EMPTY);
|
||||
Object itemInfo = hostView.getTag();
|
||||
if (itemInfo instanceof ItemInfo) {
|
||||
mLauncher.addLaunchCookie((ItemInfo) itemInfo, activityOptions.options);
|
||||
|
||||
@@ -366,8 +366,8 @@ public final class TaskViewUtils {
|
||||
* device is considered in multiWindowMode and things like insets and stuff change
|
||||
* and calculations have to be adjusted in the animations for that
|
||||
*/
|
||||
public static void composeRecentsSplitLaunchAnimator(@NonNull TaskView initialView,
|
||||
@NonNull TaskView v, @NonNull TransitionInfo transitionInfo,
|
||||
public static void composeRecentsSplitLaunchAnimator(@NonNull Task initalTask,
|
||||
@NonNull Task secondTask, @NonNull TransitionInfo transitionInfo,
|
||||
SurfaceControl.Transaction t, @NonNull Runnable finishCallback) {
|
||||
|
||||
final TransitionInfo.Change[] splitRoots = new TransitionInfo.Change[2];
|
||||
@@ -377,7 +377,7 @@ public final class TaskViewUtils {
|
||||
final int mode = change.getMode();
|
||||
// Find the target tasks' root tasks since those are the split stages that need to
|
||||
// be animated (the tasks themselves are children and thus inherit animation).
|
||||
if (taskId == initialView.getTask().key.id || taskId == v.getTask().key.id) {
|
||||
if (taskId == initalTask.key.id || taskId == secondTask.key.id) {
|
||||
if (!(mode == TRANSIT_OPEN || mode == TRANSIT_TO_FRONT)) {
|
||||
throw new IllegalStateException(
|
||||
"Expected task to be showing, but it is " + mode);
|
||||
@@ -386,7 +386,7 @@ public final class TaskViewUtils {
|
||||
throw new IllegalStateException("Initiating multi-split launch but the split"
|
||||
+ "root of " + taskId + " is already visible or has broken hierarchy.");
|
||||
}
|
||||
splitRoots[taskId == initialView.getTask().key.id ? 0 : 1] =
|
||||
splitRoots[taskId == initalTask.key.id ? 0 : 1] =
|
||||
transitionInfo.getChange(change.getParent());
|
||||
}
|
||||
}
|
||||
@@ -406,8 +406,8 @@ public final class TaskViewUtils {
|
||||
}
|
||||
|
||||
/** Legacy version (until shell transitions are enabled) */
|
||||
public static void composeRecentsSplitLaunchAnimatorLegacy(@NonNull TaskView initialView,
|
||||
@NonNull TaskView v, @NonNull RemoteAnimationTargetCompat[] appTargets,
|
||||
public static void composeRecentsSplitLaunchAnimatorLegacy(@NonNull Task initialTask,
|
||||
@NonNull Task secondTask, @NonNull RemoteAnimationTargetCompat[] appTargets,
|
||||
@NonNull RemoteAnimationTargetCompat[] wallpaperTargets,
|
||||
@NonNull RemoteAnimationTargetCompat[] nonAppTargets,
|
||||
@NonNull Runnable finishCallback) {
|
||||
@@ -416,12 +416,12 @@ public final class TaskViewUtils {
|
||||
for (int i = 0; i < appTargets.length; ++i) {
|
||||
final int taskId = appTargets[i].taskInfo != null ? appTargets[i].taskInfo.taskId : -1;
|
||||
final int mode = appTargets[i].mode;
|
||||
if (taskId == initialView.getTask().key.id || taskId == v.getTask().key.id) {
|
||||
if (taskId == initialTask.key.id || taskId == secondTask.key.id) {
|
||||
if (mode != MODE_OPENING) {
|
||||
throw new IllegalStateException(
|
||||
"Expected task to be opening, but it is " + mode);
|
||||
}
|
||||
splitRoots[taskId == initialView.getTask().key.id ? 0 : 1] = i;
|
||||
splitRoots[taskId == initialTask.key.id ? 0 : 1] = i;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ import com.android.launcher3.util.SplitConfigurationOptions.StagePosition;
|
||||
import com.android.quickstep.SystemUiProxy;
|
||||
import com.android.quickstep.TaskAnimationManager;
|
||||
import com.android.quickstep.TaskViewUtils;
|
||||
import com.android.quickstep.views.TaskView;
|
||||
import com.android.systemui.shared.recents.model.Task;
|
||||
import com.android.systemui.shared.system.RemoteAnimationAdapterCompat;
|
||||
import com.android.systemui.shared.system.RemoteAnimationRunnerCompat;
|
||||
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
|
||||
@@ -47,23 +47,21 @@ import com.android.systemui.shared.system.RemoteTransitionRunner;
|
||||
public class SplitSelectStateController {
|
||||
|
||||
private final SystemUiProxy mSystemUiProxy;
|
||||
private TaskView mInitialTaskView;
|
||||
private TaskView mSecondTaskView;
|
||||
private @StagePosition int mStagePosition;
|
||||
private Task mInitialTask;
|
||||
private Task mSecondTask;
|
||||
private Rect mInitialBounds;
|
||||
private final Handler mHandler;
|
||||
|
||||
public SplitSelectStateController(Handler handler, SystemUiProxy systemUiProxy) {
|
||||
mSystemUiProxy = systemUiProxy;
|
||||
mHandler = handler;
|
||||
}
|
||||
|
||||
/**
|
||||
* To be called after first task selected
|
||||
*/
|
||||
public void setInitialTaskSelect(TaskView taskView, @StagePosition int stagePosition,
|
||||
public void setInitialTaskSelect(Task taskView, @StagePosition int stagePosition,
|
||||
Rect initialBounds) {
|
||||
mInitialTaskView = taskView;
|
||||
mInitialTask = taskView;
|
||||
mStagePosition = stagePosition;
|
||||
mInitialBounds = initialBounds;
|
||||
}
|
||||
@@ -71,21 +69,28 @@ public class SplitSelectStateController {
|
||||
/**
|
||||
* To be called after second task selected
|
||||
*/
|
||||
public void setSecondTaskId(TaskView taskView) {
|
||||
mSecondTaskView = taskView;
|
||||
public void setSecondTaskId(Task taskView) {
|
||||
mSecondTask = taskView;
|
||||
launchTasks(mInitialTask, mSecondTask, mStagePosition);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param stagePosition representing location of task1
|
||||
*/
|
||||
public void launchTasks(Task task1, Task task2, @StagePosition int stagePosition) {
|
||||
// Assume initial task is for top/left part of screen
|
||||
final int[] taskIds = mStagePosition == STAGE_POSITION_TOP_OR_LEFT
|
||||
? new int[]{mInitialTaskView.getTask().key.id, taskView.getTask().key.id}
|
||||
: new int[]{taskView.getTask().key.id, mInitialTaskView.getTask().key.id};
|
||||
final int[] taskIds = stagePosition == STAGE_POSITION_TOP_OR_LEFT
|
||||
? new int[]{task1.key.id, task2.key.id}
|
||||
: new int[]{task2.key.id, task1.key.id};
|
||||
if (TaskAnimationManager.ENABLE_SHELL_TRANSITIONS) {
|
||||
RemoteSplitLaunchTransitionRunner animationRunner =
|
||||
new RemoteSplitLaunchTransitionRunner(mInitialTaskView, taskView);
|
||||
new RemoteSplitLaunchTransitionRunner(task1, task2);
|
||||
mSystemUiProxy.startTasks(taskIds[0], null /* mainOptions */, taskIds[1],
|
||||
null /* sideOptions */, STAGE_POSITION_BOTTOM_OR_RIGHT,
|
||||
new RemoteTransitionCompat(animationRunner, MAIN_EXECUTOR));
|
||||
} else {
|
||||
RemoteSplitLaunchAnimationRunner animationRunner =
|
||||
new RemoteSplitLaunchAnimationRunner(mInitialTaskView, taskView);
|
||||
new RemoteSplitLaunchAnimationRunner(task1, task2);
|
||||
final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter(
|
||||
RemoteAnimationAdapterCompat.wrapRemoteAnimationRunner(animationRunner),
|
||||
300, 150,
|
||||
@@ -105,19 +110,19 @@ public class SplitSelectStateController {
|
||||
*/
|
||||
private class RemoteSplitLaunchTransitionRunner implements RemoteTransitionRunner {
|
||||
|
||||
private final TaskView mInitialTaskView;
|
||||
private final TaskView mTaskView;
|
||||
private final Task mInitialTask;
|
||||
private final Task mSecondTask;
|
||||
|
||||
RemoteSplitLaunchTransitionRunner(TaskView initialTaskView, TaskView taskView) {
|
||||
mInitialTaskView = initialTaskView;
|
||||
mTaskView = taskView;
|
||||
RemoteSplitLaunchTransitionRunner(Task initialTask, Task secondTask) {
|
||||
mInitialTask = initialTask;
|
||||
mSecondTask = secondTask;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startAnimation(IBinder transition, TransitionInfo info,
|
||||
SurfaceControl.Transaction t, Runnable finishCallback) {
|
||||
TaskViewUtils.composeRecentsSplitLaunchAnimator(mInitialTaskView, mTaskView,
|
||||
info, t, finishCallback);
|
||||
TaskViewUtils.composeRecentsSplitLaunchAnimator(mInitialTask,
|
||||
mSecondTask, info, t, finishCallback);
|
||||
// After successful launch, call resetState
|
||||
resetState();
|
||||
}
|
||||
@@ -129,20 +134,20 @@ public class SplitSelectStateController {
|
||||
*/
|
||||
private class RemoteSplitLaunchAnimationRunner implements RemoteAnimationRunnerCompat {
|
||||
|
||||
private final TaskView mInitialTaskView;
|
||||
private final TaskView mTaskView;
|
||||
private final Task mInitialTask;
|
||||
private final Task mSecondTask;
|
||||
|
||||
RemoteSplitLaunchAnimationRunner(TaskView initialTaskView, TaskView taskView) {
|
||||
mInitialTaskView = initialTaskView;
|
||||
mTaskView = taskView;
|
||||
RemoteSplitLaunchAnimationRunner(Task initialTask, Task secondTask) {
|
||||
mInitialTask = initialTask;
|
||||
mSecondTask = secondTask;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationStart(int transit, RemoteAnimationTargetCompat[] apps,
|
||||
RemoteAnimationTargetCompat[] wallpapers, RemoteAnimationTargetCompat[] nonApps,
|
||||
Runnable finishedCallback) {
|
||||
TaskViewUtils.composeRecentsSplitLaunchAnimatorLegacy(mInitialTaskView, mTaskView, apps,
|
||||
wallpapers, nonApps, finishedCallback);
|
||||
TaskViewUtils.composeRecentsSplitLaunchAnimatorLegacy(mInitialTask,
|
||||
mSecondTask, apps, wallpapers, nonApps, finishedCallback);
|
||||
// After successful launch, call resetState
|
||||
resetState();
|
||||
}
|
||||
@@ -157,8 +162,8 @@ public class SplitSelectStateController {
|
||||
* To be called if split select was cancelled
|
||||
*/
|
||||
public void resetState() {
|
||||
mInitialTaskView = null;
|
||||
mSecondTaskView = null;
|
||||
mInitialTask = null;
|
||||
mSecondTask = null;
|
||||
mStagePosition = SplitConfigurationOptions.STAGE_POSITION_UNDEFINED;
|
||||
mInitialBounds = null;
|
||||
}
|
||||
@@ -168,7 +173,7 @@ public class SplitSelectStateController {
|
||||
* chosen
|
||||
*/
|
||||
public boolean isSplitSelectActive() {
|
||||
return mInitialTaskView != null && mSecondTaskView == null;
|
||||
return mInitialTask != null && mSecondTask == null;
|
||||
}
|
||||
|
||||
public Rect getInitialBounds() {
|
||||
|
||||
@@ -4,6 +4,7 @@ import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.util.RunnableList;
|
||||
import com.android.launcher3.util.SplitConfigurationOptions;
|
||||
import com.android.quickstep.RecentsModel;
|
||||
import com.android.quickstep.TaskThumbnailCache;
|
||||
@@ -94,6 +95,13 @@ public class GroupedTaskView extends TaskView {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public RunnableList launchTaskAnimated() {
|
||||
getRecentsView().getSplitPlaceholder().launchTasks(mTask, mSecondaryTask,
|
||||
SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRecycle() {
|
||||
super.onRecycle();
|
||||
|
||||
@@ -3568,7 +3568,8 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
mSplitHiddenTaskView = taskView;
|
||||
Rect initialBounds = new Rect(taskView.getLeft(), taskView.getTop(), taskView.getRight(),
|
||||
taskView.getBottom());
|
||||
mSplitSelectStateController.setInitialTaskSelect(taskView, stagePosition, initialBounds);
|
||||
mSplitSelectStateController.setInitialTaskSelect(taskView.getTask(),
|
||||
stagePosition, initialBounds);
|
||||
mSplitHiddenTaskViewIndex = indexOfChild(taskView);
|
||||
if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
|
||||
finishRecentsAnimation(true, null);
|
||||
@@ -3609,7 +3610,7 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
secondTaskEndingBounds, taskView.getThumbnail(),
|
||||
true /*fadeWithThumbnail*/);
|
||||
pendingAnimation.addEndListener(aBoolean -> {
|
||||
mSplitSelectStateController.setSecondTaskId(taskView);
|
||||
mSplitSelectStateController.setSecondTaskId(taskView.getTask());
|
||||
resetFromSplitSelectionState();
|
||||
});
|
||||
mSecondSplitHiddenTaskView = taskView;
|
||||
|
||||
@@ -454,7 +454,6 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo
|
||||
mAllAppsStore.unregisterIconContainer(mAH[AdapterHolder.WORK].recyclerView);
|
||||
|
||||
if (mUsingTabs) {
|
||||
setupWorkToggle();
|
||||
mAH[AdapterHolder.MAIN].setup(mViewPager.getChildAt(0), mPersonalMatcher);
|
||||
mAH[AdapterHolder.WORK].setup(mViewPager.getChildAt(1), mWorkMatcher);
|
||||
mAH[AdapterHolder.WORK].recyclerView.setId(R.id.apps_list_view_work);
|
||||
@@ -485,6 +484,7 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo
|
||||
}
|
||||
|
||||
private void setupWorkToggle() {
|
||||
removeWorkToggle();
|
||||
if (Utilities.ATLEAST_P) {
|
||||
mWorkModeSwitch = (WorkModeSwitch) mLauncher.getLayoutInflater().inflate(
|
||||
R.layout.work_mode_fab, this, false);
|
||||
@@ -497,6 +497,14 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo
|
||||
}
|
||||
}
|
||||
|
||||
private void removeWorkToggle() {
|
||||
if (mWorkModeSwitch == null) return;
|
||||
if (mWorkModeSwitch.getParent() == this) {
|
||||
this.removeView(mWorkModeSwitch);
|
||||
}
|
||||
mWorkModeSwitch = null;
|
||||
}
|
||||
|
||||
private void replaceRVContainer(boolean showTabs) {
|
||||
for (int i = 0; i < mAH.length; i++) {
|
||||
AllAppsRecyclerView rv = mAH[i].recyclerView;
|
||||
@@ -519,8 +527,10 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo
|
||||
mViewPager = (AllAppsPagedView) newView;
|
||||
mViewPager.initParentViews(this);
|
||||
mViewPager.getPageIndicator().setOnActivePageChangedListener(this);
|
||||
setupWorkToggle();
|
||||
} else {
|
||||
mViewPager = null;
|
||||
removeWorkToggle();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -539,14 +549,6 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo
|
||||
mWorkModeSwitch.setWorkTabVisible(currentActivePage == AdapterHolder.WORK
|
||||
&& mAllAppsStore.hasModelFlag(
|
||||
FLAG_HAS_SHORTCUT_PERMISSION | FLAG_QUIET_MODE_CHANGE_PERMISSION));
|
||||
|
||||
if (currentActivePage == AdapterHolder.WORK) {
|
||||
if (mWorkModeSwitch.getParent() == null) {
|
||||
addView(mWorkModeSwitch);
|
||||
}
|
||||
} else {
|
||||
removeView(mWorkModeSwitch);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -51,6 +51,7 @@ public class WorkModeSwitch extends Button implements Insettable, View.OnClickLi
|
||||
|
||||
@Nullable
|
||||
private KeyboardInsetAnimationCallback mKeyboardInsetAnimationCallback;
|
||||
private boolean mWorkTabVisible;
|
||||
|
||||
public WorkModeSwitch(Context context) {
|
||||
this(context, null, 0);
|
||||
@@ -91,11 +92,10 @@ public class WorkModeSwitch extends Button implements Insettable, View.OnClickLi
|
||||
*/
|
||||
public void setWorkTabVisible(boolean workTabVisible) {
|
||||
clearAnimation();
|
||||
if (workTabVisible) {
|
||||
mWorkTabVisible = workTabVisible;
|
||||
if (workTabVisible && mWorkEnabled) {
|
||||
setEnabled(true);
|
||||
if (mWorkEnabled) {
|
||||
setVisibility(VISIBLE);
|
||||
}
|
||||
setVisibility(VISIBLE);
|
||||
setAlpha(0);
|
||||
animate().alpha(1).start();
|
||||
} else {
|
||||
@@ -105,7 +105,7 @@ public class WorkModeSwitch extends Button implements Insettable, View.OnClickLi
|
||||
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
if (Utilities.ATLEAST_P) {
|
||||
if (Utilities.ATLEAST_P && mWorkTabVisible) {
|
||||
setEnabled(false);
|
||||
Launcher.fromContext(getContext()).getStatsLogManager().logger().log(
|
||||
LAUNCHER_TURN_OFF_WORK_APPS_TAP);
|
||||
@@ -137,7 +137,7 @@ public class WorkModeSwitch extends Button implements Insettable, View.OnClickLi
|
||||
|
||||
@Override
|
||||
public WindowInsets onApplyWindowInsets(WindowInsets insets) {
|
||||
if (Utilities.ATLEAST_R) {
|
||||
if (Utilities.ATLEAST_R && mWorkTabVisible) {
|
||||
setTranslationY(0);
|
||||
if (insets.isVisible(WindowInsets.Type.ime())) {
|
||||
Insets keyboardInsets = insets.getInsets(WindowInsets.Type.ime());
|
||||
|
||||
@@ -76,6 +76,22 @@ public class StatsLogManager implements ResourceBasedOverride {
|
||||
}
|
||||
|
||||
public interface EventEnum {
|
||||
|
||||
/**
|
||||
* Tag used to request new UI Event IDs via presubmit analysis.
|
||||
*
|
||||
* <p>Use RESERVE_NEW_UI_EVENT_ID as the constructor parameter for a new {@link EventEnum}
|
||||
* to signal the presubmit analyzer to reserve a new ID for the event. The new ID will be
|
||||
* returned as a Gerrit presubmit finding. Do not submit {@code RESERVE_NEW_UI_EVENT_ID} as
|
||||
* the constructor parameter for any event.
|
||||
*
|
||||
* <pre>
|
||||
* @UiEvent(doc = "Briefly describe the interaction when this event will be logged")
|
||||
* UNIQUE_EVENT_NAME(RESERVE_NEW_UI_EVENT_ID);
|
||||
* </pre>
|
||||
*/
|
||||
int RESERVE_NEW_UI_EVENT_ID = Integer.MIN_VALUE; // Negative IDs are ignored by the logger.
|
||||
|
||||
int getId();
|
||||
}
|
||||
|
||||
@@ -489,8 +505,7 @@ public class StatsLogManager implements ResourceBasedOverride {
|
||||
LAUNCHER_TURN_OFF_WORK_APPS_TAP(839),
|
||||
|
||||
@UiEvent(doc = "Launcher item drop failed since there was not enough room on the screen.")
|
||||
LAUNCHER_ITEM_DROP_FAILED_INSUFFICIENT_SPACE(872)
|
||||
;
|
||||
LAUNCHER_ITEM_DROP_FAILED_INSUFFICIENT_SPACE(872);
|
||||
|
||||
// ADD MORE
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ import org.junit.rules.TestWatcher;
|
||||
import org.junit.runner.Description;
|
||||
import org.junit.runners.model.Statement;
|
||||
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
@@ -66,15 +67,18 @@ public class FailureWatcher extends TestWatcher {
|
||||
onError(mDevice, description, e);
|
||||
}
|
||||
|
||||
static File diagFile(Description description, String prefix, String ext) {
|
||||
return new File(getInstrumentation().getTargetContext().getFilesDir(),
|
||||
prefix + "-" + description.getTestClass().getSimpleName() + "."
|
||||
+ description.getMethodName() + "." + ext);
|
||||
}
|
||||
|
||||
public static void onError(UiDevice device, Description description, Throwable e) {
|
||||
Log.d("b/196820244", "onError 1");
|
||||
if (device == null) return;
|
||||
Log.d("b/196820244", "onError 2");
|
||||
final File parentFile = getInstrumentation().getTargetContext().getFilesDir();
|
||||
final File sceenshot = new File(parentFile,
|
||||
"TestScreenshot-" + description.getMethodName() + ".png");
|
||||
final File hierarchy = new File(parentFile,
|
||||
"Hierarchy-" + description.getMethodName() + ".zip");
|
||||
final File sceenshot = diagFile(description, "TestScreenshot", "png");
|
||||
final File hierarchy = diagFile(description, "Hierarchy", "zip");
|
||||
|
||||
// Dump window hierarchy
|
||||
try (ZipOutputStream out = new ZipOutputStream(new FileOutputStream(hierarchy))) {
|
||||
@@ -97,13 +101,13 @@ public class FailureWatcher extends TestWatcher {
|
||||
device.takeScreenshot(sceenshot);
|
||||
|
||||
// Dump accessibility hierarchy
|
||||
final File accessibilityHierarchyFile = new File(parentFile,
|
||||
"AccessibilityHierarchy-" + description.getMethodName() + ".uix");
|
||||
try {
|
||||
device.dumpWindowHierarchy(accessibilityHierarchyFile);
|
||||
device.dumpWindowHierarchy(diagFile(description, "AccessibilityHierarchy", "uix"));
|
||||
} catch (IOException ex) {
|
||||
Log.e(TAG, "Failed to save accessibility hierarchy", ex);
|
||||
}
|
||||
|
||||
dumpCommand("logcat -d -s TestRunner", diagFile(description, "FilteredLogcat", "txt"));
|
||||
}
|
||||
|
||||
private static void dumpStringCommand(String cmd, OutputStream out) throws IOException {
|
||||
@@ -111,6 +115,14 @@ public class FailureWatcher extends TestWatcher {
|
||||
dumpCommand(cmd, out);
|
||||
}
|
||||
|
||||
private static void dumpCommand(String cmd, File out) {
|
||||
try (BufferedOutputStream buffered = new BufferedOutputStream(
|
||||
new FileOutputStream(out))) {
|
||||
dumpCommand(cmd, buffered);
|
||||
} catch (IOException ex) {
|
||||
}
|
||||
}
|
||||
|
||||
private static void dumpCommand(String cmd, OutputStream out) throws IOException {
|
||||
try (AutoCloseInputStream in = new AutoCloseInputStream(getInstrumentation()
|
||||
.getUiAutomation().executeShellCommand(cmd))) {
|
||||
|
||||
Reference in New Issue
Block a user