Commit 880cb5b3 authored by Sinan Sahin's avatar Sinan Sahin Committed by Commit Bot

[Offline indicator v2] Optimize memory by inflating view when needed

With this CL, we inflate the view right before showing it and destroy it
when it's hidden. Animations are also set to null when they end.

Bug: 1005843
Change-Id: I2fd05939bd81eb7155a48744cfca33a1bc319e9a
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2355005Reviewed-by: default avatarTheresa  <twellington@chromium.org>
Reviewed-by: default avatarMatthew Jones <mdjones@chromium.org>
Commit-Queue: Sinan Sahin <sinansahin@google.com>
Cr-Commit-Position: refs/heads/master@{#801059}
parent c6346a15
...@@ -7,6 +7,7 @@ package org.chromium.chrome.browser.status_indicator; ...@@ -7,6 +7,7 @@ package org.chromium.chrome.browser.status_indicator;
import android.app.Activity; import android.app.Activity;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.view.View; import android.view.View;
import android.view.ViewGroup;
import android.view.ViewStub; import android.view.ViewStub;
import androidx.annotation.ColorInt; import androidx.annotation.ColorInt;
...@@ -42,6 +43,7 @@ public class StatusIndicatorCoordinator { ...@@ -42,6 +43,7 @@ public class StatusIndicatorCoordinator {
} }
private StatusIndicatorMediator mMediator; private StatusIndicatorMediator mMediator;
private PropertyModelChangeProcessor mMCP;
private StatusIndicatorSceneLayer mSceneLayer; private StatusIndicatorSceneLayer mSceneLayer;
private boolean mIsShowing; private boolean mIsShowing;
private Runnable mRemoveOnLayoutChangeListener; private Runnable mRemoveOnLayoutChangeListener;
...@@ -65,42 +67,74 @@ public class StatusIndicatorCoordinator { ...@@ -65,42 +67,74 @@ public class StatusIndicatorCoordinator {
BrowserControlsStateProvider browserControlsStateProvider, BrowserControlsStateProvider browserControlsStateProvider,
Supplier<Integer> statusBarColorWithoutStatusIndicatorSupplier, Supplier<Integer> statusBarColorWithoutStatusIndicatorSupplier,
Supplier<Boolean> canAnimateNativeBrowserControls, Callback<Runnable> requestRender) { Supplier<Boolean> canAnimateNativeBrowserControls, Callback<Runnable> requestRender) {
// TODO(crbug.com/1005843): Create this view lazily if/when we need it. This is a task for mSceneLayer = new StatusIndicatorSceneLayer(browserControlsStateProvider);
// when we have the public API figured out. First, we should avoid inflating the view here
// in case it's never used. // This will create the view before showing it.
final ViewStub stub = activity.findViewById(R.id.status_indicator_stub); Runnable inflateView = () -> {
ViewStub stub = activity.findViewById(R.id.status_indicator_stub);
ViewResourceFrameLayout root = (ViewResourceFrameLayout) stub.inflate(); ViewResourceFrameLayout root = (ViewResourceFrameLayout) stub.inflate();
mSceneLayer = new StatusIndicatorSceneLayer(root, () -> browserControlsStateProvider); resourceManager.getDynamicResourceLoader().registerResource(
root.getId(), root.getResourceAdapter());
mSceneLayer.setResourceId(root.getId());
PropertyModel model = PropertyModel model =
new PropertyModel.Builder(StatusIndicatorProperties.ALL_KEYS) new PropertyModel.Builder(StatusIndicatorProperties.ALL_KEYS)
.with(StatusIndicatorProperties.ANDROID_VIEW_VISIBILITY, View.GONE) .with(StatusIndicatorProperties.ANDROID_VIEW_VISIBILITY, View.GONE)
.with(StatusIndicatorProperties.COMPOSITED_VIEW_VISIBLE, false) .with(StatusIndicatorProperties.COMPOSITED_VIEW_VISIBLE, false)
.build(); .build();
PropertyModelChangeProcessor.create(model, mMCP = PropertyModelChangeProcessor.create(model,
new StatusIndicatorViewBinder.ViewHolder(root, mSceneLayer), new StatusIndicatorViewBinder.ViewHolder(root, mSceneLayer),
StatusIndicatorViewBinder::bind); StatusIndicatorViewBinder::bind);
mMediator.setModel(model);
root.addOnLayoutChangeListener(mMediator);
mRemoveOnLayoutChangeListener = () -> root.removeOnLayoutChangeListener(mMediator);
};
// This will run to destroy the view once it's hidden.
Runnable destroyView = () -> {
mRemoveOnLayoutChangeListener.run();
mRemoveOnLayoutChangeListener = null;
ViewResourceFrameLayout root = activity.findViewById(R.id.status_indicator);
mSceneLayer.setResourceId(0);
resourceManager.getDynamicResourceLoader().unregisterResource(root.getId());
mMediator.setModel(null);
mMCP.destroy();
mMCP = null;
// Remove the view and add a ViewStub in its place. This is basically returning the
// view tree to its initial condition and will make it possible to inflate the view
// easily the next time it's needed, i.e. next #show() call.
final ViewGroup parent = ((ViewGroup) root.getParent());
final int index = parent.indexOfChild(root);
parent.removeViewAt(index);
final ViewStub stub = new ViewStub(activity);
stub.setLayoutParams(new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
stub.setId(R.id.status_indicator_stub);
stub.setInflatedId(R.id.status_indicator);
stub.setLayoutResource(R.layout.status_indicator_container);
parent.addView(stub, index);
};
Callback<Runnable> invalidateCompositorView = callback -> { Callback<Runnable> invalidateCompositorView = callback -> {
ViewResourceFrameLayout root = activity.findViewById(R.id.status_indicator);
root.getResourceAdapter().invalidate(null); root.getResourceAdapter().invalidate(null);
requestRender.onResult(callback); requestRender.onResult(callback);
}; };
Runnable requestLayout = () -> root.requestLayout(); Runnable requestLayout = () -> {
ViewResourceFrameLayout root = activity.findViewById(R.id.status_indicator);
mMediator = new StatusIndicatorMediator(model, browserControlsStateProvider, root.requestLayout();
statusBarColorWithoutStatusIndicatorSupplier, canAnimateNativeBrowserControls, };
invalidateCompositorView, requestLayout); mMediator = new StatusIndicatorMediator(browserControlsStateProvider,
resourceManager.getDynamicResourceLoader().registerResource( statusBarColorWithoutStatusIndicatorSupplier, inflateView, destroyView,
root.getId(), root.getResourceAdapter()); canAnimateNativeBrowserControls, invalidateCompositorView, requestLayout);
root.addOnLayoutChangeListener(mMediator);
mRemoveOnLayoutChangeListener = () -> root.removeOnLayoutChangeListener(mMediator);
} }
public void destroy() { public void destroy() {
if (mRemoveOnLayoutChangeListener != null) {
mRemoveOnLayoutChangeListener.run(); mRemoveOnLayoutChangeListener.run();
}
mMediator.destroy(); mMediator.destroy();
} }
// TODO(sinansahin): Destroy the view when not needed.
/** /**
* Show the status indicator with the initial properties with animations. * Show the status indicator with the initial properties with animations.
* *
......
...@@ -37,6 +37,8 @@ class StatusIndicatorMediator ...@@ -37,6 +37,8 @@ class StatusIndicatorMediator
new HashSet<>(); new HashSet<>();
private Supplier<Integer> mStatusBarWithoutIndicatorColorSupplier; private Supplier<Integer> mStatusBarWithoutIndicatorColorSupplier;
private Runnable mOnShowAnimationEnd; private Runnable mOnShowAnimationEnd;
private Runnable mInflateView;
private Runnable mDestroyView;
private Supplier<Boolean> mCanAnimateNativeBrowserControls; private Supplier<Boolean> mCanAnimateNativeBrowserControls;
private Callback<Runnable> mInvalidateCompositorView; private Callback<Runnable> mInvalidateCompositorView;
private Runnable mRequestLayout; private Runnable mRequestLayout;
...@@ -52,12 +54,13 @@ class StatusIndicatorMediator ...@@ -52,12 +54,13 @@ class StatusIndicatorMediator
/** /**
* Constructs the status indicator mediator. * Constructs the status indicator mediator.
* @param model The {@link PropertyModel} for the status indicator.
* @param browserControlsStateProvider The {@link BrowserControlsStateProvider} to listen to * @param browserControlsStateProvider The {@link BrowserControlsStateProvider} to listen to
* for the changes in controls offsets. * for the changes in controls offsets.
* @param statusBarWithoutIndicatorColorSupplier A supplier that will get the status bar color * @param statusBarWithoutIndicatorColorSupplier A supplier that will get the status bar color
* without taking the status indicator into * without taking the status indicator into
* account. * account.
* @param inflateView A {@link Runnable} to inflate the status indicator view before showing.
* @param destroyView A {@link Runnable} to destroy the status indicator view once hidden.
* @param canAnimateNativeBrowserControls Will supply a boolean denoting whether the native * @param canAnimateNativeBrowserControls Will supply a boolean denoting whether the native
* browser controls can be animated. This will be false * browser controls can be animated. This will be false
* where we can't have a reliable cc::BCOM instance, e.g. * where we can't have a reliable cc::BCOM instance, e.g.
...@@ -65,14 +68,14 @@ class StatusIndicatorMediator ...@@ -65,14 +68,14 @@ class StatusIndicatorMediator
* @param invalidateCompositorView Callback to invalidate the compositor texture. * @param invalidateCompositorView Callback to invalidate the compositor texture.
* @param requestLayout Runnable to request layout for the view. * @param requestLayout Runnable to request layout for the view.
*/ */
StatusIndicatorMediator(PropertyModel model, StatusIndicatorMediator(BrowserControlsStateProvider browserControlsStateProvider,
BrowserControlsStateProvider browserControlsStateProvider, Supplier<Integer> statusBarWithoutIndicatorColorSupplier, Runnable inflateView,
Supplier<Integer> statusBarWithoutIndicatorColorSupplier, Runnable destroyView, Supplier<Boolean> canAnimateNativeBrowserControls,
Supplier<Boolean> canAnimateNativeBrowserControls,
Callback<Runnable> invalidateCompositorView, Runnable requestLayout) { Callback<Runnable> invalidateCompositorView, Runnable requestLayout) {
mModel = model;
mBrowserControlsStateProvider = browserControlsStateProvider; mBrowserControlsStateProvider = browserControlsStateProvider;
mStatusBarWithoutIndicatorColorSupplier = statusBarWithoutIndicatorColorSupplier; mStatusBarWithoutIndicatorColorSupplier = statusBarWithoutIndicatorColorSupplier;
mInflateView = inflateView;
mDestroyView = destroyView;
mCanAnimateNativeBrowserControls = canAnimateNativeBrowserControls; mCanAnimateNativeBrowserControls = canAnimateNativeBrowserControls;
mInvalidateCompositorView = invalidateCompositorView; mInvalidateCompositorView = invalidateCompositorView;
mRequestLayout = requestLayout; mRequestLayout = requestLayout;
...@@ -110,6 +113,10 @@ class StatusIndicatorMediator ...@@ -110,6 +113,10 @@ class StatusIndicatorMediator
mObservers.remove(observer); mObservers.remove(observer);
} }
void setModel(PropertyModel model) {
mModel = model;
}
// Animations // Animations
// TODO(sinansahin): We might want to end the running animations if we need to hide before we're // TODO(sinansahin): We might want to end the running animations if we need to hide before we're
...@@ -137,6 +144,8 @@ class StatusIndicatorMediator ...@@ -137,6 +144,8 @@ class StatusIndicatorMediator
*/ */
void animateShow(@NonNull String statusText, Drawable statusIcon, @ColorInt int backgroundColor, void animateShow(@NonNull String statusText, Drawable statusIcon, @ColorInt int backgroundColor,
@ColorInt int textColor, @ColorInt int iconTint) { @ColorInt int textColor, @ColorInt int iconTint) {
mInflateView.run();
Runnable initializeProperties = () -> { Runnable initializeProperties = () -> {
mModel.set(StatusIndicatorProperties.STATUS_TEXT, statusText); mModel.set(StatusIndicatorProperties.STATUS_TEXT, statusText);
mModel.set(StatusIndicatorProperties.STATUS_ICON, statusIcon); mModel.set(StatusIndicatorProperties.STATUS_ICON, statusIcon);
...@@ -169,13 +178,13 @@ class StatusIndicatorMediator ...@@ -169,13 +178,13 @@ class StatusIndicatorMediator
@Override @Override
public void onEnd(Animator animation) { public void onEnd(Animator animation) {
initializeProperties.run(); initializeProperties.run();
mStatusBarAnimation = null;
} }
}); });
mStatusBarAnimation.start(); mStatusBarAnimation.start();
} }
private void animateTextFadeIn() { private void animateTextFadeIn() {
if (mTextFadeInAnimation == null) {
mTextFadeInAnimation = ValueAnimator.ofFloat(0.f, 1.f); mTextFadeInAnimation = ValueAnimator.ofFloat(0.f, 1.f);
mTextFadeInAnimation.setInterpolator(Interpolators.FAST_OUT_SLOW_IN_INTERPOLATOR); mTextFadeInAnimation.setInterpolator(Interpolators.FAST_OUT_SLOW_IN_INTERPOLATOR);
mTextFadeInAnimation.setDuration(FADE_TEXT_DURATION_MS); mTextFadeInAnimation.setDuration(FADE_TEXT_DURATION_MS);
...@@ -188,8 +197,12 @@ class StatusIndicatorMediator ...@@ -188,8 +197,12 @@ class StatusIndicatorMediator
public void onStart(Animator animation) { public void onStart(Animator animation) {
mRequestLayout.run(); mRequestLayout.run();
} }
});
@Override
public void onEnd(Animator animator) {
mTextFadeInAnimation = null;
} }
});
mTextFadeInAnimation.start(); mTextFadeInAnimation.start();
} }
...@@ -274,6 +287,7 @@ class StatusIndicatorMediator ...@@ -274,6 +287,7 @@ class StatusIndicatorMediator
@Override @Override
public void onEnd(Animator animation) { public void onEnd(Animator animation) {
animationCompleteCallback.run(); animationCompleteCallback.run();
mUpdateAnimatorSet = null;
} }
}); });
mUpdateAnimatorSet.start(); mUpdateAnimatorSet.start();
...@@ -328,6 +342,7 @@ class StatusIndicatorMediator ...@@ -328,6 +342,7 @@ class StatusIndicatorMediator
} else { } else {
updateVisibility(true); updateVisibility(true);
} }
mHideAnimatorSet = null;
} }
}); });
mHideAnimatorSet.start(); mHideAnimatorSet.start();
...@@ -394,6 +409,7 @@ class StatusIndicatorMediator ...@@ -394,6 +409,7 @@ class StatusIndicatorMediator
mBrowserControlsStateProvider.removeObserver(this); mBrowserControlsStateProvider.removeObserver(this);
mIsHiding = false; mIsHiding = false;
mJavaLayoutHeight = 0; mJavaLayoutHeight = 0;
mDestroyView.run();
} }
} }
......
...@@ -8,7 +8,6 @@ import android.graphics.RectF; ...@@ -8,7 +8,6 @@ import android.graphics.RectF;
import org.chromium.base.annotations.JNINamespace; import org.chromium.base.annotations.JNINamespace;
import org.chromium.base.annotations.NativeMethods; import org.chromium.base.annotations.NativeMethods;
import org.chromium.base.supplier.Supplier;
import org.chromium.chrome.browser.browser_controls.BrowserControlsStateProvider; import org.chromium.chrome.browser.browser_controls.BrowserControlsStateProvider;
import org.chromium.chrome.browser.compositor.LayerTitleCache; import org.chromium.chrome.browser.compositor.LayerTitleCache;
import org.chromium.chrome.browser.compositor.layouts.components.VirtualView; import org.chromium.chrome.browser.compositor.layouts.components.VirtualView;
...@@ -16,7 +15,6 @@ import org.chromium.chrome.browser.compositor.layouts.eventfilter.EventFilter; ...@@ -16,7 +15,6 @@ import org.chromium.chrome.browser.compositor.layouts.eventfilter.EventFilter;
import org.chromium.chrome.browser.compositor.overlays.SceneOverlay; import org.chromium.chrome.browser.compositor.overlays.SceneOverlay;
import org.chromium.chrome.browser.compositor.scene_layer.SceneLayer; import org.chromium.chrome.browser.compositor.scene_layer.SceneLayer;
import org.chromium.chrome.browser.compositor.scene_layer.SceneOverlayLayer; import org.chromium.chrome.browser.compositor.scene_layer.SceneOverlayLayer;
import org.chromium.components.browser_ui.widget.ViewResourceFrameLayout;
import org.chromium.ui.resources.ResourceManager; import org.chromium.ui.resources.ResourceManager;
import java.util.List; import java.util.List;
...@@ -33,23 +31,18 @@ class StatusIndicatorSceneLayer extends SceneOverlayLayer implements SceneOverla ...@@ -33,23 +31,18 @@ class StatusIndicatorSceneLayer extends SceneOverlayLayer implements SceneOverla
/** The resource ID used to reference the view bitmap in native. */ /** The resource ID used to reference the view bitmap in native. */
private int mResourceId; private int mResourceId;
/** The {@link ViewResourceFrameLayout} that this scene layer represents. */ /** The {@link BrowserControlsStateProvider} to access browser controls offsets. */
private ViewResourceFrameLayout mStatusIndicator; private BrowserControlsStateProvider mBrowserControlsStateProvider;
/** A {@link Supplier} for accessing the {@link BrowserControlsStateProvider}. */
private Supplier<BrowserControlsStateProvider> mBrowserControlsStateProviderSupplier;
private boolean mIsVisible; private boolean mIsVisible;
/** /**
* Build a composited status view layer. * Build a composited status view layer.
* @param statusIndicator The view used to generate the composited version. * @param browserControlsStateProvider {@link BrowserControlsStateProvider} to access browser
* controls offsets.
*/ */
public StatusIndicatorSceneLayer(ViewResourceFrameLayout statusIndicator, public StatusIndicatorSceneLayer(BrowserControlsStateProvider browserControlsStateProvider) {
Supplier<BrowserControlsStateProvider> browserControlsStateProviderSupplier) { mBrowserControlsStateProvider = browserControlsStateProvider;
mStatusIndicator = statusIndicator;
mResourceId = mStatusIndicator.getId();
mBrowserControlsStateProviderSupplier = browserControlsStateProviderSupplier;
} }
/** /**
...@@ -60,6 +53,14 @@ class StatusIndicatorSceneLayer extends SceneOverlayLayer implements SceneOverla ...@@ -60,6 +53,14 @@ class StatusIndicatorSceneLayer extends SceneOverlayLayer implements SceneOverla
mIsVisible = visible; mIsVisible = visible;
} }
/**
* Set the resource ID.
* @param id Resource view ID.
*/
public void setResourceId(int id) {
mResourceId = id;
}
@Override @Override
protected void initializeNative() { protected void initializeNative() {
if (mNativePtr == 0) { if (mNativePtr == 0) {
...@@ -77,11 +78,7 @@ class StatusIndicatorSceneLayer extends SceneOverlayLayer implements SceneOverla ...@@ -77,11 +78,7 @@ class StatusIndicatorSceneLayer extends SceneOverlayLayer implements SceneOverla
@Override @Override
public SceneOverlayLayer getUpdatedSceneOverlayTree(RectF viewport, RectF visibleViewport, public SceneOverlayLayer getUpdatedSceneOverlayTree(RectF viewport, RectF visibleViewport,
LayerTitleCache layerTitleCache, ResourceManager resourceManager, float yOffset) { LayerTitleCache layerTitleCache, ResourceManager resourceManager, float yOffset) {
final BrowserControlsStateProvider browserControlsStateProvider = final int offset = mBrowserControlsStateProvider.getTopControlsMinHeightOffset();
mBrowserControlsStateProviderSupplier.get();
final int offset = browserControlsStateProvider != null
? browserControlsStateProvider.getTopControlsMinHeightOffset()
: 0;
StatusIndicatorSceneLayerJni.get().updateStatusIndicatorLayer( StatusIndicatorSceneLayerJni.get().updateStatusIndicatorLayer(
mNativePtr, StatusIndicatorSceneLayer.this, resourceManager, mResourceId, offset); mNativePtr, StatusIndicatorSceneLayer.this, resourceManager, mResourceId, offset);
return this; return this;
......
...@@ -64,7 +64,7 @@ public class StatusIndicatorViewBinderTest extends DummyUiActivityTestCase { ...@@ -64,7 +64,7 @@ public class StatusIndicatorViewBinderTest extends DummyUiActivityTestCase {
mContainer = getActivity().findViewById(R.id.status_indicator); mContainer = getActivity().findViewById(R.id.status_indicator);
mStatusTextView = mContainer.findViewById(R.id.status_text); mStatusTextView = mContainer.findViewById(R.id.status_text);
mSceneLayer = new MockStatusIndicatorSceneLayer(mContainer); mSceneLayer = new MockStatusIndicatorSceneLayer();
mModel = new PropertyModel.Builder(StatusIndicatorProperties.ALL_KEYS) mModel = new PropertyModel.Builder(StatusIndicatorProperties.ALL_KEYS)
.with(StatusIndicatorProperties.STATUS_TEXT, "") .with(StatusIndicatorProperties.STATUS_TEXT, "")
.with(StatusIndicatorProperties.STATUS_ICON, null) .with(StatusIndicatorProperties.STATUS_ICON, null)
...@@ -197,8 +197,8 @@ public class StatusIndicatorViewBinderTest extends DummyUiActivityTestCase { ...@@ -197,8 +197,8 @@ public class StatusIndicatorViewBinderTest extends DummyUiActivityTestCase {
/** Mock {@link StatusIndicatorSceneLayer} class to avoid native initialization. */ /** Mock {@link StatusIndicatorSceneLayer} class to avoid native initialization. */
private class MockStatusIndicatorSceneLayer extends StatusIndicatorSceneLayer { private class MockStatusIndicatorSceneLayer extends StatusIndicatorSceneLayer {
MockStatusIndicatorSceneLayer(ViewResourceFrameLayout statusIndicator) { MockStatusIndicatorSceneLayer() {
super(statusIndicator, null); super(null);
} }
@Override @Override
......
...@@ -46,6 +46,10 @@ public class StatusIndicatorMediatorTest { ...@@ -46,6 +46,10 @@ public class StatusIndicatorMediatorTest {
@Mock @Mock
StatusIndicatorCoordinator.StatusIndicatorObserver mObserver; StatusIndicatorCoordinator.StatusIndicatorObserver mObserver;
@Mock @Mock
Runnable mInflateView;
@Mock
Runnable mDestroyView;
@Mock
Supplier<Boolean> mCanAnimateNativeBrowserControls; Supplier<Boolean> mCanAnimateNativeBrowserControls;
@Mock @Mock
Callback<Runnable> mInvalidateCompositorView; Callback<Runnable> mInvalidateCompositorView;
...@@ -58,6 +62,8 @@ public class StatusIndicatorMediatorTest { ...@@ -58,6 +62,8 @@ public class StatusIndicatorMediatorTest {
@Before @Before
public void setUp() { public void setUp() {
MockitoAnnotations.initMocks(this); MockitoAnnotations.initMocks(this);
doNothing().when(mInflateView).run();
doNothing().when(mDestroyView).run();
when(mCanAnimateNativeBrowserControls.get()).thenReturn(true); when(mCanAnimateNativeBrowserControls.get()).thenReturn(true);
doNothing().when(mInvalidateCompositorView).onResult(any(Runnable.class)); doNothing().when(mInvalidateCompositorView).onResult(any(Runnable.class));
doNothing().when(mRequestLayout).run(); doNothing().when(mRequestLayout).run();
...@@ -65,9 +71,10 @@ public class StatusIndicatorMediatorTest { ...@@ -65,9 +71,10 @@ public class StatusIndicatorMediatorTest {
.with(StatusIndicatorProperties.ANDROID_VIEW_VISIBILITY, View.GONE) .with(StatusIndicatorProperties.ANDROID_VIEW_VISIBILITY, View.GONE)
.with(StatusIndicatorProperties.COMPOSITED_VIEW_VISIBLE, false) .with(StatusIndicatorProperties.COMPOSITED_VIEW_VISIBLE, false)
.build(); .build();
mMediator = new StatusIndicatorMediator(mModel, mBrowserControlsStateProvider, mMediator = new StatusIndicatorMediator(mBrowserControlsStateProvider, () -> Color.WHITE,
() -> Color.WHITE, mCanAnimateNativeBrowserControls, mInvalidateCompositorView, mInflateView, mDestroyView, mCanAnimateNativeBrowserControls,
mRequestLayout); mInvalidateCompositorView, mRequestLayout);
mMediator.setModel(mModel);
} }
@Test @Test
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment