/*
 * Copyright (C) 2011 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 android.app.cts;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;

import android.app.WallpaperColors;
import android.app.WallpaperManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Point;
import android.os.Handler;
import android.os.Looper;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import android.util.Log;
import android.view.Display;
import android.view.WindowManager;

import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.MockitoAnnotations;

import android.app.stubs.R;

import java.io.IOException;
import java.util.ArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

@RunWith(AndroidJUnit4.class)
public class WallpaperManagerTest {

    private static final boolean DEBUG = false;
    private static final String TAG = "WallpaperManagerTest";

    private WallpaperManager mWallpaperManager;
    private Context mContext;

    @Before
    public void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);
        mContext = InstrumentationRegistry.getTargetContext();
        mWallpaperManager = WallpaperManager.getInstance(mContext);
    }

    @Test
    public void setBitmapTest() {
        Bitmap tmpWallpaper = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(tmpWallpaper);
        canvas.drawColor(Color.RED);

        try {
            int which = WallpaperManager.FLAG_SYSTEM;
            int oldWallpaperId = mWallpaperManager.getWallpaperId(which);
            mWallpaperManager.setBitmap(tmpWallpaper);
            int newWallpaperId = mWallpaperManager.getWallpaperId(which);
            Assert.assertNotEquals(oldWallpaperId, newWallpaperId);
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            tmpWallpaper.recycle();
        }
    }

    @Test
    public void setResourceTest() {
        try {
            int which = WallpaperManager.FLAG_SYSTEM;
            int oldWallpaperId = mWallpaperManager.getWallpaperId(which);
            mWallpaperManager.setResource(R.drawable.robot);
            int newWallpaperId = mWallpaperManager.getWallpaperId(which);
            Assert.assertNotEquals(oldWallpaperId, newWallpaperId);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    @Test
    public void wallpaperChangedBroadcastTest() {
        Bitmap tmpWallpaper = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(tmpWallpaper);
        canvas.drawColor(Color.BLACK);

        CountDownLatch latch = new CountDownLatch(1);
        mContext.registerReceiver(new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                latch.countDown();
            }
        }, new IntentFilter(Intent.ACTION_WALLPAPER_CHANGED));

        try {
            mWallpaperManager.setBitmap(tmpWallpaper);

            // Wait for 5 sec since this is an async call.
            // Should fail if Intent.ACTION_WALLPAPER_CHANGED isn't delivered.
            latch.await(5, TimeUnit.SECONDS);
            if (latch.getCount() > 0) {
                throw new AssertionError("Intent.ACTION_WALLPAPER_CHANGED not received.");
            }
        } catch (InterruptedException | IOException e) {
            throw new AssertionError("Intent.ACTION_WALLPAPER_CHANGED not received.");
        } finally {
            tmpWallpaper.recycle();
        }
    }

    @Test
    public void wallpaperClearBroadcastTest() {
        CountDownLatch latch = new CountDownLatch(1);
        mContext.registerReceiver(new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                latch.countDown();
            }
        }, new IntentFilter(Intent.ACTION_WALLPAPER_CHANGED));

        try {
            mWallpaperManager.clear(WallpaperManager.FLAG_LOCK | WallpaperManager.FLAG_SYSTEM);

            // Wait for 5 sec since this is an async call.
            // Should fail if Intent.ACTION_WALLPAPER_CHANGED isn't delivered.
            latch.await(5, TimeUnit.SECONDS);
            if (latch.getCount() > 0) {
                throw new AssertionError("Intent.ACTION_WALLPAPER_CHANGED not received.");
            }
        } catch (InterruptedException | IOException e) {
            throw new AssertionError(e);
        }
    }

    @Test
    public void invokeOnColorsChangedListenerTest_systemOnly() {
        int both = WallpaperManager.FLAG_LOCK | WallpaperManager.FLAG_SYSTEM;
        // Expect both since the first step is to migrate the current wallpaper
        // to the lock screen.
        verifyColorListenerInvoked(WallpaperManager.FLAG_SYSTEM, both);
    }

    @Test
    public void invokeOnColorsChangedListenerTest_lockOnly() {
        verifyColorListenerInvoked(WallpaperManager.FLAG_LOCK, WallpaperManager.FLAG_LOCK);
    }

    @Test
    public void invokeOnColorsChangedListenerTest_both() {
        int both = WallpaperManager.FLAG_LOCK | WallpaperManager.FLAG_SYSTEM;
        verifyColorListenerInvoked(both, both);
    }

    @Test
    public void invokeOnColorsChangedListenerTest_clearLock() throws IOException {
        verifyColorListenerInvokedClearing(WallpaperManager.FLAG_LOCK);
    }

    @Test
    public void invokeOnColorsChangedListenerTest_clearSystem() throws IOException {
        verifyColorListenerInvokedClearing(WallpaperManager.FLAG_SYSTEM);
    }

    /**
     * Removing a listener should not invoke it anymore
     */
    @Test
    public void addRemoveOnColorsChangedListenerTest_onlyInvokeAdded() throws IOException {
        ensureCleanState();

        final CountDownLatch latch = new CountDownLatch(1);
        WallpaperManager.OnColorsChangedListener counter = (colors, whichWp) -> latch.countDown();

        // Add and remove listener
        WallpaperManager.OnColorsChangedListener listener =
                mock(WallpaperManager.OnColorsChangedListener.class);
        mWallpaperManager.addOnColorsChangedListener(listener);
        mWallpaperManager.removeOnColorsChangedListener(listener);

        // Verify that the listener is not called
        mWallpaperManager.addOnColorsChangedListener(counter);
        try {
            mWallpaperManager.setResource(R.drawable.robot);
            latch.await(5, TimeUnit.SECONDS);
            if (latch.getCount() > 0) {
                throw new AssertionError("Registered listener not invoked");
            }
        } catch (InterruptedException | IOException e) {
            throw new RuntimeException(e);
        }
        verify(listener, never()).onColorsChanged(any(WallpaperColors.class), anyInt());
        mWallpaperManager.removeOnColorsChangedListener(counter);
    }

    /**
     * Suggesting desired dimensions is only a hint to the system that can be ignored.
     *
     * Test if the desired minimum width or height the WallpaperManager returns
     * is greater than 0. If so, then we check whether that the size is at least the
     * as big as the screen.
     */
    @Test
    public void suggestDesiredDimensionsTest() {
        final Point min = getScreenSize();
        final int w = min.x * 3;
        final int h = min.y * 2;
        assertDesiredMinimum(new Point(min.x / 2, min.y / 2), min);

        assertDesiredMinimum(new Point(w, h), min);

        assertDesiredMinimum(new Point(min.x / 2, h), min);

        assertDesiredMinimum(new Point(w, min.y / 2), min);
    }

    private void assertDesiredMinimum(Point suggestedSize, Point minSize) {
        mWallpaperManager.suggestDesiredDimensions(suggestedSize.x, suggestedSize.y);
        Point actualSize = new Point(mWallpaperManager.getDesiredMinimumWidth(),
                mWallpaperManager.getDesiredMinimumHeight());
        if (actualSize.x > 0 || actualSize.y > 0) {
            if ((actualSize.x < minSize.x || actualSize.y < minSize.y)) {
                throw new AssertionError("Expected at least x: " + minSize.x + " y: "
                        + minSize.y + ", got x: " + actualSize.x +
                        " y: " + actualSize.y);
            }
        }
    }

    private Point getScreenSize() {
        WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
        Display d = wm.getDefaultDisplay();
        Point p = new Point();
        d.getRealSize(p);
        return p;
    }

    /**
     * Helper to set a listener anc verify if it was called with the same flags.
     * Executes operation synchronously.
     *
     * @param which FLAG_LOCK, FLAG_SYSTEM or a combination of both.
     */
    private void verifyColorListenerInvoked(int which, int whichExpected) {
        ensureCleanState();
        int expected = 0;
        if ((whichExpected & WallpaperManager.FLAG_LOCK) != 0) expected++;
        if ((whichExpected & WallpaperManager.FLAG_SYSTEM) != 0) expected++;
        ArrayList<Integer> received = new ArrayList<>();

        final CountDownLatch latch = new CountDownLatch(expected);
        Handler handler = new Handler(Looper.getMainLooper());

        WallpaperManager.OnColorsChangedListener listener =
                mock(WallpaperManager.OnColorsChangedListener.class);
        WallpaperManager.OnColorsChangedListener counter = (colors, whichWp) -> {
            handler.post(()-> {
                received.add(whichWp);
                boolean ok = false;
                if ((whichWp & WallpaperManager.FLAG_LOCK) != 0 &&
                        (whichExpected & WallpaperManager.FLAG_LOCK) != 0) {
                    latch.countDown();
                    ok = true;
                }
                if ((whichWp & WallpaperManager.FLAG_SYSTEM) != 0 &&
                        (whichExpected & WallpaperManager.FLAG_SYSTEM) != 0) {
                    latch.countDown();
                    ok = true;
                }
                if (!ok) {
                    throw new AssertionError("Unexpected which flag: " + whichWp +
                            " should be: " + whichExpected);
                }
            });
        };

        mWallpaperManager.addOnColorsChangedListener(listener);
        mWallpaperManager.addOnColorsChangedListener(counter);

        try {
            mWallpaperManager.setResource(R.drawable.robot, which);
            latch.await(5, TimeUnit.SECONDS);
            if (latch.getCount() != 0) {
                throw new AssertionError("Didn't receive all color events. Expected: " +
                        whichExpected + " received: " + received);
            }
        } catch (InterruptedException | IOException e) {
            throw new RuntimeException(e);
        }

        mWallpaperManager.removeOnColorsChangedListener(listener);
        mWallpaperManager.removeOnColorsChangedListener(counter);
    }

    /**
     * Helper to clear a wallpaper synchronously.
     *
     * @param which FLAG_LOCK, FLAG_SYSTEM or a combination of both.
     */
    private void verifyColorListenerInvokedClearing(int which) {
        ensureCleanState();

        final CountDownLatch latch = new CountDownLatch(1);

        WallpaperManager.OnColorsChangedListener listener =
                mock(WallpaperManager.OnColorsChangedListener.class);
        WallpaperManager.OnColorsChangedListener counter = (colors, whichWp) -> {
            latch.countDown();
        };

        mWallpaperManager.addOnColorsChangedListener(listener);
        mWallpaperManager.addOnColorsChangedListener(counter);

        try {
            mWallpaperManager.clear(which);
            latch.await(5, TimeUnit.SECONDS);
        } catch (InterruptedException | IOException e) {
            throw new RuntimeException(e);
        }

        verify(listener, atLeast(1))
                .onColorsChanged(nullable(WallpaperColors.class), anyInt());

        mWallpaperManager.removeOnColorsChangedListener(listener);
        mWallpaperManager.removeOnColorsChangedListener(counter);
    }

    /**
     * Helper method to make sure a wallpaper is set for both FLAG_SYSTEM and FLAG_LOCK
     * and its callbacks were already called. Necessary to cleanup previous tests states.
     *
     * This is necessary to avoid race conditions between tests
     */
    private void ensureCleanState() {
        Bitmap bmp = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
        int expectedEvents = 3; // Changed wallpaper, LOCK and SYSTEM
        CountDownLatch latch = new CountDownLatch(expectedEvents);
        if (DEBUG) {
            Log.d("WP", "Started latch expecting: " + latch.getCount());
        }
        BroadcastReceiver receiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                latch.countDown();
                if (DEBUG) {
                    Log.d("WP", "broadcast state count down: " + latch.getCount());
                }
            }
        };
        WallpaperManager.OnColorsChangedListener callback = (colors, which) -> {
            if ((which & WallpaperManager.FLAG_LOCK) != 0) {
                latch.countDown();
            }
            if ((which & WallpaperManager.FLAG_SYSTEM) != 0) {
                latch.countDown();
            }
            if (DEBUG) {
                Log.d("WP", "color state count down: " + which + " - " + colors);
            }
        };
        mContext.registerReceiver(receiver, new IntentFilter(Intent.ACTION_WALLPAPER_CHANGED));
        mWallpaperManager.addOnColorsChangedListener(callback);

        try {
            mWallpaperManager.setBitmap(bmp);

            // Wait for up to 5 sec since this is an async call.
            // Will pass as soon as the expected callbacks are executed.
            latch.await(5, TimeUnit.SECONDS);
            if (latch.getCount() != 0) {
                Log.w(TAG, "Did not receive all events! This is probably a bug.");
            }
        } catch (InterruptedException | IOException e) {
            throw new RuntimeException("Can't ensure a clean state.");
        } finally {
            mContext.unregisterReceiver(receiver);
            mWallpaperManager.removeOnColorsChangedListener(callback);
            bmp.recycle();
        }
    }
}