ChangeScreen2: Poll for updates in the background

Poll every 30 seconds for updates made to the currently open
change. If a modification is detected show a small butter
bar in the bottom right corner advising the user they are
viewing a stale version of the change.

To be efficient this relies on the recently added support to
reply "304 Not Modified" when there are no updates.

change.updateDelay can be configured by the site administrator
to manage the polling frequency.

Change-Id: Ib3f3acf513193bf1f1f92c472cd586999f3cad5d
This commit is contained in:
Shawn Pearce
2013-07-19 19:45:25 -07:00
parent cd5035d179
commit b9ebb668f6
12 changed files with 555 additions and 32 deletions

View File

@@ -0,0 +1,113 @@
// Copyright (C) 2013 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.google.gerrit.client.ui;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.core.client.Scheduler.RepeatingCommand;
import com.google.gwt.event.dom.client.KeyPressEvent;
import com.google.gwt.event.dom.client.KeyPressHandler;
import com.google.gwt.event.dom.client.MouseMoveEvent;
import com.google.gwt.event.dom.client.MouseMoveHandler;
import com.google.gwt.event.logical.shared.HasValueChangeHandlers;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.event.shared.EventBus;
import com.google.gwt.event.shared.GwtEvent;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.event.shared.SimpleEventBus;
import com.google.gwt.user.client.History;
import com.google.gwtexpui.globalkey.client.DocWidget;
/** Checks for user keyboard and mouse activity. */
public class UserActivityMonitor {
private static final long TIMEOUT = 10 * 60 * 1000;
private static final MonitorImpl impl;
/**
* @return true if there has been keyboard and/or mouse activity in recent
* enough history to believe a user is still controlling this session.
*/
public static boolean isActive() {
return impl.active || impl.recent;
}
public static HandlerRegistration addValueChangeHandler(
ValueChangeHandler<Boolean> handler) {
return impl.addValueChangeHandler(handler);
}
static {
impl = new MonitorImpl();
DocWidget.get().addKeyPressHandler(impl);
DocWidget.get().addMouseMoveHandler(impl);
History.addValueChangeHandler(impl);
Scheduler.get().scheduleFixedDelay(impl, 60 * 1000);
}
private UserActivityMonitor() {
}
private static class MonitorImpl implements RepeatingCommand,
KeyPressHandler, MouseMoveHandler, ValueChangeHandler<String>,
HasValueChangeHandlers<Boolean> {
private final EventBus bus = new SimpleEventBus();
private boolean recent = true;
private boolean active = true;
private long last = System.currentTimeMillis();
@Override
public void onKeyPress(KeyPressEvent event) {
recent = true;
}
@Override
public void onMouseMove(MouseMoveEvent event) {
recent = true;
}
@Override
public void onValueChange(ValueChangeEvent<String> event) {
recent = true;
}
@Override
public boolean execute() {
long now = System.currentTimeMillis();
if (recent) {
if (!active) {
ValueChangeEvent.fire(this, active);
}
recent = false;
active = true;
last = now;
} else if (active && (now - last) > TIMEOUT) {
active = false;
ValueChangeEvent.fire(this, false);
}
return true;
}
@Override
public HandlerRegistration addValueChangeHandler(
ValueChangeHandler<Boolean> handler) {
return bus.addHandler(ValueChangeEvent.getType(), handler);
}
@Override
public void fireEvent(GwtEvent<?> event) {
bus.fireEvent(event);
}
}
}