Merge "Rate limit notifyColorsChanged()" into oc-mr1-dev

This commit is contained in:
TreeHugger Robot
2017-08-09 20:07:48 +00:00
committed by Android (Google) Code Review
2 changed files with 114 additions and 7 deletions

View File

@@ -33,10 +33,12 @@ import android.graphics.drawable.Drawable;
import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManager.DisplayListener;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
import android.os.SystemClock;
import android.util.Log;
import android.util.MergedConfiguration;
import android.view.Display;
@@ -54,6 +56,7 @@ import android.view.WindowInsets;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.HandlerCaller;
import com.android.internal.view.BaseIWindow;
import com.android.internal.view.BaseSurfaceHolder;
@@ -61,6 +64,7 @@ import com.android.internal.view.BaseSurfaceHolder;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.function.Supplier;
/**
* A wallpaper service is responsible for showing a live wallpaper behind
@@ -106,7 +110,9 @@ public abstract class WallpaperService extends Service {
private static final int MSG_WINDOW_MOVED = 10035;
private static final int MSG_TOUCH_EVENT = 10040;
private static final int MSG_REQUEST_WALLPAPER_COLORS = 10050;
private static final int NOTIFY_COLORS_RATE_LIMIT_MS = 1000;
private final ArrayList<Engine> mActiveEngines
= new ArrayList<Engine>();
@@ -186,6 +192,11 @@ public abstract class WallpaperService extends Service {
boolean mPendingSync;
MotionEvent mPendingMove;
// Needed for throttling onComputeColors.
private long mLastColorInvalidation;
private final Runnable mNotifyColorsChanged = this::notifyColorsChanged;
private Supplier<Long> mClockFunction = SystemClock::elapsedRealtime;
DisplayManager mDisplayManager;
Display mDisplay;
private int mDisplayState;
@@ -551,18 +562,38 @@ public abstract class WallpaperService extends Service {
* This will trigger a {@link #onComputeColors()} call.
*/
public void notifyColorsChanged() {
final long now = mClockFunction.get();
final Handler mainHandler = Handler.getMain();
if (now - mLastColorInvalidation < NOTIFY_COLORS_RATE_LIMIT_MS) {
Log.w(TAG, "This call has been deferred. You should only call "
+ "notifyColorsChanged() once every "
+ (NOTIFY_COLORS_RATE_LIMIT_MS / 1000f) + " seconds.");
if (!mainHandler.hasCallbacks(mNotifyColorsChanged)) {
mainHandler.postDelayed(mNotifyColorsChanged, NOTIFY_COLORS_RATE_LIMIT_MS);
}
return;
}
mLastColorInvalidation = now;
mainHandler.removeCallbacks(mNotifyColorsChanged);
try {
mConnection.onWallpaperColorsChanged(onComputeColors());
final WallpaperColors newColors = onComputeColors();
if (mConnection != null) {
mConnection.onWallpaperColorsChanged(newColors);
} else {
Log.w(TAG, "Can't notify system because wallpaper connection "
+ "was not established.");
}
} catch (RemoteException e) {
Log.w(TAG, "Can't invalidate wallpaper colors because " +
"wallpaper connection was lost", e);
Log.w(TAG, "Can't notify system because wallpaper connection was lost.", e);
}
}
/**
* Called by the system when it needs to know what colors the wallpaper is using.
* You might return null if no color information is available at the moment. In that case
* you might want to call {@link #notifyColorsChanged()} in a near future.
* You might return null if no color information is available at the moment.
* In that case you might want to call {@link #notifyColorsChanged()} when
* color information becomes available.
* <p>
* The simplest way of creating a {@link android.app.WallpaperColors} object is by using
* {@link android.app.WallpaperColors#fromBitmap(Bitmap)} or
@@ -631,6 +662,14 @@ public abstract class WallpaperService extends Service {
}
}
/**
* @hide
*/
@VisibleForTesting
public void setClockFunction(Supplier<Long> clockFunction) {
mClockFunction = clockFunction;
}
void updateSurface(boolean forceRelayout, boolean forceReport, boolean redrawNeeded) {
if (mDestroyed) {
Log.w(TAG, "Ignoring updateSurface: destroyed");
@@ -893,7 +932,7 @@ public abstract class WallpaperService extends Service {
" w=" + mLayout.width + " h=" + mLayout.height);
}
}
void attach(IWallpaperEngineWrapper wrapper) {
if (DEBUG) Log.v(TAG, "attach: " + this + " wrapper=" + wrapper);
if (mDestroyed) {

View File

@@ -0,0 +1,68 @@
/*
* Copyright (C) 2017 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.server.wallpaper;
import static org.junit.Assert.assertEquals;
import android.app.WallpaperColors;
import android.os.SystemClock;
import android.service.wallpaper.WallpaperService;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.concurrent.CountDownLatch;
@SmallTest
@RunWith(AndroidJUnit4.class)
public class WallpaperServiceTests {
@Test
public void testNotifyColorsChanged_rateLimit() throws Exception {
CountDownLatch eventCountdown = new CountDownLatch(2);
WallpaperService service = new WallpaperService() {
@Override
public Engine onCreateEngine() {
return new WallpaperService.Engine() {
@Override
public WallpaperColors onComputeColors() {
eventCountdown.countDown();
return null;
}
};
}
};
WallpaperService.Engine engine = service.onCreateEngine();
// Called because it's the first time.
engine.notifyColorsChanged();
assertEquals("OnComputeColors should have been called.",
1, eventCountdown.getCount());
// Ignored since the call should be throttled.
engine.notifyColorsChanged();
assertEquals("OnComputeColors should have been throttled.",
1, eventCountdown.getCount());
// Called after being deferred.
engine.setClockFunction(() -> SystemClock.elapsedRealtime() + 1500);
engine.notifyColorsChanged();
assertEquals("OnComputeColors should have been deferred.",
0, eventCountdown.getCount());
}
}