Snap for 10580366 from fd35baa3f8 to udc-qpr1-release
Change-Id: Ia6e829c8a73b015f9c7e6570b82cbc1a84273046
This commit is contained in:
@@ -19,6 +19,6 @@
|
||||
android:viewportHeight="24"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:fillColor="@color/overview_button"
|
||||
android:pathData="M15.08,7.05c0.84,1.18 0.84,2.71 0,3.89l1.68,1.69c2.02,-2.02 2.02,-5.07 0,-7.27l-1.68,1.69zM20.07,2l-1.63,1.63c2.77,3.02 2.77,7.56 0,10.74L20.07,16c3.9,-3.89 3.91,-9.95 0,-14zM9,13c2.21,0 4,-1.79 4,-4s-1.79,-4 -4,-4 -4,1.79 -4,4 1.79,4 4,4zM9,7c1.1,0 2,0.9 2,2s-0.9,2 -2,2 -2,-0.9 -2,-2 0.9,-2 2,-2zM9,14c-2.67,0 -8,1.34 -8,4v3h16v-3c0,-2.66 -5.33,-4 -8,-4zM15,19L3,19v-0.99C3.2,17.29 6.3,16 9,16s5.8,1.29 6,2v1z"/>
|
||||
</vector>
|
||||
|
||||
@@ -19,18 +19,18 @@
|
||||
android:viewportHeight="24"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:fillColor="@color/overview_button"
|
||||
android:pathData="M16,3h-2v2h2c1.65,0 3,1.35 3,3v2h2V8C21,5.24 18.76,3 16,3z"/>
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:fillColor="@color/overview_button"
|
||||
android:pathData="M5,16v-2H3v2c0,2.76 2.24,5 5,5h2v-2H8C6.35,19 5,17.65 5,16z"/>
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:fillColor="@color/overview_button"
|
||||
android:pathData="M12,8.5c-1.93,0 -3.5,1.57 -3.5,3.5s1.57,3.5 3.5,3.5s3.5,-1.57 3.5,-3.5S13.93,8.5 12,8.5z"/>
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:fillColor="@color/overview_button"
|
||||
android:pathData="M18,18m-2,0a2,2 0,1 1,4 0a2,2 0,1 1,-4 0"/>
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:fillColor="@color/overview_button"
|
||||
android:pathData="M5,8c0,-1.65 1.35,-3 3,-3h2V3H8C5.24,3 3,5.24 3,8v2h2V8z"/>
|
||||
</vector>
|
||||
|
||||
@@ -19,6 +19,6 @@
|
||||
android:viewportHeight="24"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:fillColor="@color/overview_button"
|
||||
android:pathData="M12.87,15.07l-2.54,-2.51 0.03,-0.03c1.74,-1.94 2.98,-4.17 3.71,-6.53L17,6L17,4h-7L10,2L8,2v2L1,4v1.99h11.17C11.5,7.92 10.44,9.75 9,11.35 8.07,10.32 7.3,9.19 6.69,8h-2c0.73,1.63 1.73,3.17 2.98,4.56l-5.09,5.02L4,19l5,-5 3.11,3.11 0.76,-2.04zM18.5,10h-2L12,22h2l1.12,-3h4.75L21,22h2l-4.5,-12zM15.88,17l1.62,-4.33L19.12,17h-3.24z"/>
|
||||
</vector>
|
||||
|
||||
@@ -23,8 +23,8 @@
|
||||
<LinearLayout
|
||||
android:id="@+id/action_buttons"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/overview_actions_height"
|
||||
android:layout_gravity="top|center_horizontal"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom|center_horizontal"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<Space
|
||||
@@ -104,13 +104,11 @@
|
||||
</LinearLayout>
|
||||
|
||||
<!-- Unused. Included only for compatibility with parent class. -->
|
||||
<Button
|
||||
<ImageButton
|
||||
android:id="@+id/action_split"
|
||||
style="@style/GoOverviewActionButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:drawableStart="@drawable/ic_split_vertical"
|
||||
android:text="@string/action_split"
|
||||
android:src="@drawable/ic_split_vertical"
|
||||
android:contentDescription="@string/action_split"
|
||||
android:theme="@style/ThemeControlHighlightWorkspaceColor"
|
||||
android:visibility="gone" />
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<dimen name="go_overview_button_container_width">80dp</dimen>
|
||||
<dimen name="go_overview_button_container_margin">16dp</dimen>
|
||||
<dimen name="go_overview_button_caption_margin">8dp</dimen>
|
||||
<dimen name="overview_actions_height">96dp</dimen>
|
||||
<dimen name="overview_actions_size">96dp</dimen>
|
||||
<dimen name="overview_proactive_row_height">0dp</dimen>
|
||||
<dimen name="overview_proactive_row_bottom_margin">24dp</dimen>
|
||||
<dimen name="task_corner_radius_override">28dp</dimen>
|
||||
|
||||
@@ -1,32 +1,10 @@
|
||||
<!-- 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="20dp"
|
||||
android:height="20dp"
|
||||
android:viewportWidth="20"
|
||||
android:viewportHeight="20">
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M5.8334,1.666H8.3334V3.3327H5.8334V6.666H4.1667V3.3327C4.1667,2.4122 4.9129,1.666 5.8334,1.666Z"
|
||||
android:fillColor="#000000"/>
|
||||
<path
|
||||
android:pathData="M4.1667,13.3327V16.666C4.1667,17.5865 4.9129,18.3327 5.8334,18.3327H8.3334V16.666H5.8334V13.3327H4.1667Z"
|
||||
android:fillColor="#000000"/>
|
||||
<path
|
||||
android:pathData="M14.1667,13.3327V16.666H11.6667V18.3327H14.1667C15.0872,18.3327 15.8334,17.5865 15.8334,16.666V13.3327H14.1667Z"
|
||||
android:fillColor="#000000"/>
|
||||
<path
|
||||
android:pathData="M15.8334,6.666V3.3327C15.8334,2.4122 15.0872,1.666 14.1667,1.666H11.6667V3.3327H14.1667V6.666H15.8334Z"
|
||||
android:fillColor="#000000"/>
|
||||
</vector>
|
||||
android:pathData="M5,4C5,2.343 6.343,1 8,1L16,1C17.657,1 19,2.343 19,4L19,20C19,21.657 17.657,23 16,23L8,23C6.343,23 5,21.657 5,20L5,4ZM8,3C7.448,3 7,3.448 7,4L7,20C7,20.552 7.448,21 8,21L16,21C16.552,21 17,20.552 17,20L17,4C17,3.448 16.552,3 16,3L8,3ZM8,4L8,8L9.5,8L9.5,5.5L12,5.5L12,4L8,4ZM16,16L16,20L12,20L12,18.5L14.5,18.5L14.5,16L16,16Z"
|
||||
android:fillColor="@color/overview_button"
|
||||
android:fillType="evenOdd"/>
|
||||
</vector>
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
-->
|
||||
<com.android.launcher3.LauncherRootView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/launcher"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fitsSystemWindows="true">
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
<LinearLayout
|
||||
android:id="@+id/action_buttons"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/overview_actions_height"
|
||||
android:layout_height="@dimen/overview_actions_size"
|
||||
android:layout_gravity="bottom|center_horizontal"
|
||||
android:orientation="horizontal">
|
||||
|
||||
@@ -31,13 +31,14 @@
|
||||
android:layout_height="1dp"
|
||||
android:layout_weight="1" />
|
||||
|
||||
<Button
|
||||
<ImageButton
|
||||
android:id="@+id/action_screenshot"
|
||||
style="@style/OverviewActionButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:drawableStart="@drawable/ic_screenshot"
|
||||
android:text="@string/action_screenshot"
|
||||
android:layout_width="@dimen/overview_actions_size"
|
||||
android:layout_height="@dimen/overview_actions_size"
|
||||
android:gravity="center"
|
||||
android:src="@drawable/ic_screenshot"
|
||||
android:contentDescription="@string/action_screenshot"
|
||||
android:theme="@style/ThemeControlHighlightWorkspaceColor" />
|
||||
|
||||
<Space
|
||||
@@ -46,12 +47,14 @@
|
||||
android:layout_height="1dp"
|
||||
android:visibility="gone" />
|
||||
|
||||
<Button
|
||||
<ImageButton
|
||||
android:id="@+id/action_split"
|
||||
style="@style/OverviewActionButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/action_split"
|
||||
android:layout_width="@dimen/overview_actions_size"
|
||||
android:layout_height="@dimen/overview_actions_size"
|
||||
android:gravity="center"
|
||||
android:src="@drawable/ic_split_vertical"
|
||||
android:contentDescription="@string/action_split"
|
||||
android:theme="@style/ThemeControlHighlightWorkspaceColor"
|
||||
android:visibility="gone" />
|
||||
|
||||
|
||||
@@ -50,8 +50,10 @@
|
||||
|
||||
<!-- Overrideable in overlay that provides the Overview Actions. -->
|
||||
<dimen name="overview_actions_top_margin">24dp</dimen>
|
||||
<dimen name="overview_actions_height">48dp</dimen>
|
||||
<dimen name="overview_actions_size">60dp</dimen>
|
||||
<dimen name="overview_actions_button_spacing">36dp</dimen>
|
||||
<!-- 12dp + 156dp floating search pill width (note this is in addition to normal 36dp) -->
|
||||
<dimen name="overview_actions_additional_floating_search_spacing">168dp</dimen>
|
||||
|
||||
<!-- These speeds are in dp/s -->
|
||||
<dimen name="max_task_dismiss_drag_velocity">2.25dp</dimen>
|
||||
|
||||
@@ -221,15 +221,10 @@
|
||||
<item name="android:colorControlHighlight">?attr/workspaceTextColor</item>
|
||||
</style>
|
||||
|
||||
<style name="OverviewActionButton"
|
||||
parent="@android:style/Widget.DeviceDefault.Button.Borderless">
|
||||
<item name="android:paddingTop">4dp</item>
|
||||
<item name="android:paddingBottom">4dp</item>
|
||||
<item name="android:textColor">@color/overview_button</item>
|
||||
<style name="OverviewActionButton" parent="@android:style/Widget.DeviceDefault.ImageButton">
|
||||
<item name="android:background">@drawable/circle_btn_bg</item>
|
||||
<item name="android:backgroundTint">?androidprv:attr/materialColorSurfaceBright</item>
|
||||
<item name="android:drawableTint">@color/overview_button</item>
|
||||
<item name="android:tint">?android:attr/textColorPrimary</item>
|
||||
<item name="android:drawablePadding">8dp</item>
|
||||
<item name="android:textAllCaps">false</item>
|
||||
</style>
|
||||
|
||||
<style name="OverviewClearAllButton" parent="@android:style/Widget.DeviceDefault.Button">
|
||||
|
||||
@@ -362,10 +362,9 @@ public class BubbleBarController extends IBubblesListener.Stub {
|
||||
}
|
||||
if (bubbleToSelect != null) {
|
||||
setSelectedBubble(bubbleToSelect);
|
||||
}
|
||||
|
||||
if (previouslySelectedBubble == null) {
|
||||
mBubbleStashController.animateToInitialState(update.expanded);
|
||||
if (previouslySelectedBubble == null) {
|
||||
mBubbleStashController.animateToInitialState(update.expanded);
|
||||
}
|
||||
}
|
||||
|
||||
if (update.expandedChanged) {
|
||||
|
||||
@@ -152,6 +152,11 @@ public class BubbleBarViewController {
|
||||
return mBarView.getBubbleBarBounds();
|
||||
}
|
||||
|
||||
/** The horizontal margin of the bubble bar from the edge of the screen. */
|
||||
public int getHorizontalMargin() {
|
||||
return mBarView.getHorizontalMargin();
|
||||
}
|
||||
|
||||
/**
|
||||
* When the bubble bar is not stashed, it can be collapsed (the icons are in a stack) or
|
||||
* expanded (the icons are in a row). This indicates whether the bubble bar is expanded.
|
||||
|
||||
@@ -201,7 +201,7 @@ public class BubbleStashController {
|
||||
public void onSysuiLockedStateChange(boolean isSysuiLocked) {
|
||||
if (isSysuiLocked != mIsSysuiLocked) {
|
||||
mIsSysuiLocked = isSysuiLocked;
|
||||
if (!mIsSysuiLocked) {
|
||||
if (!mIsSysuiLocked && mBarViewController.hasBubbles()) {
|
||||
animateToInitialState(false /* expanding */);
|
||||
}
|
||||
}
|
||||
|
||||
+5
-6
@@ -123,13 +123,15 @@ public class BubbleStashedHandleViewController {
|
||||
private void updateBounds() {
|
||||
// As more bubbles get added, the icon bounds become larger. To ensure a consistent
|
||||
// handle bar position, we pin it to the edge of the screen.
|
||||
Rect bubblebarRect = mBarViewController.getBubbleBarBounds();
|
||||
final int right =
|
||||
mActivity.getDeviceProfile().widthPx - mBarViewController.getHorizontalMargin();
|
||||
|
||||
final int stashedCenterY = mStashedHandleView.getHeight() - mStashedTaskbarHeight / 2;
|
||||
|
||||
mStashedHandleBounds.set(
|
||||
bubblebarRect.right - mStashedHandleWidth,
|
||||
right - mStashedHandleWidth,
|
||||
stashedCenterY - mStashedHandleHeight / 2,
|
||||
bubblebarRect.right,
|
||||
right,
|
||||
stashedCenterY + mStashedHandleHeight / 2);
|
||||
mStashedHandleView.updateSampledRegion(mStashedHandleBounds);
|
||||
|
||||
@@ -240,9 +242,6 @@ public class BubbleStashedHandleViewController {
|
||||
*/
|
||||
public Animator createRevealAnimToIsStashed(boolean isStashed) {
|
||||
Rect bubbleBarBounds = new Rect(mBarViewController.getBubbleBarBounds());
|
||||
// the bubble bar may have been invisible when the bounds were previously calculated,
|
||||
// update them again to ensure they're correct.
|
||||
updateBounds();
|
||||
|
||||
// Account for the full visual height of the bubble bar
|
||||
int heightDiff = (mBarSize - bubbleBarBounds.height()) / 2;
|
||||
|
||||
@@ -125,8 +125,33 @@ public class OverviewState extends LauncherState {
|
||||
|
||||
@Override
|
||||
public int getFloatingSearchBarRestingMarginBottom(Launcher launcher) {
|
||||
return areElementsVisible(launcher, FLOATING_SEARCH_BAR) ? 0
|
||||
: super.getFloatingSearchBarRestingMarginBottom(launcher);
|
||||
if (!areElementsVisible(launcher, FLOATING_SEARCH_BAR)) {
|
||||
return super.getFloatingSearchBarRestingMarginBottom(launcher);
|
||||
}
|
||||
RecentsView recentsView = launcher.getOverviewPanel();
|
||||
DeviceProfile dp = launcher.getDeviceProfile();
|
||||
int activeTaskMarginBottom = LayoutUtils.getShelfTrackingDistance(launcher, dp,
|
||||
recentsView.getPagedOrientationHandler());
|
||||
// Center between task bottom and bottom of the screen.
|
||||
return (activeTaskMarginBottom - dp.overviewActionsHeight) / 2
|
||||
- launcher.getResources().getDimensionPixelSize(R.dimen.qsb_shadow_height);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFloatingSearchBarRestingMarginStart(Launcher launcher) {
|
||||
return getFloatingSearchBarRestingMarginHorizontal(launcher);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFloatingSearchBarRestingMarginEnd(Launcher launcher) {
|
||||
return getFloatingSearchBarRestingMarginHorizontal(launcher);
|
||||
}
|
||||
|
||||
private static int getFloatingSearchBarRestingMarginHorizontal(Launcher launcher) {
|
||||
// Width if the search bar were to be expanded (focused).
|
||||
int expandedWidth = launcher.getResources().getDimensionPixelSize(
|
||||
R.dimen.overview_floating_search_width);
|
||||
return (launcher.getDeviceProfile().widthPx - expandedWidth) / 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -20,6 +20,7 @@ import static android.app.ActivityTaskManager.INVALID_TASK_ID;
|
||||
import static com.android.launcher3.LauncherState.ALL_APPS;
|
||||
import static com.android.launcher3.LauncherState.CLEAR_ALL_BUTTON;
|
||||
import static com.android.launcher3.LauncherState.EDIT_MODE;
|
||||
import static com.android.launcher3.LauncherState.FLOATING_SEARCH_BAR;
|
||||
import static com.android.launcher3.LauncherState.NORMAL;
|
||||
import static com.android.launcher3.LauncherState.OVERVIEW;
|
||||
import static com.android.launcher3.LauncherState.OVERVIEW_MODAL_TASK;
|
||||
@@ -98,6 +99,12 @@ public class LauncherRecentsView extends RecentsView<QuickstepLauncher, Launcher
|
||||
return mActivity.canStartHomeSafely();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFloatingSearchVisible() {
|
||||
return FeatureFlags.ENABLE_FLOATING_SEARCH_BAR.get()
|
||||
&& OVERVIEW.areElementsVisible(mActivity, FLOATING_SEARCH_BAR);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onTaskLaunchAnimationEnd(boolean success) {
|
||||
if (success) {
|
||||
|
||||
@@ -22,12 +22,14 @@ import android.graphics.Rect;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.widget.Button;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.ImageButton;
|
||||
|
||||
import androidx.annotation.IntDef;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.android.launcher3.BaseActivity;
|
||||
import com.android.launcher3.BaseDraggingActivity;
|
||||
import com.android.launcher3.DeviceProfile;
|
||||
import com.android.launcher3.Insettable;
|
||||
import com.android.launcher3.R;
|
||||
@@ -49,6 +51,7 @@ public class OverviewActionsView<T extends OverlayUICallbacks> extends FrameLayo
|
||||
implements OnClickListener, Insettable {
|
||||
|
||||
private final Rect mInsets = new Rect();
|
||||
private BaseDraggingActivity mActivity;
|
||||
|
||||
@IntDef(flag = true, value = {
|
||||
HIDDEN_NON_ZERO_ROTATION,
|
||||
@@ -96,7 +99,7 @@ public class OverviewActionsView<T extends OverlayUICallbacks> extends FrameLayo
|
||||
public static final int FLAG_SINGLE_TASK = 1 << 0;
|
||||
|
||||
private MultiValueAlpha mMultiValueAlpha;
|
||||
private Button mSplitButton;
|
||||
private ImageButton mSplitButton;
|
||||
|
||||
@ActionsHiddenFlags
|
||||
private int mHiddenFlags;
|
||||
@@ -132,6 +135,8 @@ public class OverviewActionsView<T extends OverlayUICallbacks> extends FrameLayo
|
||||
@Override
|
||||
protected void onFinishInflate() {
|
||||
super.onFinishInflate();
|
||||
mActivity = BaseActivity.fromContext(getContext());
|
||||
|
||||
mMultiValueAlpha = new MultiValueAlpha(findViewById(R.id.action_buttons), NUM_ALPHAS);
|
||||
mMultiValueAlpha.setUpdateVisibility(true);
|
||||
|
||||
@@ -273,7 +278,7 @@ public class OverviewActionsView<T extends OverlayUICallbacks> extends FrameLayo
|
||||
LayoutParams actionParams = (LayoutParams) findViewById(
|
||||
R.id.action_buttons).getLayoutParams();
|
||||
actionParams.setMargins(
|
||||
actionParams.leftMargin, mDp.overviewActionsTopMarginPx,
|
||||
actionParams.leftMargin, 0,
|
||||
actionParams.rightMargin, getBottomMargin());
|
||||
}
|
||||
|
||||
@@ -286,6 +291,11 @@ public class OverviewActionsView<T extends OverlayUICallbacks> extends FrameLayo
|
||||
return mDp.stashedTaskbarHeight;
|
||||
}
|
||||
|
||||
if (isFloatingSearchVisible()) {
|
||||
// Center between task and bottom of the screen.
|
||||
return (mDp.heightPx - mTaskSize.bottom - mDp.overviewActionsHeight) / 2;
|
||||
}
|
||||
|
||||
// Align to bottom of task Rect.
|
||||
return mDp.heightPx - mTaskSize.bottom - mDp.overviewActionsTopMarginPx
|
||||
- mDp.overviewActionsHeight;
|
||||
@@ -301,9 +311,12 @@ public class OverviewActionsView<T extends OverlayUICallbacks> extends FrameLayo
|
||||
|
||||
requestLayout();
|
||||
|
||||
mSplitButton.setCompoundDrawablesRelativeWithIntrinsicBounds(
|
||||
(dp.isLandscape ? R.drawable.ic_split_horizontal : R.drawable.ic_split_vertical),
|
||||
0, 0, 0);
|
||||
mSplitButton.setImageResource(
|
||||
dp.isLandscape ? R.drawable.ic_split_horizontal : R.drawable.ic_split_vertical);
|
||||
}
|
||||
|
||||
protected boolean isFloatingSearchVisible() {
|
||||
return ((RecentsView) mActivity.getOverviewPanel()).isFloatingSearchVisible();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -5220,6 +5220,11 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
});
|
||||
}
|
||||
|
||||
/** @return {@code true} if floating search bar is visible in Recents. */
|
||||
public boolean isFloatingSearchVisible() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public RemoteTargetHandle[] getRemoteTargetHandles() {
|
||||
return mRemoteTargetHandles;
|
||||
}
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
|
||||
<item
|
||||
android:alpha="1"
|
||||
android:color="?androidprv:attr/materialColorOnSurface"
|
||||
android:color="?androidprv:attr/materialColorOnSurfaceVariant"
|
||||
android:state_enabled="true" />
|
||||
<item
|
||||
android:alpha="?android:disabledAlpha"
|
||||
android:color="?androidprv:attr/materialColorOnSurface"
|
||||
android:color="?androidprv:attr/materialColorOnSurfaceVariant"
|
||||
android:state_enabled="false" />
|
||||
</selector>
|
||||
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:color="@color/accent_ripple_color">
|
||||
<item android:id="@android:id/mask">
|
||||
<shape android:shape="oval">
|
||||
<solid android:color="@android:color/white" />
|
||||
</shape>
|
||||
</item>
|
||||
<item>
|
||||
<shape android:shape="oval">
|
||||
<solid android:color="@android:color/white" />
|
||||
</shape>
|
||||
</item>
|
||||
</ripple>
|
||||
@@ -5,5 +5,5 @@
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M4,6L9,6L9,18L4,18L4,6ZM2,6L2,18C2,19.1 2.9,20 4,20L9,20C10.1,20 11,19.1 11,18L11,6C11,4.9 10.1,4 9,4L4,4C2.9,4 2,4.9 2,6ZM15,6L20,6L20,18L15,18L15,6ZM13,6L13,18C13,19.1 13.9,20 15,20L20,20C21.1,20 22,19.1 22,18L22,6C22,4.9 21.1,4 20,4L15,4C13.9,4 13,4.9 13,6Z"
|
||||
android:fillColor="#000000"/>
|
||||
android:fillColor="@color/overview_button"/>
|
||||
</vector>
|
||||
|
||||
@@ -5,5 +5,5 @@
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M18,4V9H6V4H18ZM18,2H6C4.9,2 4,2.9 4,4V9C4,10.1 4.9,11 6,11H18C19.1,11 20,10.1 20,9V4C20,2.9 19.1,2 18,2ZM18,15V20H6V15H18ZM18,13H6C4.9,13 4,13.9 4,15V20C4,21.1 4.9,22 6,22H18C19.1,22 20,21.1 20,20V15C20,13.9 19.1,13 18,13Z"
|
||||
android:fillColor="#000000"/>
|
||||
android:fillColor="@color/overview_button"/>
|
||||
</vector>
|
||||
|
||||
@@ -396,10 +396,12 @@
|
||||
<dimen name="task_thumbnail_icon_drawable_size">0dp</dimen>
|
||||
<dimen name="task_thumbnail_icon_drawable_size_grid">0dp</dimen>
|
||||
<dimen name="overview_task_margin">0dp</dimen>
|
||||
<dimen name="overview_actions_height">0dp</dimen>
|
||||
<dimen name="overview_actions_size">0dp</dimen>
|
||||
<dimen name="overview_actions_button_spacing">0dp</dimen>
|
||||
<dimen name="overview_actions_margin_gesture">0dp</dimen>
|
||||
<dimen name="overview_actions_top_margin">0dp</dimen>
|
||||
<!-- Width if the search bar were to be full-size in Overview. Note pill is 192dp smaller. -->
|
||||
<dimen name="overview_floating_search_width">348dp</dimen>
|
||||
<dimen name="overview_grid_side_margin">0dp</dimen>
|
||||
<dimen name="overview_grid_row_spacing">0dp</dimen>
|
||||
<dimen name="overview_page_spacing">0dp</dimen>
|
||||
|
||||
@@ -584,13 +584,11 @@ public class DeviceProfile {
|
||||
overviewTaskIconDrawableSizeGridPx =
|
||||
res.getDimensionPixelSize(R.dimen.task_thumbnail_icon_drawable_size_grid);
|
||||
overviewTaskThumbnailTopMarginPx = overviewTaskIconSizePx + overviewTaskMarginPx;
|
||||
// Don't add margin with floating search bar to minimize risk of overlapping.
|
||||
overviewActionsTopMarginPx = FeatureFlags.ENABLE_FLOATING_SEARCH_BAR.get() ? 0
|
||||
: res.getDimensionPixelSize(R.dimen.overview_actions_top_margin);
|
||||
overviewActionsTopMarginPx = res.getDimensionPixelSize(R.dimen.overview_actions_top_margin);
|
||||
overviewPageSpacing = res.getDimensionPixelSize(R.dimen.overview_page_spacing);
|
||||
overviewActionsButtonSpacing = res.getDimensionPixelSize(
|
||||
R.dimen.overview_actions_button_spacing);
|
||||
overviewActionsHeight = res.getDimensionPixelSize(R.dimen.overview_actions_height);
|
||||
overviewActionsHeight = res.getDimensionPixelSize(R.dimen.overview_actions_size);
|
||||
overviewRowSpacing = res.getDimensionPixelSize(R.dimen.overview_grid_row_spacing);
|
||||
overviewGridSideMargin = res.getDimensionPixelSize(R.dimen.overview_grid_side_margin);
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ import static com.android.launcher3.config.FeatureFlags.ENABLE_ALL_APPS_RV_PREIN
|
||||
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_COUNT;
|
||||
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_TAP_ON_PERSONAL_TAB;
|
||||
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_TAP_ON_WORK_TAB;
|
||||
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
|
||||
import static com.android.launcher3.util.ScrollableLayoutManager.PREDICTIVE_BACK_MIN_SCALE;
|
||||
|
||||
import android.animation.Animator;
|
||||
@@ -461,7 +462,7 @@ public class ActivityAllAppsContainerView<T extends Context & ActivityContext>
|
||||
updateHeaderScroll(0);
|
||||
if (exitSearch) {
|
||||
// Reset the search bar after transitioning home.
|
||||
mSearchUiManager.resetSearch();
|
||||
MAIN_EXECUTOR.getHandler().post(mSearchUiManager::resetSearch);
|
||||
// Animate to A-Z with 0 time to reset the animation with proper state management.
|
||||
animateToSearchState(false, 0);
|
||||
}
|
||||
|
||||
@@ -299,6 +299,28 @@
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity-alias>
|
||||
<activity-alias android:name="MaxShortcutsActivity"
|
||||
android:label="TestActivityMaxShortcuts"
|
||||
android:exported="true"
|
||||
android:targetActivity="com.android.launcher3.testcomponent.OtherBaseTestingActivity">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>
|
||||
<meta-data android:name="android.app.shortcuts"
|
||||
android:resource="@xml/max_shortcuts"/>
|
||||
</activity-alias>
|
||||
<activity-alias android:name="SingleShortcutActivity"
|
||||
android:label="TestActivitySingleShortcut"
|
||||
android:exported="true"
|
||||
android:targetActivity="com.android.launcher3.testcomponent.OtherBaseTestingActivity">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>
|
||||
<meta-data android:name="android.app.shortcuts"
|
||||
android:resource="@xml/single_shortcut"/>
|
||||
</activity-alias>
|
||||
<activity
|
||||
android:name="com.android.launcher3.testcomponent.DialogTestActivity"
|
||||
android:label="Dialog Activity"
|
||||
|
||||
@@ -3,4 +3,5 @@
|
||||
<string name="shortcut1" translatable="false">Shortcut 1</string>
|
||||
<string name="shortcut2" translatable="false">Shortcut 2</string>
|
||||
<string name="shortcut3" translatable="false">Shortcut 3</string>
|
||||
<string name="shortcut4" translatable="false">Shortcut 4</string>
|
||||
</resources>
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright (C) 2023 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.
|
||||
-->
|
||||
<shortcuts xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||
<shortcut
|
||||
android:shortcutId="max_shortcut1"
|
||||
android:icon="@drawable/test_theme_icon"
|
||||
android:shortcutShortLabel="@string/shortcut1">
|
||||
<intent android:action="com.android.launcher3.intent.action.test_shortcut_max"/>
|
||||
</shortcut>
|
||||
<shortcut
|
||||
android:shortcutId="max_shortcut2"
|
||||
android:shortcutShortLabel="@string/shortcut2">
|
||||
<intent android:action="com.android.launcher3.intent.action.test_shortcut_max"/>
|
||||
</shortcut>
|
||||
<shortcut
|
||||
android:shortcutId="max_shortcut3"
|
||||
android:shortcutShortLabel="@string/shortcut3">
|
||||
<intent android:action="com.android.launcher3.intent.action.test_shortcut_max"/>
|
||||
</shortcut>
|
||||
<shortcut
|
||||
android:shortcutId="max_shortcut4"
|
||||
android:shortcutShortLabel="@string/shortcut4">
|
||||
<intent android:action="com.android.launcher3.intent.action.test_shortcut_max"/>
|
||||
</shortcut>
|
||||
</shortcuts>
|
||||
@@ -1,4 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright (C) 2023 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.
|
||||
-->
|
||||
<shortcuts xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||
<shortcut
|
||||
android:shortcutId="shortcut1_themed"
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright (C) 2023 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.
|
||||
-->
|
||||
<shortcuts xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||
<shortcut
|
||||
android:shortcutId="single_shortcut_themed"
|
||||
android:icon="@drawable/test_theme_icon"
|
||||
android:shortcutShortLabel="@string/shortcut1">
|
||||
<intent android:action="com.android.launcher3.intent.action.test_shortcut_single"/>
|
||||
</shortcut>
|
||||
</shortcuts>
|
||||
@@ -16,6 +16,7 @@
|
||||
package com.android.launcher3.celllayout;
|
||||
|
||||
import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
|
||||
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
|
||||
|
||||
import static com.android.launcher3.ui.TestViewHelpers.findWidgetProvider;
|
||||
import static com.android.launcher3.util.WidgetUtils.createWidgetInfo;
|
||||
@@ -43,9 +44,9 @@ import java.util.stream.IntStream;
|
||||
public class TestWorkspaceBuilder {
|
||||
|
||||
private static final String TAG = "CellLayoutBoardBuilder";
|
||||
private static final ComponentName APP_COMPONENT_NAME = new ComponentName(
|
||||
private static final String TEST_ACTIVITY_PACKAGE_PREFIX = "com.android.launcher3.tests.";
|
||||
private ComponentName mAppComponentName = new ComponentName(
|
||||
"com.google.android.calculator", "com.android.calculator2.Calculator");
|
||||
|
||||
private UserHandle mMyUser;
|
||||
|
||||
private Context mContext;
|
||||
@@ -80,8 +81,20 @@ public class TestWorkspaceBuilder {
|
||||
}
|
||||
|
||||
private AppInfo getApp() {
|
||||
return new AppInfo(APP_COMPONENT_NAME, "test icon", mMyUser,
|
||||
AppInfo.makeLaunchIntent(APP_COMPONENT_NAME));
|
||||
return new AppInfo(mAppComponentName, "test icon", mMyUser,
|
||||
AppInfo.makeLaunchIntent(mAppComponentName));
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to set the app to use for the test workspace,
|
||||
* using activity-alias from AndroidManifest-common.
|
||||
* @param testAppName the android:name field of the test app activity-alias to use
|
||||
*/
|
||||
public void setTestAppActivityAlias(String testAppName) {
|
||||
this.mAppComponentName = new ComponentName(
|
||||
getInstrumentation().getContext().getPackageName(),
|
||||
TEST_ACTIVITY_PACKAGE_PREFIX + testAppName
|
||||
);
|
||||
}
|
||||
|
||||
private void addCorrespondingWidgetRect(CellLayoutBoard.WidgetRect widgetRect,
|
||||
|
||||
@@ -15,13 +15,12 @@
|
||||
*/
|
||||
package com.android.launcher3.util.viewcapture_analysis;
|
||||
|
||||
import static com.android.launcher3.util.viewcapture_analysis.ViewCaptureAnalyzer.diagPathFromRoot;
|
||||
|
||||
import com.android.launcher3.util.viewcapture_analysis.ViewCaptureAnalyzer.AnalysisNode;
|
||||
import com.android.launcher3.util.viewcapture_analysis.ViewCaptureAnalyzer.AnomalyDetector;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Anomaly detector that triggers an error when alpha of a view changes too rapidly.
|
||||
@@ -32,9 +31,11 @@ final class AlphaJumpDetector extends AnomalyDetector {
|
||||
private static final String CONTENT = "DecorView|LinearLayout|FrameLayout:id/content|";
|
||||
private static final String DRAG_LAYER =
|
||||
CONTENT + "LauncherRootView:id/launcher|DragLayer:id/drag_layer|";
|
||||
private static final String RECENTS_DRAG_LAYER =
|
||||
CONTENT + "LauncherRootView:id/launcher|RecentsDragLayer:id/drag_layer|";
|
||||
|
||||
// Paths of nodes that are excluded from analysis.
|
||||
private static final Collection<String> PATHS_TO_IGNORE = Set.of(
|
||||
private static final Iterable<String> PATHS_TO_IGNORE = List.of(
|
||||
CONTENT
|
||||
+ "AddItemDragLayer:id/add_item_drag_layer|AddItemWidgetsBottomSheet:id"
|
||||
+ "/add_item_bottom_sheet|LinearLayout:id/add_item_bottom_sheet_content"
|
||||
@@ -112,29 +113,102 @@ final class AlphaJumpDetector extends AnomalyDetector {
|
||||
DRAG_LAYER + "WidgetsFullSheet|SpringRelativeLayout:id/container",
|
||||
DRAG_LAYER + "WidgetsTwoPaneSheet|SpringRelativeLayout:id/container",
|
||||
CONTENT + "LauncherRootView:id/launcher|FloatingIconView",
|
||||
CONTENT
|
||||
+ "LauncherRootView|RecentsDragLayer:id/drag_layer|ArrowTipView|View:id/arrow",
|
||||
CONTENT
|
||||
+ "LauncherRootView|RecentsDragLayer:id/drag_layer|FallbackRecentsView:id"
|
||||
+ "/overview_panel",
|
||||
CONTENT
|
||||
+ "LauncherRootView|RecentsDragLayer:id/drag_layer|NexusOverviewActionsView"
|
||||
+ ":id/overview_actions_view|LinearLayout:id/action_buttons|Button:id"
|
||||
+ "/action_screenshot",
|
||||
CONTENT
|
||||
+ "LauncherRootView|RecentsDragLayer:id/drag_layer|NexusOverviewActionsView"
|
||||
+ ":id/overview_actions_view|LinearLayout:id/action_buttons|Button:id"
|
||||
+ "/action_select"
|
||||
RECENTS_DRAG_LAYER + "ArrowTipView|View:id/arrow",
|
||||
DRAG_LAYER + "FallbackRecentsView:id/overview_panel",
|
||||
RECENTS_DRAG_LAYER + "FallbackRecentsView:id/overview_panel",
|
||||
DRAG_LAYER
|
||||
+ "NexusOverviewActionsView:id/overview_actions_view"
|
||||
+ "|LinearLayout:id/action_buttons|ImageButton:id/action_screenshot",
|
||||
RECENTS_DRAG_LAYER
|
||||
+ "NexusOverviewActionsView:id/overview_actions_view"
|
||||
+ "|LinearLayout:id/action_buttons|ImageButton:id/action_screenshot",
|
||||
DRAG_LAYER
|
||||
+ "NexusOverviewActionsView:id/overview_actions_view"
|
||||
+ "|LinearLayout:id/action_buttons|ImageButton:id/action_select",
|
||||
RECENTS_DRAG_LAYER
|
||||
+ "NexusOverviewActionsView:id/overview_actions_view"
|
||||
+ "|LinearLayout:id/action_buttons|ImageButton:id/action_select",
|
||||
DRAG_LAYER
|
||||
+ "NexusOverviewActionsView:id/overview_actions_view"
|
||||
+ "|LinearLayout:id/action_buttons|ImageButton:id/action_split",
|
||||
RECENTS_DRAG_LAYER
|
||||
+ "NexusOverviewActionsView:id/overview_actions_view"
|
||||
+ "|LinearLayout:id/action_buttons|ImageButton:id/action_split"
|
||||
);
|
||||
|
||||
/**
|
||||
* Element of the tree of ignored nodes.
|
||||
* If the "children" map is empty, then this node should be ignored, i.e. alpha jumps analysis
|
||||
* shouldn't run for it.
|
||||
* I.e. ignored nodes correspond to the leaves in the ignored nodes tree.
|
||||
*/
|
||||
private static class IgnoreNode {
|
||||
// Map from child node identities to ignore-nodes for these children.
|
||||
public final Map<String, IgnoreNode> children = new HashMap<>();
|
||||
}
|
||||
|
||||
private static final IgnoreNode IGNORED_NODES_ROOT = buildIgnoreNodesTree();
|
||||
|
||||
// Converts the list of full paths of nodes to ignore to a more efficient tree of ignore-nodes.
|
||||
private static IgnoreNode buildIgnoreNodesTree() {
|
||||
final IgnoreNode root = new IgnoreNode();
|
||||
for (String pathToIgnore : PATHS_TO_IGNORE) {
|
||||
// Scan the diag path of an ignored node and add its elements into the tree.
|
||||
IgnoreNode currentIgnoreNode = root;
|
||||
for (String part : pathToIgnore.split("\\|")) {
|
||||
// Ensure that the child of the node is added to the tree.
|
||||
IgnoreNode child = currentIgnoreNode.children.get(part);
|
||||
if (child == null) {
|
||||
currentIgnoreNode.children.put(part, child = new IgnoreNode());
|
||||
}
|
||||
currentIgnoreNode = child;
|
||||
}
|
||||
}
|
||||
return root;
|
||||
}
|
||||
|
||||
// Minimal increase or decrease of view's alpha between frames that triggers the error.
|
||||
private static final float ALPHA_JUMP_THRESHOLD = 1f;
|
||||
|
||||
// Per-AnalysisNode data that's specific to this detector.
|
||||
private static class NodeData {
|
||||
public boolean ignoreAlphaJumps;
|
||||
|
||||
// If ignoreNode is null, then this AnalysisNode node will be ignored if its parent is
|
||||
// ignored.
|
||||
// Otherwise, this AnalysisNode will be ignored if ignoreNode is a leaf i.e. has no
|
||||
// children.
|
||||
public IgnoreNode ignoreNode;
|
||||
}
|
||||
|
||||
private NodeData getNodeData(AnalysisNode info) {
|
||||
return (NodeData) info.detectorsData[detectorOrdinal];
|
||||
}
|
||||
|
||||
@Override
|
||||
void initializeNode(AnalysisNode info) {
|
||||
final NodeData nodeData = new NodeData();
|
||||
info.detectorsData[detectorOrdinal] = nodeData;
|
||||
|
||||
// If the parent view ignores alpha jumps, its descendants will too.
|
||||
final boolean parentIgnoreAlphaJumps = info.parent != null && info.parent.ignoreAlphaJumps;
|
||||
info.ignoreAlphaJumps = parentIgnoreAlphaJumps
|
||||
|| PATHS_TO_IGNORE.contains(diagPathFromRoot(info));
|
||||
final boolean parentIgnoresAlphaJumps = info.parent != null && getNodeData(
|
||||
info.parent).ignoreAlphaJumps;
|
||||
if (parentIgnoresAlphaJumps) {
|
||||
nodeData.ignoreAlphaJumps = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// Parent view doesn't ignore alpha jumps.
|
||||
// Initialize this AnalysisNode's ignore-node with the corresponding child of the
|
||||
// ignore-node of the parent, if present.
|
||||
final IgnoreNode parentIgnoreNode = info.parent != null
|
||||
? getNodeData(info.parent).ignoreNode
|
||||
: IGNORED_NODES_ROOT;
|
||||
nodeData.ignoreNode = parentIgnoreNode != null
|
||||
? parentIgnoreNode.children.get(info.nodeIdentity) : null;
|
||||
// AnalysisNode will be ignored if the corresponding ignore-node is a leaf.
|
||||
nodeData.ignoreAlphaJumps =
|
||||
nodeData.ignoreNode != null && nodeData.ignoreNode.children.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -144,7 +218,7 @@ final class AlphaJumpDetector extends AnomalyDetector {
|
||||
if (oldInfo != null && oldInfo.frameN != frameN) return;
|
||||
|
||||
final AnalysisNode latestInfo = newInfo != null ? newInfo : oldInfo;
|
||||
if (latestInfo.ignoreAlphaJumps) return;
|
||||
if (getNodeData(latestInfo).ignoreAlphaJumps) return;
|
||||
|
||||
final float oldAlpha = oldInfo != null ? oldInfo.alpha : 0;
|
||||
final float newAlpha = newInfo != null ? newInfo.alpha : 0;
|
||||
|
||||
+26
-12
@@ -40,6 +40,9 @@ public class ViewCaptureAnalyzer {
|
||||
* Detector of one kind of anomaly.
|
||||
*/
|
||||
abstract static class AnomalyDetector {
|
||||
// Index of this detector in ViewCaptureAnalyzer.ANOMALY_DETECTORS
|
||||
public int detectorOrdinal;
|
||||
|
||||
/**
|
||||
* Initializes fields of the node that are specific to the anomaly detected by this
|
||||
* detector.
|
||||
@@ -64,9 +67,13 @@ public class ViewCaptureAnalyzer {
|
||||
}
|
||||
|
||||
// All detectors. They will be invoked in the order listed here.
|
||||
private static final Iterable<AnomalyDetector> ANOMALY_DETECTORS = Arrays.asList(
|
||||
private static final AnomalyDetector[] ANOMALY_DETECTORS = {
|
||||
new AlphaJumpDetector()
|
||||
);
|
||||
};
|
||||
|
||||
static {
|
||||
for (int i = 0; i < ANOMALY_DETECTORS.length; ++i) ANOMALY_DETECTORS[i].detectorOrdinal = i;
|
||||
}
|
||||
|
||||
// A view from view capture data converted to a form that's convenient for detecting anomalies.
|
||||
static class AnalysisNode {
|
||||
@@ -86,7 +93,11 @@ public class ViewCaptureAnalyzer {
|
||||
public int frameN;
|
||||
public ViewNode viewCaptureNode;
|
||||
|
||||
public boolean ignoreAlphaJumps;
|
||||
// Class name + resource id
|
||||
public String nodeIdentity;
|
||||
|
||||
// Collection of detector-specific data for this node.
|
||||
public final Object[] detectorsData = new Object[ANOMALY_DETECTORS.length];
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
@@ -139,7 +150,7 @@ public class ViewCaptureAnalyzer {
|
||||
for (AnalysisNode info : lastSeenNodes.values()) {
|
||||
if (info.frameN == frameN - 1) {
|
||||
if (!info.viewCaptureNode.getWillNotDraw()) {
|
||||
ANOMALY_DETECTORS.forEach(
|
||||
Arrays.stream(ANOMALY_DETECTORS).forEach(
|
||||
detector -> detector.detectAnomalies(
|
||||
/* oldInfo = */ info,
|
||||
/* newInfo = */ null,
|
||||
@@ -177,6 +188,8 @@ public class ViewCaptureAnalyzer {
|
||||
final AnalysisNode newAnalysisNode = new AnalysisNode();
|
||||
newAnalysisNode.className = viewCaptureData.getClassname(classIndex);
|
||||
newAnalysisNode.resourceId = viewCaptureNode.getId();
|
||||
newAnalysisNode.nodeIdentity =
|
||||
getNodeIdentity(newAnalysisNode.className, newAnalysisNode.resourceId);
|
||||
newAnalysisNode.parent = parent;
|
||||
newAnalysisNode.left = left;
|
||||
newAnalysisNode.top = top;
|
||||
@@ -185,12 +198,13 @@ public class ViewCaptureAnalyzer {
|
||||
newAnalysisNode.alpha = alpha;
|
||||
newAnalysisNode.frameN = frameN;
|
||||
newAnalysisNode.viewCaptureNode = viewCaptureNode;
|
||||
ANOMALY_DETECTORS.forEach(detector -> detector.initializeNode(newAnalysisNode));
|
||||
Arrays.stream(ANOMALY_DETECTORS).forEach(
|
||||
detector -> detector.initializeNode(newAnalysisNode));
|
||||
|
||||
// Detect anomalies for the view
|
||||
final AnalysisNode oldAnalysisNode = lastSeenNodes.get(hashcode); // may be null
|
||||
if (frameN != 0 && !viewCaptureNode.getWillNotDraw()) {
|
||||
ANOMALY_DETECTORS.forEach(
|
||||
Arrays.stream(ANOMALY_DETECTORS).forEach(
|
||||
detector -> detector.detectAnomalies(oldAnalysisNode, newAnalysisNode, frameN));
|
||||
}
|
||||
lastSeenNodes.put(hashcode, newAnalysisNode);
|
||||
@@ -221,18 +235,18 @@ public class ViewCaptureAnalyzer {
|
||||
return className.substring(className.lastIndexOf(".") + 1);
|
||||
}
|
||||
|
||||
static String diagPathFromRoot(AnalysisNode nodeBox) {
|
||||
final StringBuilder path = new StringBuilder(diagPathElement(nodeBox));
|
||||
private static String diagPathFromRoot(AnalysisNode nodeBox) {
|
||||
final StringBuilder path = new StringBuilder(nodeBox.nodeIdentity);
|
||||
for (AnalysisNode ancestor = nodeBox.parent; ancestor != null; ancestor = ancestor.parent) {
|
||||
path.insert(0, diagPathElement(ancestor) + "|");
|
||||
path.insert(0, ancestor.nodeIdentity + "|");
|
||||
}
|
||||
return path.toString();
|
||||
}
|
||||
|
||||
private static String diagPathElement(AnalysisNode nodeBox) {
|
||||
private static String getNodeIdentity(String className, String resourceId) {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
sb.append(classNameToSimpleName(nodeBox.className));
|
||||
if (!"NO_ID".equals(nodeBox.resourceId)) sb.append(":" + nodeBox.resourceId);
|
||||
sb.append(classNameToSimpleName(className));
|
||||
if (!"NO_ID".equals(resourceId)) sb.append(":" + resourceId);
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user