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

Commit f278ac79 authored by Lucas Dupin's avatar Lucas Dupin Committed by android-build-merger
Browse files

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

am: 9d836b63

Change-Id: I49a5f9ec39246c204b265717c9cebb5b6773e5f8
parents 1a0a79c8 9d836b63
Loading
Loading
Loading
Loading
+46 −7
Original line number Original line Diff line number Diff line
@@ -33,10 +33,12 @@ import android.graphics.drawable.Drawable;
import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManager.DisplayListener;
import android.hardware.display.DisplayManager.DisplayListener;
import android.os.Bundle;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.IBinder;
import android.os.Looper;
import android.os.Looper;
import android.os.Message;
import android.os.Message;
import android.os.RemoteException;
import android.os.RemoteException;
import android.os.SystemClock;
import android.util.Log;
import android.util.Log;
import android.util.MergedConfiguration;
import android.util.MergedConfiguration;
import android.view.Display;
import android.view.Display;
@@ -54,6 +56,7 @@ import android.view.WindowInsets;
import android.view.WindowManager;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
import android.view.WindowManagerGlobal;


import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.HandlerCaller;
import com.android.internal.os.HandlerCaller;
import com.android.internal.view.BaseIWindow;
import com.android.internal.view.BaseIWindow;
import com.android.internal.view.BaseSurfaceHolder;
import com.android.internal.view.BaseSurfaceHolder;
@@ -61,6 +64,7 @@ import com.android.internal.view.BaseSurfaceHolder;
import java.io.FileDescriptor;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.ArrayList;
import java.util.function.Supplier;


/**
/**
 * A wallpaper service is responsible for showing a live wallpaper behind
 * 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_TOUCH_EVENT = 10040;
    private static final int MSG_REQUEST_WALLPAPER_COLORS = 10050;
    private static final int MSG_REQUEST_WALLPAPER_COLORS = 10050;


    private static final int NOTIFY_COLORS_RATE_LIMIT_MS = 1000;

    private final ArrayList<Engine> mActiveEngines
    private final ArrayList<Engine> mActiveEngines
            = new ArrayList<Engine>();
            = new ArrayList<Engine>();
    
    
@@ -186,6 +192,11 @@ public abstract class WallpaperService extends Service {
        boolean mPendingSync;
        boolean mPendingSync;
        MotionEvent mPendingMove;
        MotionEvent mPendingMove;


        // Needed for throttling onComputeColors.
        private long mLastColorInvalidation;
        private final Runnable mNotifyColorsChanged = this::notifyColorsChanged;
        private Supplier<Long> mClockFunction = SystemClock::elapsedRealtime;

        DisplayManager mDisplayManager;
        DisplayManager mDisplayManager;
        Display mDisplay;
        Display mDisplay;
        private int mDisplayState;
        private int mDisplayState;
@@ -551,18 +562,38 @@ public abstract class WallpaperService extends Service {
         * This will trigger a {@link #onComputeColors()} call.
         * This will trigger a {@link #onComputeColors()} call.
         */
         */
        public void notifyColorsChanged() {
        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 {
            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) {
            } catch (RemoteException e) {
                Log.w(TAG, "Can't invalidate wallpaper colors because " +
                Log.w(TAG, "Can't notify system because wallpaper connection was lost.", e);
                        "wallpaper connection was lost", e);
            }
            }
        }
        }


        /**
        /**
         * Called by the system when it needs to know what colors the wallpaper is using.
         * 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 return null if no color information is available at the moment.
         * you might want to call {@link #notifyColorsChanged()} in a near future.
         * In that case you might want to call {@link #notifyColorsChanged()} when
         * color information becomes available.
         * <p>
         * <p>
         * The simplest way of creating a {@link android.app.WallpaperColors} object is by using
         * The simplest way of creating a {@link android.app.WallpaperColors} object is by using
         * {@link android.app.WallpaperColors#fromBitmap(Bitmap)} or
         * {@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) {
        void updateSurface(boolean forceRelayout, boolean forceReport, boolean redrawNeeded) {
            if (mDestroyed) {
            if (mDestroyed) {
                Log.w(TAG, "Ignoring updateSurface: destroyed");
                Log.w(TAG, "Ignoring updateSurface: destroyed");
+68 −0
Original line number Original line 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());
    }
}