Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0fd9139d authored by Android Build Merger (Role)'s avatar Android Build Merger (Role) Committed by Android (Google) Code Review
Browse files

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

Merge "Merge "Rate limit notifyColorsChanged()" into oc-mr1-dev am: 9d836b63" into oc-mr1-dev-plus-aosp
parents 28e9494d f278ac79
Loading
Loading
Loading
Loading
+46 −7
Original line number Diff line number Diff line
@@ -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
@@ -107,6 +111,8 @@ public abstract class WallpaperService extends Service {
    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");
+68 −0
Original line number Diff line number Diff line
/*
 * 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());
    }
}