Commit 61c7526b authored by jdduke's avatar jdduke Committed by Commit bot

Reland "[Android] Preserve the front buffer when the activity is paused"

This change was reverted in r322170 due to WebView breakage. The
ApplicationStatus dependency has been made optional, allowing
WebView to opt-out of its use. It was speculatively reverted
again in r327092, but that turned out to be a false alarm.

Original description: ----------------------------

Currently, when an activity is stopped, we explicitly hide the
foreground Tab. This is problematic, as current hiding semantics
might clear the visual front buffer before the window is hidden.
This in turn causes an unpleasant flickering during activity
transitions, e.g., when backgrounding Chrome or locking the screen.

Wire Activity onPause/onResume notifications to WindowAndroidObservers,
allowing the foreground tab to preserve its front buffer while hiding
its web content. If the tab is explicitly hidden, or the root window
is lost, the front buffer will be cleared as usual.

BUG=481450,434401

Review URL: https://codereview.chromium.org/1001573003

Cr-Commit-Position: refs/heads/master@{#329283}
parent 7fd7d99a
...@@ -871,9 +871,11 @@ public class AwContents implements SmartClipProvider, ...@@ -871,9 +871,11 @@ public class AwContents implements SmartClipProvider,
WebContents webContents = nativeGetWebContents(mNativeAwContents); WebContents webContents = nativeGetWebContents(mNativeAwContents);
// WebView does not currently initialize ApplicationStatus, crbug.com/470582.
final boolean listenToActivityState = false;
Activity activity = ContentViewCore.activityFromContext(mContext); Activity activity = ContentViewCore.activityFromContext(mContext);
mWindowAndroid = activity != null mWindowAndroid = activity != null
? new ActivityWindowAndroid(activity) ? new ActivityWindowAndroid(activity, listenToActivityState)
: new WindowAndroid(mContext.getApplicationContext()); : new WindowAndroid(mContext.getApplicationContext());
mContentViewCore = createAndInitializeContentViewCore( mContentViewCore = createAndInitializeContentViewCore(
mContainerView, mContext, mInternalAccessAdapter, webContents, mContainerView, mContext, mInternalAccessAdapter, webContents,
......
...@@ -1211,7 +1211,13 @@ public class Tab implements ViewGroup.OnHierarchyChangeListener, ...@@ -1211,7 +1211,13 @@ public class Tab implements ViewGroup.OnHierarchyChangeListener,
* on both cold and warm starts. * on both cold and warm starts.
*/ */
public void onActivityStart() { public void onActivityStart() {
show(TabSelectionType.FROM_USER); if (isHidden()) {
show(TabSelectionType.FROM_USER);
} else {
// The visible Tab's renderer process may have died after the activity was paused.
// Ensure that it's restored appropriately.
loadIfNeeded();
}
// When resuming the activity, force an update to the fullscreen state to ensure a // When resuming the activity, force an update to the fullscreen state to ensure a
// subactivity did not change the fullscreen configuration of this ChromeTab's renderer in // subactivity did not change the fullscreen configuration of this ChromeTab's renderer in
...@@ -1223,7 +1229,7 @@ public class Tab implements ViewGroup.OnHierarchyChangeListener, ...@@ -1223,7 +1229,7 @@ public class Tab implements ViewGroup.OnHierarchyChangeListener,
* Called on the foreground tab when the Activity is stopped. * Called on the foreground tab when the Activity is stopped.
*/ */
public void onActivityStop() { public void onActivityStop() {
hide(); // TODO(jdduke): Remove this method when all downstream callers have been removed.
} }
/** /**
......
...@@ -6,7 +6,9 @@ package org.chromium.chrome.browser; ...@@ -6,7 +6,9 @@ package org.chromium.chrome.browser;
import android.test.suitebuilder.annotation.SmallTest; import android.test.suitebuilder.annotation.SmallTest;
import org.chromium.base.ThreadUtils;
import org.chromium.base.test.util.Feature; import org.chromium.base.test.util.Feature;
import org.chromium.chrome.browser.tabmodel.TabModel.TabSelectionType;
import org.chromium.chrome.shell.ChromeShellTestBase; import org.chromium.chrome.shell.ChromeShellTestBase;
import org.chromium.content.browser.test.util.CallbackHelper; import org.chromium.content.browser.test.util.CallbackHelper;
...@@ -48,4 +50,51 @@ public class TabTest extends ChromeShellTestBase { ...@@ -48,4 +50,51 @@ public class TabTest extends ChromeShellTestBase {
mOnTitleUpdatedHelper.waitForCallback(currentCallCount); mOnTitleUpdatedHelper.waitForCallback(currentCallCount);
assertEquals("title does not update", newTitle, mTab.getTitle()); assertEquals("title does not update", newTitle, mTab.getTitle());
} }
@SmallTest
@Feature({"Tab"})
public void testTabRestoredIfKilledWhileActivityStopped() {
launchChromeShellWithBlankPage();
final Tab tab = getActivity().getActiveTab();
// Ensure the tab is showing before stopping the activity.
ThreadUtils.runOnUiThreadBlocking(new Runnable() {
@Override
public void run() {
tab.show(TabSelectionType.FROM_NEW);
}
});
assertFalse(tab.needsReload());
assertFalse(tab.isHidden());
assertFalse(tab.isShowingSadTab());
// Stop the activity and simulate a killed renderer.
ThreadUtils.runOnUiThreadBlocking(new Runnable() {
@Override
public void run() {
getInstrumentation().callActivityOnPause(getActivity());
getInstrumentation().callActivityOnStop(getActivity());
tab.simulateRendererKilledForTesting(false);
}
});
assertTrue(tab.needsReload());
assertFalse(tab.isHidden());
assertFalse(tab.isShowingSadTab());
// Resume the activity.
ThreadUtils.runOnUiThreadBlocking(new Runnable() {
@Override
public void run() {
getInstrumentation().callActivityOnStart(getActivity());
getInstrumentation().callActivityOnResume(getActivity());
}
});
// The tab should be restored and visible.
assertFalse(tab.isHidden());
assertFalse(tab.needsReload());
assertFalse(tab.isShowingSadTab());
}
} }
...@@ -83,7 +83,8 @@ public class ChromeShellActivity extends AppCompatActivity implements AppMenuPro ...@@ -83,7 +83,8 @@ public class ChromeShellActivity extends AppCompatActivity implements AppMenuPro
new ActivityWindowAndroidFactory() { new ActivityWindowAndroidFactory() {
@Override @Override
public ActivityWindowAndroid getActivityWindowAndroid(Activity activity) { public ActivityWindowAndroid getActivityWindowAndroid(Activity activity) {
return new ActivityWindowAndroid(activity); final boolean listenToActivityState = true;
return new ActivityWindowAndroid(activity, listenToActivityState);
} }
}; };
...@@ -278,9 +279,6 @@ public class ChromeShellActivity extends AppCompatActivity implements AppMenuPro ...@@ -278,9 +279,6 @@ public class ChromeShellActivity extends AppCompatActivity implements AppMenuPro
super.onStop(); super.onStop();
if (mToolbar != null) mToolbar.hideSuggestions(); if (mToolbar != null) mToolbar.hideSuggestions();
Tab activeTab = getActiveTab();
if (activeTab != null) activeTab.onActivityStop();
} }
@Override @Override
......
...@@ -474,6 +474,7 @@ void CompositorImpl::SetVisible(bool visible) { ...@@ -474,6 +474,7 @@ void CompositorImpl::SetVisible(bool visible) {
CreateLayerTreeHost(); CreateLayerTreeHost();
ui_resource_provider_.SetLayerTreeHost(host_.get()); ui_resource_provider_.SetLayerTreeHost(host_.get());
} }
root_window_->OnVisibilityChanged(visible);
} }
void CompositorImpl::setDeviceScaleFactor(float factor) { void CompositorImpl::setDeviceScaleFactor(float factor) {
......
...@@ -10,11 +10,13 @@ namespace content { ...@@ -10,11 +10,13 @@ namespace content {
DelegatedFrameEvictor::DelegatedFrameEvictor( DelegatedFrameEvictor::DelegatedFrameEvictor(
DelegatedFrameEvictorClient* client) DelegatedFrameEvictorClient* client)
: client_(client), has_frame_(false) {} : client_(client), has_frame_(false), visible_(false) {
}
DelegatedFrameEvictor::~DelegatedFrameEvictor() { DiscardedFrame(); } DelegatedFrameEvictor::~DelegatedFrameEvictor() { DiscardedFrame(); }
void DelegatedFrameEvictor::SwappedFrame(bool visible) { void DelegatedFrameEvictor::SwappedFrame(bool visible) {
visible_ = visible;
has_frame_ = true; has_frame_ = true;
RendererFrameManager::GetInstance()->AddFrame(this, visible); RendererFrameManager::GetInstance()->AddFrame(this, visible);
} }
...@@ -25,11 +27,14 @@ void DelegatedFrameEvictor::DiscardedFrame() { ...@@ -25,11 +27,14 @@ void DelegatedFrameEvictor::DiscardedFrame() {
} }
void DelegatedFrameEvictor::SetVisible(bool visible) { void DelegatedFrameEvictor::SetVisible(bool visible) {
if (visible_ == visible)
return;
visible_ = visible;
if (has_frame_) { if (has_frame_) {
if (visible) { if (visible) {
RendererFrameManager::GetInstance()->LockFrame(this); LockFrame();
} else { } else {
RendererFrameManager::GetInstance()->UnlockFrame(this); UnlockFrame();
} }
} }
} }
......
...@@ -35,6 +35,7 @@ class CONTENT_EXPORT DelegatedFrameEvictor : public RendererFrameManagerClient { ...@@ -35,6 +35,7 @@ class CONTENT_EXPORT DelegatedFrameEvictor : public RendererFrameManagerClient {
DelegatedFrameEvictorClient* client_; DelegatedFrameEvictorClient* client_;
bool has_frame_; bool has_frame_;
bool visible_;
DISALLOW_COPY_AND_ASSIGN(DelegatedFrameEvictor); DISALLOW_COPY_AND_ASSIGN(DelegatedFrameEvictor);
}; };
......
...@@ -549,23 +549,7 @@ void RenderWidgetHostViewAndroid::Show() { ...@@ -549,23 +549,7 @@ void RenderWidgetHostViewAndroid::Show() {
return; return;
is_showing_ = true; is_showing_ = true;
if (layer_.get()) ShowInternal();
layer_->SetHideLayerAndSubtree(false);
if (overscroll_controller_)
overscroll_controller_->Enable();
frame_evictor_->SetVisible(true);
if (!host_ || !host_->is_hidden())
return;
host_->WasShown(ui::LatencyInfo());
if (content_view_core_) {
StartObservingRootWindow();
RequestVSyncUpdate(BEGIN_FRAME);
}
} }
void RenderWidgetHostViewAndroid::Hide() { void RenderWidgetHostViewAndroid::Hide() {
...@@ -573,24 +557,10 @@ void RenderWidgetHostViewAndroid::Hide() { ...@@ -573,24 +557,10 @@ void RenderWidgetHostViewAndroid::Hide() {
return; return;
is_showing_ = false; is_showing_ = false;
if (layer_.get() && locks_on_frame_count_ == 0)
layer_->SetHideLayerAndSubtree(true);
if (overscroll_controller_)
overscroll_controller_->Disable();
frame_evictor_->SetVisible(false);
RunAckCallbacks(cc::SurfaceDrawStatus::DRAW_SKIPPED); bool hide_frontbuffer = true;
bool stop_observing_root_window = true;
if (!host_ || host_->is_hidden()) HideInternal(hide_frontbuffer, stop_observing_root_window);
return;
// Inform the renderer that we are being hidden so it can reduce its resource
// utilization.
host_->WasHidden();
StopObservingRootWindow();
} }
bool RenderWidgetHostViewAndroid::IsShowing() { bool RenderWidgetHostViewAndroid::IsShowing() {
...@@ -1407,6 +1377,53 @@ void RenderWidgetHostViewAndroid::AcceleratedSurfaceInitialized(int route_id) { ...@@ -1407,6 +1377,53 @@ void RenderWidgetHostViewAndroid::AcceleratedSurfaceInitialized(int route_id) {
accelerated_surface_route_id_ = route_id; accelerated_surface_route_id_ = route_id;
} }
void RenderWidgetHostViewAndroid::ShowInternal() {
DCHECK(is_showing_);
if (!host_ || !host_->is_hidden())
return;
if (layer_.get())
layer_->SetHideLayerAndSubtree(false);
frame_evictor_->SetVisible(true);
if (overscroll_controller_)
overscroll_controller_->Enable();
host_->WasShown(ui::LatencyInfo());
if (content_view_core_) {
StartObservingRootWindow();
RequestVSyncUpdate(BEGIN_FRAME);
}
}
void RenderWidgetHostViewAndroid::HideInternal(
bool hide_frontbuffer,
bool stop_observing_root_window) {
if (hide_frontbuffer) {
if (layer_.get() && locks_on_frame_count_ == 0)
layer_->SetHideLayerAndSubtree(true);
frame_evictor_->SetVisible(false);
}
if (stop_observing_root_window)
StopObservingRootWindow();
if (!host_ || host_->is_hidden())
return;
if (overscroll_controller_)
overscroll_controller_->Disable();
RunAckCallbacks(cc::SurfaceDrawStatus::DRAW_SKIPPED);
// Inform the renderer that we are being hidden so it can reduce its resource
// utilization.
host_->WasHidden();
}
void RenderWidgetHostViewAndroid::AttachLayers() { void RenderWidgetHostViewAndroid::AttachLayers() {
if (!content_view_core_) if (!content_view_core_)
return; return;
...@@ -1434,6 +1451,12 @@ void RenderWidgetHostViewAndroid::RemoveLayers() { ...@@ -1434,6 +1451,12 @@ void RenderWidgetHostViewAndroid::RemoveLayers() {
void RenderWidgetHostViewAndroid::RequestVSyncUpdate(uint32 requests) { void RenderWidgetHostViewAndroid::RequestVSyncUpdate(uint32 requests) {
bool should_request_vsync = !outstanding_vsync_requests_ && requests; bool should_request_vsync = !outstanding_vsync_requests_ && requests;
outstanding_vsync_requests_ |= requests; outstanding_vsync_requests_ |= requests;
// If the host has been hidden, defer vsync requests until it is shown
// again via |Show()|.
if (!host_ || host_->is_hidden())
return;
// Note that if we're not currently observing the root window, outstanding // Note that if we're not currently observing the root window, outstanding
// vsync requests will be pushed if/when we resume observing in // vsync requests will be pushed if/when we resume observing in
// |StartObservingRootWindow()|. // |StartObservingRootWindow()|.
...@@ -1443,6 +1466,7 @@ void RenderWidgetHostViewAndroid::RequestVSyncUpdate(uint32 requests) { ...@@ -1443,6 +1466,7 @@ void RenderWidgetHostViewAndroid::RequestVSyncUpdate(uint32 requests) {
void RenderWidgetHostViewAndroid::StartObservingRootWindow() { void RenderWidgetHostViewAndroid::StartObservingRootWindow() {
DCHECK(content_view_core_window_android_); DCHECK(content_view_core_window_android_);
DCHECK(is_showing_);
if (observing_root_window_) if (observing_root_window_)
return; return;
...@@ -1755,7 +1779,8 @@ void RenderWidgetHostViewAndroid::SetContentViewCore( ...@@ -1755,7 +1779,8 @@ void RenderWidgetHostViewAndroid::SetContentViewCore(
if (!content_view_core_) if (!content_view_core_)
return; return;
StartObservingRootWindow(); if (is_showing_)
StartObservingRootWindow();
if (resize) if (resize)
WasResized(); WasResized();
...@@ -1796,6 +1821,17 @@ void RenderWidgetHostViewAndroid::OnCompositingDidCommit() { ...@@ -1796,6 +1821,17 @@ void RenderWidgetHostViewAndroid::OnCompositingDidCommit() {
RunAckCallbacks(cc::SurfaceDrawStatus::DRAWN); RunAckCallbacks(cc::SurfaceDrawStatus::DRAWN);
} }
void RenderWidgetHostViewAndroid::OnRootWindowVisibilityChanged(bool visible) {
DCHECK(is_showing_);
if (visible) {
ShowInternal();
} else {
bool hide_frontbuffer = true;
bool stop_observing_root_window = false;
HideInternal(hide_frontbuffer, stop_observing_root_window);
}
}
void RenderWidgetHostViewAndroid::OnAttachCompositor() { void RenderWidgetHostViewAndroid::OnAttachCompositor() {
DCHECK(content_view_core_); DCHECK(content_view_core_);
if (!overscroll_controller_) if (!overscroll_controller_)
...@@ -1812,7 +1848,7 @@ void RenderWidgetHostViewAndroid::OnDetachCompositor() { ...@@ -1812,7 +1848,7 @@ void RenderWidgetHostViewAndroid::OnDetachCompositor() {
void RenderWidgetHostViewAndroid::OnVSync(base::TimeTicks frame_time, void RenderWidgetHostViewAndroid::OnVSync(base::TimeTicks frame_time,
base::TimeDelta vsync_period) { base::TimeDelta vsync_period) {
TRACE_EVENT0("cc,benchmark", "RenderWidgetHostViewAndroid::OnVSync"); TRACE_EVENT0("cc,benchmark", "RenderWidgetHostViewAndroid::OnVSync");
if (!host_) if (!host_ || host_->is_hidden())
return; return;
if (outstanding_vsync_requests_ & FLUSH_INPUT) { if (outstanding_vsync_requests_ & FLUSH_INPUT) {
...@@ -1838,6 +1874,20 @@ void RenderWidgetHostViewAndroid::OnAnimate(base::TimeTicks begin_frame_time) { ...@@ -1838,6 +1874,20 @@ void RenderWidgetHostViewAndroid::OnAnimate(base::TimeTicks begin_frame_time) {
SetNeedsAnimate(); SetNeedsAnimate();
} }
void RenderWidgetHostViewAndroid::OnActivityPaused() {
TRACE_EVENT0("browser", "RenderWidgetHostViewAndroid::OnActivityPaused");
DCHECK(is_showing_);
bool hide_frontbuffer = false;
bool stop_observing_root_window = false;
HideInternal(hide_frontbuffer, stop_observing_root_window);
}
void RenderWidgetHostViewAndroid::OnActivityResumed() {
TRACE_EVENT0("browser", "RenderWidgetHostViewAndroid::OnActivityResumed");
DCHECK(is_showing_);
ShowInternal();
}
void RenderWidgetHostViewAndroid::OnLostResources() { void RenderWidgetHostViewAndroid::OnLostResources() {
ReleaseLocksOnSurface(); ReleaseLocksOnSurface();
if (layer_.get()) if (layer_.get())
......
...@@ -175,11 +175,14 @@ class CONTENT_EXPORT RenderWidgetHostViewAndroid ...@@ -175,11 +175,14 @@ class CONTENT_EXPORT RenderWidgetHostViewAndroid
// ui::WindowAndroidObserver implementation. // ui::WindowAndroidObserver implementation.
void OnCompositingDidCommit() override; void OnCompositingDidCommit() override;
void OnRootWindowVisibilityChanged(bool visible) override;
void OnAttachCompositor() override; void OnAttachCompositor() override;
void OnDetachCompositor() override; void OnDetachCompositor() override;
void OnVSync(base::TimeTicks frame_time, void OnVSync(base::TimeTicks frame_time,
base::TimeDelta vsync_period) override; base::TimeDelta vsync_period) override;
void OnAnimate(base::TimeTicks begin_frame_time) override; void OnAnimate(base::TimeTicks begin_frame_time) override;
void OnActivityPaused() override;
void OnActivityResumed() override;
// DelegatedFrameEvictor implementation // DelegatedFrameEvictor implementation
void EvictDelegatedFrame() override; void EvictDelegatedFrame() override;
...@@ -269,6 +272,8 @@ class CONTENT_EXPORT RenderWidgetHostViewAndroid ...@@ -269,6 +272,8 @@ class CONTENT_EXPORT RenderWidgetHostViewAndroid
const cc::CompositorFrameMetadata& frame_metadata); const cc::CompositorFrameMetadata& frame_metadata);
void ComputeContentsSize(const cc::CompositorFrameMetadata& frame_metadata); void ComputeContentsSize(const cc::CompositorFrameMetadata& frame_metadata);
void ShowInternal();
void HideInternal(bool hide_frontbuffer, bool stop_observing_root_window);
void AttachLayers(); void AttachLayers();
void RemoveLayers(); void RemoveLayers();
......
...@@ -72,7 +72,8 @@ public class ContentShellActivity extends Activity { ...@@ -72,7 +72,8 @@ public class ContentShellActivity extends Activity {
setContentView(R.layout.content_shell_activity); setContentView(R.layout.content_shell_activity);
mShellManager = (ShellManager) findViewById(R.id.shell_container); mShellManager = (ShellManager) findViewById(R.id.shell_container);
mWindowAndroid = new ActivityWindowAndroid(this); final boolean listenToActivityState = true;
mWindowAndroid = new ActivityWindowAndroid(this, listenToActivityState);
mWindowAndroid.restoreInstanceState(savedInstanceState); mWindowAndroid.restoreInstanceState(savedInstanceState);
mShellManager.setWindow(mWindowAndroid); mShellManager.setWindow(mWindowAndroid);
// Set up the animation placeholder to be the SurfaceView. This disables the // Set up the animation placeholder to be the SurfaceView. This disables the
...@@ -183,14 +184,6 @@ public class ContentShellActivity extends Activity { ...@@ -183,14 +184,6 @@ public class ContentShellActivity extends Activity {
} }
} }
@Override
protected void onStop() {
super.onStop();
ContentViewCore contentViewCore = getActiveContentViewCore();
if (contentViewCore != null) contentViewCore.onHide();
}
@Override @Override
protected void onStart() { protected void onStart() {
super.onStart(); super.onStart();
......
...@@ -11,6 +11,8 @@ import android.content.Intent; ...@@ -11,6 +11,8 @@ import android.content.Intent;
import android.content.IntentSender.SendIntentException; import android.content.IntentSender.SendIntentException;
import android.view.View; import android.view.View;
import org.chromium.base.ActivityState;
import org.chromium.base.ApplicationStatus;
import org.chromium.ui.UiUtils; import org.chromium.ui.UiUtils;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
...@@ -20,7 +22,9 @@ import java.lang.ref.WeakReference; ...@@ -20,7 +22,9 @@ import java.lang.ref.WeakReference;
* Activity Instance. * Activity Instance.
* Only instantiate this class when you need the implemented features. * Only instantiate this class when you need the implemented features.
*/ */
public class ActivityWindowAndroid extends WindowAndroid implements View.OnLayoutChangeListener { public class ActivityWindowAndroid
extends WindowAndroid
implements ApplicationStatus.ActivityStateListener, View.OnLayoutChangeListener {
// Constants used for intent request code bounding. // Constants used for intent request code bounding.
private static final int REQUEST_CODE_PREFIX = 1000; private static final int REQUEST_CODE_PREFIX = 1000;
private static final int REQUEST_CODE_RANGE_SIZE = 100; private static final int REQUEST_CODE_RANGE_SIZE = 100;
...@@ -29,10 +33,28 @@ public class ActivityWindowAndroid extends WindowAndroid implements View.OnLayou ...@@ -29,10 +33,28 @@ public class ActivityWindowAndroid extends WindowAndroid implements View.OnLayou
private final WeakReference<Activity> mActivityRef; private final WeakReference<Activity> mActivityRef;
private int mNextRequestCode = 0; private int mNextRequestCode = 0;
/**
* Creates an Activity-specific WindowAndroid with associated intent functionality.
* TODO(jdduke): Remove this overload when all callsites have been updated to
* indicate their activity state listening preference.
* @param activity The activity associated with the WindowAndroid.
*/
public ActivityWindowAndroid(Activity activity) { public ActivityWindowAndroid(Activity activity) {
this(activity, true);
}
/**
* Creates an Activity-specific WindowAndroid with associated intent functionality.
* @param activity The activity associated with the WindowAndroid.
* @param listenToActivityState Whether to listen to activity state changes.
*/
public ActivityWindowAndroid(Activity activity, boolean listenToActivityState) {
super(activity.getApplicationContext()); super(activity.getApplicationContext());
mActivityRef = new WeakReference<Activity>(activity); mActivityRef = new WeakReference<Activity>(activity);
activity.findViewById(android.R.id.content).addOnLayoutChangeListener(this); activity.findViewById(android.R.id.content).addOnLayoutChangeListener(this);
if (listenToActivityState) {
ApplicationStatus.registerStateListenerForActivity(this, activity);
}
} }
@Override @Override
...@@ -103,6 +125,15 @@ public class ActivityWindowAndroid extends WindowAndroid implements View.OnLayou ...@@ -103,6 +125,15 @@ public class ActivityWindowAndroid extends WindowAndroid implements View.OnLayou
return new WeakReference<Activity>(mActivityRef.get()); return new WeakReference<Activity>(mActivityRef.get());
} }
@Override
public void onActivityStateChange(Activity activity, int newState) {
if (newState == ActivityState.PAUSED) {
onActivityPaused();
} else if (newState == ActivityState.RESUMED) {
onActivityResumed();
}
}
@Override @Override
public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft,
int oldTop, int oldRight, int oldBottom) { int oldTop, int oldRight, int oldBottom) {
......
...@@ -250,6 +250,24 @@ public class WindowAndroid { ...@@ -250,6 +250,24 @@ public class WindowAndroid {
} }
} }
/**
* For window instances associated with an activity, notifies any listeners
* that the activity has been paused.
*/
protected void onActivityPaused() {
if (mNativeWindowAndroid == 0) return;
nativeOnActivityPaused(mNativeWindowAndroid);
}
/**
* For window instances associated with an activity, notifies any listeners
* that the activity has been paused.
*/
protected void onActivityResumed() {
if (mNativeWindowAndroid == 0) return;
nativeOnActivityResumed(mNativeWindowAndroid);
}
/** /**
* Responds to the intent result if the intent was created by the native window. * Responds to the intent result if the intent was created by the native window.
* @param requestCode Request code of the requested intent. * @param requestCode Request code of the requested intent.
...@@ -414,6 +432,8 @@ public class WindowAndroid { ...@@ -414,6 +432,8 @@ public class WindowAndroid {
private native void nativeOnVSync(long nativeWindowAndroid, private native void nativeOnVSync(long nativeWindowAndroid,
long vsyncTimeMicros, long vsyncTimeMicros,
long vsyncPeriodMicros); long vsyncPeriodMicros);
private native void nativeOnActivityPaused(long nativeWindowAndroid);
private native void nativeOnActivityResumed(long nativeWindowAndroid);
private native void nativeDestroy(long nativeWindowAndroid); private native void nativeDestroy(long nativeWindowAndroid);
} }
...@@ -43,6 +43,11 @@ void WindowAndroid::OnCompositingDidCommit() { ...@@ -43,6 +43,11 @@ void WindowAndroid::OnCompositingDidCommit() {
OnCompositingDidCommit()); OnCompositingDidCommit());
} }
void WindowAndroid::OnVisibilityChanged(bool visible) {
FOR_EACH_OBSERVER(WindowAndroidObserver, observer_list_,
OnRootWindowVisibilityChanged(visible));
}
void WindowAndroid::AddObserver(WindowAndroidObserver* observer) { void WindowAndroid::AddObserver(WindowAndroidObserver* observer) {
if (!observer_list_.HasObserver(observer)) if (!observer_list_.HasObserver(observer))
observer_list_.AddObserver(observer); observer_list_.AddObserver(observer);
...@@ -100,6 +105,14 @@ void WindowAndroid::OnVSync(JNIEnv* env, ...@@ -100,6 +105,14 @@ void WindowAndroid::OnVSync(JNIEnv* env,
compositor_->OnVSync(frame_time, vsync_period); compositor_->OnVSync(frame_time, vsync_period);
} }
void WindowAndroid::OnActivityResumed(JNIEnv* env, jobject obj) {
FOR_EACH_OBSERVER(WindowAndroidObserver, observer_list_, OnActivityResumed());
}
void WindowAndroid::OnActivityPaused(JNIEnv* env, jobject obj) {
FOR_EACH_OBSERVER(WindowAndroidObserver, observer_list_, OnActivityPaused());
}
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Native JNI methods // Native JNI methods
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
......
...@@ -43,6 +43,7 @@ class UI_ANDROID_EXPORT WindowAndroid { ...@@ -43,6 +43,7 @@ class UI_ANDROID_EXPORT WindowAndroid {
// Compositor callback relay. // Compositor callback relay.
void OnCompositingDidCommit(); void OnCompositingDidCommit();
void OnVisibilityChanged(bool visible);
void AttachCompositor(WindowAndroidCompositor* compositor); void AttachCompositor(WindowAndroidCompositor* compositor);
void DetachCompositor(); void DetachCompositor();
...@@ -59,6 +60,8 @@ class UI_ANDROID_EXPORT WindowAndroid { ...@@ -59,6 +60,8 @@ class UI_ANDROID_EXPORT WindowAndroid {
jlong time_micros, jlong time_micros,
jlong period_micros); jlong period_micros);
void Animate(base::TimeTicks begin_frame_time); void Animate(base::TimeTicks begin_frame_time);
void OnActivityPaused(JNIEnv* env, jobject obj);
void OnActivityResumed(JNIEnv* env, jobject obj);
private: private:
~WindowAndroid(); ~WindowAndroid();
......
...@@ -12,12 +12,19 @@ namespace ui { ...@@ -12,12 +12,19 @@ namespace ui {
class UI_ANDROID_EXPORT WindowAndroidObserver { class UI_ANDROID_EXPORT WindowAndroidObserver {
public: public:
virtual void OnCompositingDidCommit() = 0; virtual void OnCompositingDidCommit() = 0;
virtual void OnRootWindowVisibilityChanged(bool visible) = 0;
virtual void OnAttachCompositor() = 0; virtual void OnAttachCompositor() = 0;
virtual void OnDetachCompositor() = 0; virtual void OnDetachCompositor() = 0;
virtual void OnVSync(base::TimeTicks frame_time, virtual void OnVSync(base::TimeTicks frame_time,
base::TimeDelta vsync_period) = 0; base::TimeDelta vsync_period) = 0;
virtual void OnAnimate(base::TimeTicks frame_begin_time) {} virtual void OnAnimate(base::TimeTicks frame_begin_time) {}
// Note that activity state callbacks will only be made if the WindowAndroid
// has been explicitly subscribed to receive them. The observer instance
// should account for whether or not this is the case.
virtual void OnActivityPaused() = 0;
virtual void OnActivityResumed() = 0;
protected: protected:
virtual ~WindowAndroidObserver() {} virtual ~WindowAndroidObserver() {}
}; };
......
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