Snap for 10106040 from 4d17468f88 to udc-release
Change-Id: I5d24fe1c0dc961081331092c43d2be016c2f0424
This commit is contained in:
@@ -43,7 +43,8 @@ class BubbleBarBackground(context: TaskbarActivityContext, private val backgroun
|
||||
private var shadowBlur = 0f
|
||||
private var keyShadowDistance = 0f
|
||||
|
||||
private var arrowPositionX: Float = 0f
|
||||
var arrowPositionX: Float = 0f
|
||||
private set
|
||||
private var showingArrow: Boolean = false
|
||||
private var arrowDrawable: ShapeDrawable
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.android.launcher3.taskbar.bubbles;
|
||||
|
||||
import android.animation.ValueAnimator;
|
||||
import android.annotation.Nullable;
|
||||
import android.content.Context;
|
||||
import android.graphics.Rect;
|
||||
@@ -41,14 +42,14 @@ import java.util.List;
|
||||
* - stashed as a handle
|
||||
* - unstashed but collapsed, in this state the bar is showing but the bubbles are stacked within it
|
||||
* - unstashed and expanded, in this state the bar is showing and the bubbles are shown in a row
|
||||
* with one of the bubbles being selected. Additionally, WMShell will display the expanded bubble
|
||||
* view above the bar.
|
||||
* with one of the bubbles being selected. Additionally, WMShell will display the expanded bubble
|
||||
* view above the bar.
|
||||
* <p>
|
||||
* The bubble bar has some behavior related to taskbar:
|
||||
* - When taskbar is unstashed, bubble bar will also become unstashed (but in its "collapsed"
|
||||
* state)
|
||||
* state)
|
||||
* - When taskbar is stashed, bubble bar will also become stashed (unless bubble bar is in its
|
||||
* "expanded" state)
|
||||
* "expanded" state)
|
||||
* - When bubble bar is in its "expanded" state, taskbar becomes stashed
|
||||
* <p>
|
||||
* If there are no bubbles, the bubble bar and bubble stashed handle are not shown. Additionally
|
||||
@@ -64,6 +65,7 @@ public class BubbleBarView extends FrameLayout {
|
||||
// TODO: (b/273594744) calculate the amount of space we have and base the max on that
|
||||
// if it's smaller than 5.
|
||||
private static final int MAX_BUBBLES = 5;
|
||||
private static final int ARROW_POSITION_ANIMATION_DURATION_MS = 200;
|
||||
|
||||
private final TaskbarActivityContext mActivityContext;
|
||||
private final BubbleBarBackground mBubbleBarBackground;
|
||||
@@ -209,14 +211,18 @@ public class BubbleBarView extends FrameLayout {
|
||||
/**
|
||||
* Sets which bubble view should be shown as selected.
|
||||
*/
|
||||
// TODO: (b/273592694) animate it
|
||||
public void setSelectedBubble(BubbleView view) {
|
||||
mSelectedBubbleView = view;
|
||||
updateArrowForSelected();
|
||||
invalidate();
|
||||
updateArrowForSelected(/* shouldAnimate= */ true);
|
||||
}
|
||||
|
||||
private void updateArrowForSelected() {
|
||||
/**
|
||||
* Update the arrow position to match the selected bubble.
|
||||
*
|
||||
* @param shouldAnimate whether or not to animate the arrow. If the bar was just expanded, this
|
||||
* should be set to {@code false}. Otherwise set this to {@code true}.
|
||||
*/
|
||||
private void updateArrowForSelected(boolean shouldAnimate) {
|
||||
if (mSelectedBubbleView == null) {
|
||||
Log.w(TAG, "trying to update selection arrow without a selected view!");
|
||||
return;
|
||||
@@ -224,7 +230,21 @@ public class BubbleBarView extends FrameLayout {
|
||||
final int index = indexOfChild(mSelectedBubbleView);
|
||||
// Find the center of the bubble when it's expanded, set the arrow position to it.
|
||||
final float tx = getPaddingStart() + index * (mIconSize + mIconSpacing) + mIconSize / 2f;
|
||||
mBubbleBarBackground.setArrowPosition(tx);
|
||||
|
||||
if (shouldAnimate) {
|
||||
final float currentArrowPosition = mBubbleBarBackground.getArrowPositionX();
|
||||
ValueAnimator animator = ValueAnimator.ofFloat(currentArrowPosition, tx);
|
||||
animator.setDuration(ARROW_POSITION_ANIMATION_DURATION_MS);
|
||||
animator.addUpdateListener(animation -> {
|
||||
float x = (float) animation.getAnimatedValue();
|
||||
mBubbleBarBackground.setArrowPosition(x);
|
||||
invalidate();
|
||||
});
|
||||
animator.start();
|
||||
} else {
|
||||
mBubbleBarBackground.setArrowPosition(tx);
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -248,7 +268,7 @@ public class BubbleBarView extends FrameLayout {
|
||||
public void setExpanded(boolean isBarExpanded) {
|
||||
if (mIsBarExpanded != isBarExpanded) {
|
||||
mIsBarExpanded = isBarExpanded;
|
||||
updateArrowForSelected();
|
||||
updateArrowForSelected(/* shouldAnimate= */ false);
|
||||
setOrUnsetClickListener();
|
||||
if (!isBarExpanded && mReorderRunnable != null) {
|
||||
mReorderRunnable.run();
|
||||
|
||||
@@ -17,11 +17,9 @@ package com.android.quickstep.util;
|
||||
|
||||
import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
|
||||
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
|
||||
import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
|
||||
|
||||
import android.util.FloatProperty;
|
||||
import android.view.RemoteAnimationTarget;
|
||||
import android.view.SurfaceControl;
|
||||
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.anim.Interpolators;
|
||||
@@ -61,7 +59,6 @@ public class TransformParams {
|
||||
private float mCornerRadius;
|
||||
private RemoteAnimationTargets mTargetSet;
|
||||
private SurfaceTransactionApplier mSyncTransactionApplier;
|
||||
private SurfaceControl mRecentsSurface;
|
||||
|
||||
private BuilderProxy mHomeBuilderProxy = BuilderProxy.ALWAYS_VISIBLE;
|
||||
private BuilderProxy mBaseBuilderProxy = BuilderProxy.ALWAYS_VISIBLE;
|
||||
@@ -141,8 +138,9 @@ public class TransformParams {
|
||||
public SurfaceTransaction createSurfaceParams(BuilderProxy proxy) {
|
||||
RemoteAnimationTargets targets = mTargetSet;
|
||||
SurfaceTransaction transaction = new SurfaceTransaction();
|
||||
mRecentsSurface = getRecentsSurface(targets);
|
||||
|
||||
if (targets == null) {
|
||||
return transaction;
|
||||
}
|
||||
for (int i = 0; i < targets.unfilteredApps.length; i++) {
|
||||
RemoteAnimationTarget app = targets.unfilteredApps[i];
|
||||
SurfaceProperties builder = transaction.forSurface(app.leash);
|
||||
@@ -176,20 +174,6 @@ public class TransformParams {
|
||||
return transaction;
|
||||
}
|
||||
|
||||
private static SurfaceControl getRecentsSurface(RemoteAnimationTargets targets) {
|
||||
for (int i = 0; i < targets.unfilteredApps.length; i++) {
|
||||
RemoteAnimationTarget app = targets.unfilteredApps[i];
|
||||
if (app.mode == targets.targetMode) {
|
||||
if (app.windowConfiguration.getActivityType() == ACTIVITY_TYPE_RECENTS) {
|
||||
return app.leash;
|
||||
}
|
||||
} else {
|
||||
return app.leash;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Pubic getters so outside packages can read the values.
|
||||
|
||||
public float getProgress() {
|
||||
@@ -204,10 +188,6 @@ public class TransformParams {
|
||||
return mCornerRadius;
|
||||
}
|
||||
|
||||
public SurfaceControl getRecentsSurface() {
|
||||
return mRecentsSurface;
|
||||
}
|
||||
|
||||
public RemoteAnimationTargets getTargetSet() {
|
||||
return mTargetSet;
|
||||
}
|
||||
|
||||
@@ -199,6 +199,9 @@
|
||||
<attr name="demoModeLayoutId" format="reference" />
|
||||
<attr name="isScalable" format="boolean" />
|
||||
<attr name="devicePaddingId" format="reference" />
|
||||
<!-- File that contains the specs for the workspace.
|
||||
Needs FeatureFlags.ENABLE_RESPONSIVE_WORKSPACE enabled -->
|
||||
<attr name="workspaceSpecsId" format="reference" />
|
||||
<!-- By default all categories are enabled -->
|
||||
<attr name="deviceCategory" format="integer">
|
||||
<!-- Enable on phone only -->
|
||||
|
||||
@@ -26,6 +26,6 @@
|
||||
launcher:category="1"
|
||||
launcher:sectionDrawable="@drawable/ic_note_taking_widget_category"
|
||||
launcher:sectionTitle="@string/widget_category_note_taking">
|
||||
<widget launcher:provider="com.android.settings/com.android.settings.notetask.shortcut.CreateNoteTaskShortcutActivity" />
|
||||
<widget launcher:provider="com.android.systemui/.notetask.shortcut.CreateNoteTaskShortcutActivity" />
|
||||
</section>
|
||||
</widget-sections>
|
||||
@@ -101,6 +101,7 @@ public class DeviceProfile {
|
||||
public final float aspectRatio;
|
||||
|
||||
public final boolean isScalableGrid;
|
||||
public final boolean isResponsiveGrid;
|
||||
private final int mTypeIndex;
|
||||
|
||||
/**
|
||||
@@ -293,6 +294,10 @@ public class DeviceProfile {
|
||||
this.rotationHint = windowBounds.rotationHint;
|
||||
mInsets.set(windowBounds.insets);
|
||||
|
||||
// TODO(b/241386436):
|
||||
// for testing that the flag works only, shouldn't change any launcher behaviour
|
||||
isResponsiveGrid = inv.workspaceSpecsId != INVALID_RESOURCE_HANDLE;
|
||||
|
||||
isScalableGrid = inv.isScalable && !isVerticalBarLayout() && !isMultiWindowMode;
|
||||
// Determine device posture.
|
||||
mInfo = info;
|
||||
@@ -1577,6 +1582,7 @@ public class DeviceProfile {
|
||||
|
||||
writer.println(prefix + "\taspectRatio:" + aspectRatio);
|
||||
|
||||
writer.println(prefix + "\tisResponsiveGrid:" + isResponsiveGrid);
|
||||
writer.println(prefix + "\tisScalableGrid:" + isScalableGrid);
|
||||
|
||||
writer.println(prefix + "\tinv.numRows: " + inv.numRows);
|
||||
|
||||
@@ -48,6 +48,7 @@ import androidx.annotation.VisibleForTesting;
|
||||
import androidx.annotation.XmlRes;
|
||||
import androidx.core.content.res.ResourcesCompat;
|
||||
|
||||
import com.android.launcher3.config.FeatureFlags;
|
||||
import com.android.launcher3.icons.DotRenderer;
|
||||
import com.android.launcher3.model.DeviceGridState;
|
||||
import com.android.launcher3.provider.RestoreDbTask;
|
||||
@@ -105,7 +106,7 @@ public class InvariantDeviceProfile {
|
||||
static final int INDEX_TWO_PANEL_PORTRAIT = 2;
|
||||
static final int INDEX_TWO_PANEL_LANDSCAPE = 3;
|
||||
|
||||
/** These resources are used to override the device profile */
|
||||
/** These resources are used to override the device profile */
|
||||
private static final String RES_GRID_NUM_ROWS = "grid_num_rows";
|
||||
private static final String RES_GRID_NUM_COLUMNS = "grid_num_columns";
|
||||
private static final String RES_GRID_ICON_SIZE_DP = "grid_icon_size_dp";
|
||||
@@ -177,6 +178,8 @@ public class InvariantDeviceProfile {
|
||||
protected boolean isScalable;
|
||||
@XmlRes
|
||||
public int devicePaddingId = INVALID_RESOURCE_HANDLE;
|
||||
@XmlRes
|
||||
public int workspaceSpecsId = INVALID_RESOURCE_HANDLE;
|
||||
|
||||
public String dbFile;
|
||||
public int defaultLayoutId;
|
||||
@@ -350,6 +353,7 @@ public class InvariantDeviceProfile {
|
||||
|
||||
isScalable = closestProfile.isScalable;
|
||||
devicePaddingId = closestProfile.devicePaddingId;
|
||||
workspaceSpecsId = closestProfile.mWorkspaceSpecsId;
|
||||
this.deviceType = deviceType;
|
||||
|
||||
inlineNavButtonsEndSpacing = closestProfile.inlineNavButtonsEndSpacing;
|
||||
@@ -795,6 +799,7 @@ public class InvariantDeviceProfile {
|
||||
|
||||
private final boolean isScalable;
|
||||
private final int devicePaddingId;
|
||||
private final int mWorkspaceSpecsId;
|
||||
|
||||
public GridOption(Context context, AttributeSet attrs) {
|
||||
TypedArray a = context.obtainStyledAttributes(
|
||||
@@ -836,7 +841,7 @@ public class InvariantDeviceProfile {
|
||||
|
||||
inlineNavButtonsEndSpacing =
|
||||
a.getResourceId(R.styleable.GridDisplayOption_inlineNavButtonsEndSpacing,
|
||||
R.dimen.taskbar_button_margin_default);
|
||||
R.dimen.taskbar_button_margin_default);
|
||||
|
||||
numFolderRows = a.getInt(
|
||||
R.styleable.GridDisplayOption_numFolderRows, numRows);
|
||||
@@ -856,6 +861,13 @@ public class InvariantDeviceProfile {
|
||||
deviceCategory = a.getInt(R.styleable.GridDisplayOption_deviceCategory,
|
||||
DEVICE_CATEGORY_ALL);
|
||||
|
||||
if (FeatureFlags.ENABLE_RESPONSIVE_WORKSPACE.get()) {
|
||||
mWorkspaceSpecsId = a.getResourceId(
|
||||
R.styleable.GridDisplayOption_workspaceSpecsId, INVALID_RESOURCE_HANDLE);
|
||||
} else {
|
||||
mWorkspaceSpecsId = INVALID_RESOURCE_HANDLE;
|
||||
}
|
||||
|
||||
int inlineForRotation = a.getInt(R.styleable.GridDisplayOption_inlineQsb,
|
||||
DONT_INLINE_QSB);
|
||||
inlineQsb[INDEX_DEFAULT] =
|
||||
|
||||
@@ -214,6 +214,7 @@ import com.android.launcher3.util.TouchController;
|
||||
import com.android.launcher3.util.TraceHelper;
|
||||
import com.android.launcher3.util.ViewOnDrawExecutor;
|
||||
import com.android.launcher3.views.ActivityContext;
|
||||
import com.android.launcher3.views.ComposeInitializer;
|
||||
import com.android.launcher3.views.FloatingIconView;
|
||||
import com.android.launcher3.views.FloatingSurfaceView;
|
||||
import com.android.launcher3.views.OptionsPopupView;
|
||||
@@ -553,6 +554,8 @@ public class Launcher extends StatefulActivity<LauncherState>
|
||||
setDefaultKeyMode(DEFAULT_KEYS_SEARCH_LOCAL);
|
||||
|
||||
setContentView(getRootView());
|
||||
ComposeInitializer.initCompose(this);
|
||||
|
||||
if (mOnInitialBindListener != null) {
|
||||
getRootView().getViewTreeObserver().addOnPreDrawListener(mOnInitialBindListener);
|
||||
}
|
||||
|
||||
@@ -416,6 +416,10 @@ public final class FeatureFlags {
|
||||
|
||||
// TODO(Block 32): Empty block
|
||||
|
||||
public static final BooleanFlag ENABLE_RESPONSIVE_WORKSPACE = getDebugFlag(241386436,
|
||||
"ENABLE_RESPONSIVE_WORKSPACE", DISABLED,
|
||||
"Enables new workspace grid calculations method.");
|
||||
|
||||
public static class BooleanFlag {
|
||||
|
||||
private final boolean mCurrentValue;
|
||||
|
||||
@@ -0,0 +1,229 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.android.launcher3.views;
|
||||
|
||||
import android.os.Build;
|
||||
import android.view.View;
|
||||
import android.view.ViewParent;
|
||||
import android.view.ViewTreeObserver;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.RequiresApi;
|
||||
import androidx.lifecycle.Lifecycle;
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
import androidx.lifecycle.LifecycleRegistry;
|
||||
import androidx.lifecycle.ViewTreeLifecycleOwner;
|
||||
import androidx.savedstate.SavedStateRegistry;
|
||||
import androidx.savedstate.SavedStateRegistryController;
|
||||
import androidx.savedstate.SavedStateRegistryOwner;
|
||||
import androidx.savedstate.ViewTreeSavedStateRegistryOwner;
|
||||
|
||||
import com.android.launcher3.Utilities;
|
||||
|
||||
/**
|
||||
* An initializer to use Compose for classes implementing {@code ActivityContext}. This allows
|
||||
* adding ComposeView to ViewTree outside a {@link androidx.activity.ComponentActivity}.
|
||||
*/
|
||||
public final class ComposeInitializer {
|
||||
/**
|
||||
* Performs the initialization to use Compose in the ViewTree of {@code target}.
|
||||
*/
|
||||
public static void initCompose(ActivityContext target) {
|
||||
getContentChild(target).addOnAttachStateChangeListener(
|
||||
new View.OnAttachStateChangeListener() {
|
||||
|
||||
@Override
|
||||
public void onViewAttachedToWindow(View v) {
|
||||
ComposeInitializer.onAttachedToWindow(v);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewDetachedFromWindow(View v) {
|
||||
ComposeInitializer.onDetachedFromWindow(v);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the "content child" for {@code target}.
|
||||
*
|
||||
* @see "WindowRecomposer.android.kt: [View.contentChild]"
|
||||
*/
|
||||
private static View getContentChild(ActivityContext target) {
|
||||
View self = target.getDragLayer();
|
||||
ViewParent parent = self.getParent();
|
||||
while (parent instanceof View parentView) {
|
||||
if (parentView.getId() == android.R.id.content) return self;
|
||||
self = parentView;
|
||||
parent = self.getParent();
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to be called on your window root view's [View.onAttachedToWindow] function.
|
||||
*/
|
||||
private static void onAttachedToWindow(View root) {
|
||||
if (ViewTreeLifecycleOwner.get(root) != null) {
|
||||
throw new IllegalStateException(
|
||||
"View " + root + " already has a LifecycleOwner");
|
||||
}
|
||||
|
||||
ViewParent parent = root.getParent();
|
||||
if (parent instanceof View && ((View) parent).getId() != android.R.id.content) {
|
||||
throw new IllegalStateException(
|
||||
"ComposeInitializer.onContentChildAttachedToWindow(View) must be called on "
|
||||
+ "the content child. Outside of activities and dialogs, this is "
|
||||
+ "usually the top-most View of a window.");
|
||||
}
|
||||
|
||||
// The lifecycle owner, which is STARTED when [root] is visible and RESUMED when [root]
|
||||
// is both visible and focused.
|
||||
ViewLifecycleOwner lifecycleOwner = new ViewLifecycleOwner(root);
|
||||
|
||||
// We must call [ViewLifecycleOwner.onCreate] after creating the
|
||||
// [SavedStateRegistryOwner] because `onCreate` might move the lifecycle state to STARTED
|
||||
// which will make [SavedStateRegistryController.performRestore] throw.
|
||||
lifecycleOwner.onCreate();
|
||||
|
||||
// Set the owners on the root. They will be reused by any ComposeView inside the root
|
||||
// hierarchy.
|
||||
ViewTreeLifecycleOwner.set(root, lifecycleOwner);
|
||||
ViewTreeSavedStateRegistryOwner.set(root, lifecycleOwner);
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to be called on your window root view's [View.onDetachedFromWindow] function.
|
||||
*/
|
||||
private static void onDetachedFromWindow(View root) {
|
||||
final LifecycleOwner lifecycleOwner = ViewTreeLifecycleOwner.get(root);
|
||||
if (lifecycleOwner != null) {
|
||||
((ViewLifecycleOwner) lifecycleOwner).onDestroy();
|
||||
}
|
||||
ViewTreeLifecycleOwner.set(root, null);
|
||||
ViewTreeSavedStateRegistryOwner.set(root, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* A [LifecycleOwner] for a [View] that updates lifecycle state based on window state.
|
||||
*
|
||||
* Also a trivial implementation of [SavedStateRegistryOwner] that does not do any save or
|
||||
* restore. This works for processes similar to the SystemUI process, which is always running
|
||||
* and top-level windows using this initialization are created once, when the process is
|
||||
* started.
|
||||
*
|
||||
* The implementation requires the caller to call [onCreate] and [onDestroy] when the view is
|
||||
* attached to or detached from a view hierarchy. After [onCreate] and before [onDestroy] is
|
||||
* called, the implementation monitors window state in the following way
|
||||
* * If the window is not visible, we are in the [Lifecycle.State.CREATED] state
|
||||
* * If the window is visible but not focused, we are in the [Lifecycle.State.STARTED] state
|
||||
* * If the window is visible and focused, we are in the [Lifecycle.State.RESUMED] state
|
||||
*
|
||||
* Or in table format:
|
||||
* ```
|
||||
* ┌───────────────┬───────────────────┬──────────────┬─────────────────┐
|
||||
* │ View attached │ Window Visibility │ Window Focus │ Lifecycle State │
|
||||
* ├───────────────┼───────────────────┴──────────────┼─────────────────┤
|
||||
* │ Not attached │ Any │ N/A │
|
||||
* ├───────────────┼───────────────────┬──────────────┼─────────────────┤
|
||||
* │ │ Not visible │ Any │ CREATED │
|
||||
* │ ├───────────────────┼──────────────┼─────────────────┤
|
||||
* │ Attached │ │ No focus │ STARTED │
|
||||
* │ │ Visible ├──────────────┼─────────────────┤
|
||||
* │ │ │ Has focus │ RESUMED │
|
||||
* └───────────────┴───────────────────┴──────────────┴─────────────────┘
|
||||
* ```
|
||||
*/
|
||||
private static class ViewLifecycleOwner implements SavedStateRegistryOwner {
|
||||
private final ViewTreeObserver.OnWindowFocusChangeListener mWindowFocusListener =
|
||||
hasFocus -> updateState();
|
||||
private final LifecycleRegistry mLifecycleRegistry = new LifecycleRegistry(this);
|
||||
|
||||
private final SavedStateRegistryController mSavedStateRegistryController =
|
||||
SavedStateRegistryController.create(this);
|
||||
|
||||
private final View mView;
|
||||
private final Api34Impl mApi34Impl;
|
||||
|
||||
ViewLifecycleOwner(View view) {
|
||||
mView = view;
|
||||
if (Utilities.ATLEAST_U) {
|
||||
mApi34Impl = new Api34Impl();
|
||||
} else {
|
||||
mApi34Impl = null;
|
||||
}
|
||||
|
||||
mSavedStateRegistryController.performRestore(null);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Lifecycle getLifecycle() {
|
||||
return mLifecycleRegistry;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public SavedStateRegistry getSavedStateRegistry() {
|
||||
return mSavedStateRegistryController.getSavedStateRegistry();
|
||||
}
|
||||
|
||||
void onCreate() {
|
||||
mLifecycleRegistry.setCurrentState(Lifecycle.State.CREATED);
|
||||
if (Utilities.ATLEAST_U) {
|
||||
mApi34Impl.addOnWindowVisibilityChangeListener();
|
||||
}
|
||||
mView.getViewTreeObserver().addOnWindowFocusChangeListener(
|
||||
mWindowFocusListener);
|
||||
updateState();
|
||||
}
|
||||
|
||||
void onDestroy() {
|
||||
if (Utilities.ATLEAST_U) {
|
||||
mApi34Impl.removeOnWindowVisibilityChangeListener();
|
||||
}
|
||||
mView.getViewTreeObserver().removeOnWindowFocusChangeListener(
|
||||
mWindowFocusListener);
|
||||
mLifecycleRegistry.setCurrentState(Lifecycle.State.DESTROYED);
|
||||
}
|
||||
|
||||
private void updateState() {
|
||||
Lifecycle.State state =
|
||||
mView.getWindowVisibility() != View.VISIBLE ? Lifecycle.State.CREATED
|
||||
: (!mView.hasWindowFocus() ? Lifecycle.State.STARTED
|
||||
: Lifecycle.State.RESUMED);
|
||||
mLifecycleRegistry.setCurrentState(state);
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
|
||||
private class Api34Impl {
|
||||
private final ViewTreeObserver.OnWindowVisibilityChangeListener
|
||||
mWindowVisibilityListener =
|
||||
visibility -> updateState();
|
||||
|
||||
void addOnWindowVisibilityChangeListener() {
|
||||
mView.getViewTreeObserver().addOnWindowVisibilityChangeListener(
|
||||
mWindowVisibilityListener);
|
||||
}
|
||||
|
||||
void removeOnWindowVisibilityChangeListener() {
|
||||
mView.getViewTreeObserver().removeOnWindowVisibilityChangeListener(
|
||||
mWindowVisibilityListener);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -50,7 +50,7 @@ abstract class AbstractDeviceProfileTest {
|
||||
private lateinit var originalWindowManagerProxy: WindowManagerProxy
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
open fun setUp() {
|
||||
val appContext: Context = ApplicationProvider.getApplicationContext()
|
||||
originalWindowManagerProxy = WindowManagerProxy.INSTANCE.get(appContext)
|
||||
originalDisplayController = DisplayController.INSTANCE.get(appContext)
|
||||
@@ -59,7 +59,7 @@ abstract class AbstractDeviceProfileTest {
|
||||
}
|
||||
|
||||
@After
|
||||
fun tearDown() {
|
||||
open fun tearDown() {
|
||||
WindowManagerProxy.INSTANCE.initializeForTesting(originalWindowManagerProxy)
|
||||
DisplayController.INSTANCE.initializeForTesting(originalDisplayController)
|
||||
}
|
||||
|
||||
@@ -58,6 +58,7 @@ class DeviceProfileDumpTest : AbstractDeviceProfileTest() {
|
||||
"\tmInsets.right: 0.0px (0.0dp)\n" +
|
||||
"\tmInsets.bottom: 126.0px (48.0dp)\n" +
|
||||
"\taspectRatio:2.2222223\n" +
|
||||
"\tisResponsiveGrid:false\n" +
|
||||
"\tisScalableGrid:false\n" +
|
||||
"\tinv.numRows: 5\n" +
|
||||
"\tinv.numColumns: 5\n" +
|
||||
@@ -193,6 +194,7 @@ class DeviceProfileDumpTest : AbstractDeviceProfileTest() {
|
||||
"\tmInsets.right: 0.0px (0.0dp)\n" +
|
||||
"\tmInsets.bottom: 63.0px (24.0dp)\n" +
|
||||
"\taspectRatio:2.2222223\n" +
|
||||
"\tisResponsiveGrid:false\n" +
|
||||
"\tisScalableGrid:false\n" +
|
||||
"\tinv.numRows: 5\n" +
|
||||
"\tinv.numColumns: 5\n" +
|
||||
@@ -328,6 +330,7 @@ class DeviceProfileDumpTest : AbstractDeviceProfileTest() {
|
||||
"\tmInsets.right: 126.0px (48.0dp)\n" +
|
||||
"\tmInsets.bottom: 0.0px (0.0dp)\n" +
|
||||
"\taspectRatio:2.2222223\n" +
|
||||
"\tisResponsiveGrid:false\n" +
|
||||
"\tisScalableGrid:false\n" +
|
||||
"\tinv.numRows: 5\n" +
|
||||
"\tinv.numColumns: 5\n" +
|
||||
@@ -463,6 +466,7 @@ class DeviceProfileDumpTest : AbstractDeviceProfileTest() {
|
||||
"\tmInsets.right: 0.0px (0.0dp)\n" +
|
||||
"\tmInsets.bottom: 63.0px (24.0dp)\n" +
|
||||
"\taspectRatio:2.2222223\n" +
|
||||
"\tisResponsiveGrid:false\n" +
|
||||
"\tisScalableGrid:false\n" +
|
||||
"\tinv.numRows: 5\n" +
|
||||
"\tinv.numColumns: 5\n" +
|
||||
@@ -599,6 +603,7 @@ class DeviceProfileDumpTest : AbstractDeviceProfileTest() {
|
||||
"\tmInsets.right: 0.0px (0.0dp)\n" +
|
||||
"\tmInsets.bottom: 0.0px (0.0dp)\n" +
|
||||
"\taspectRatio:1.6\n" +
|
||||
"\tisResponsiveGrid:false\n" +
|
||||
"\tisScalableGrid:true\n" +
|
||||
"\tinv.numRows: 5\n" +
|
||||
"\tinv.numColumns: 6\n" +
|
||||
@@ -735,6 +740,7 @@ class DeviceProfileDumpTest : AbstractDeviceProfileTest() {
|
||||
"\tmInsets.right: 0.0px (0.0dp)\n" +
|
||||
"\tmInsets.bottom: 0.0px (0.0dp)\n" +
|
||||
"\taspectRatio:1.6\n" +
|
||||
"\tisResponsiveGrid:false\n" +
|
||||
"\tisScalableGrid:true\n" +
|
||||
"\tinv.numRows: 5\n" +
|
||||
"\tinv.numColumns: 6\n" +
|
||||
@@ -871,6 +877,7 @@ class DeviceProfileDumpTest : AbstractDeviceProfileTest() {
|
||||
"\tmInsets.right: 0.0px (0.0dp)\n" +
|
||||
"\tmInsets.bottom: 0.0px (0.0dp)\n" +
|
||||
"\taspectRatio:1.6\n" +
|
||||
"\tisResponsiveGrid:false\n" +
|
||||
"\tisScalableGrid:true\n" +
|
||||
"\tinv.numRows: 5\n" +
|
||||
"\tinv.numColumns: 6\n" +
|
||||
@@ -1007,6 +1014,7 @@ class DeviceProfileDumpTest : AbstractDeviceProfileTest() {
|
||||
"\tmInsets.right: 0.0px (0.0dp)\n" +
|
||||
"\tmInsets.bottom: 0.0px (0.0dp)\n" +
|
||||
"\taspectRatio:1.6\n" +
|
||||
"\tisResponsiveGrid:false\n" +
|
||||
"\tisScalableGrid:true\n" +
|
||||
"\tinv.numRows: 5\n" +
|
||||
"\tinv.numColumns: 6\n" +
|
||||
@@ -1148,6 +1156,7 @@ class DeviceProfileDumpTest : AbstractDeviceProfileTest() {
|
||||
"\tmInsets.right: 0.0px (0.0dp)\n" +
|
||||
"\tmInsets.bottom: 0.0px (0.0dp)\n" +
|
||||
"\taspectRatio:1.2\n" +
|
||||
"\tisResponsiveGrid:false\n" +
|
||||
"\tisScalableGrid:false\n" +
|
||||
"\tinv.numRows: 4\n" +
|
||||
"\tinv.numColumns: 4\n" +
|
||||
@@ -1288,6 +1297,7 @@ class DeviceProfileDumpTest : AbstractDeviceProfileTest() {
|
||||
"\tmInsets.right: 0.0px (0.0dp)\n" +
|
||||
"\tmInsets.bottom: 0.0px (0.0dp)\n" +
|
||||
"\taspectRatio:1.2\n" +
|
||||
"\tisResponsiveGrid:false\n" +
|
||||
"\tisScalableGrid:false\n" +
|
||||
"\tinv.numRows: 4\n" +
|
||||
"\tinv.numColumns: 4\n" +
|
||||
@@ -1428,6 +1438,7 @@ class DeviceProfileDumpTest : AbstractDeviceProfileTest() {
|
||||
"\tmInsets.right: 0.0px (0.0dp)\n" +
|
||||
"\tmInsets.bottom: 0.0px (0.0dp)\n" +
|
||||
"\taspectRatio:1.2\n" +
|
||||
"\tisResponsiveGrid:false\n" +
|
||||
"\tisScalableGrid:false\n" +
|
||||
"\tinv.numRows: 4\n" +
|
||||
"\tinv.numColumns: 4\n" +
|
||||
@@ -1564,6 +1575,7 @@ class DeviceProfileDumpTest : AbstractDeviceProfileTest() {
|
||||
"\tmInsets.right: 0.0px (0.0dp)\n" +
|
||||
"\tmInsets.bottom: 0.0px (0.0dp)\n" +
|
||||
"\taspectRatio:1.2\n" +
|
||||
"\tisResponsiveGrid:false\n" +
|
||||
"\tisScalableGrid:false\n" +
|
||||
"\tinv.numRows: 4\n" +
|
||||
"\tinv.numColumns: 4\n" +
|
||||
|
||||
Reference in New Issue
Block a user