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

Commit a0bf4f77 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Revert "add classes to help RRO theme test""

parents d848a815 be64f9ae
Loading
Loading
Loading
Loading
+0 −154
Original line number Diff line number Diff line
/*
 * Copyright (C) 2019 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.documentsui;

import android.graphics.Color;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import java.util.Locale;

/**
 * To help the image verification by using RGB, HSV, and HSL color space to make sure whether the
 * pixels in the image over the threshold or not. Not only to use color ARGB match but also to
 * fuzzy color match(RGB, HSV, HSL).
 */
public class FuzzyColor {
    public static class Threshold {
        public int getColor() {
            return 20;
        }

        public float getHue() {
            return 8f;
        }

        public float getSaturation() {
            return 0.25f;
        }

        public float getValue() {
            return 0.25f;
        }

        public float getLuminance() {
            return 0.1f;
        }
    }

    private static Threshold sThreshold = new Threshold();

    /**
     * To set the threshold adjust the verify algorithm.
     *
     * @param threshold the threshold that want to set
     */
    public static synchronized void setThreshold(Threshold threshold) {
        if (threshold == null) {
            return;
        }
        sThreshold = threshold;
    }

    private final int mColor;
    private final float [] mHsv;
    private final float mLuminance;
    private final int mRed;
    private final int mGreen;
    private final int mBlue;
    private int mCount;

    /**
     * To initial a FuzzyColor according to color parameter.
     *
     * @param color the ARGB color for the pixel in the image
     */
    public FuzzyColor(int color) {
        mColor = color;

        mRed = Color.red(color);
        mGreen = Color.green(color);
        mBlue = Color.blue(color);
        mHsv = new float[3];
        mLuminance = Color.luminance(color);
        Color.RGBToHSV(Color.red(color), Color.green(color), Color.blue(color), mHsv);
    }

    public void add(int count) {
        mCount += count;
    }

    public int getCount() {
        return mCount;
    }

    public int getColor() {
        return mColor;
    }

    @Override
    public boolean equals(@Nullable Object obj) {
        if (obj instanceof FuzzyColor) {
            FuzzyColor other = (FuzzyColor) obj;
            return compare(this, other);
        } else if (obj instanceof Integer) {
            int color = (int) obj;
            return compare(this, new FuzzyColor(color));
        } else {
            return false;
        }
    }

    private static boolean compare(FuzzyColor c1, FuzzyColor c2) {
        if (Math.abs(c1.mRed - c2.mRed) < sThreshold.getColor()
                && Math.abs(c1.mGreen - c2.mGreen) < sThreshold.getColor()
                && Math.abs(c1.mBlue - c2.mBlue) < sThreshold.getColor()) {
            return true;
        }

        float hueDiff = Math.abs(c1.mHsv[0] - c2.mHsv[0]);
        if (hueDiff > sThreshold.getHue() && hueDiff < (360f - sThreshold.getHue())) {
            return false;
        }

        float saturationDiff = Math.abs(c1.mHsv[1] - c2.mHsv[1]);
        if (saturationDiff > sThreshold.getSaturation()) {
            return false;
        }

        float valueDiff = Math.abs(c1.mHsv[2] - c2.mHsv[2]);
        if (valueDiff > sThreshold.getValue()) {
            return false;
        }

        float luminanceDiff = Math.abs(c1.mLuminance - c2.mLuminance);
        if (luminanceDiff > sThreshold.getLuminance()) {
            return false;
        }

        return true;
    }

    @NonNull
    @Override
    public String toString() {
        return String.format(Locale.ENGLISH,
                "[#%08x] count = %d, hue = %f, saturation = %f, value = %f, luminance = %f",
                mColor, mCount, mHsv[0], mHsv[1],  mHsv[2], mLuminance);
    }
}
+0 −53
Original line number Diff line number Diff line
/*
 * Copyright (C) 2019 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.documentsui;

import android.graphics.Bitmap;
import android.util.Log;

import androidx.test.runner.screenshot.BasicScreenCaptureProcessor;
import androidx.test.runner.screenshot.ScreenCapture;
import androidx.test.runner.screenshot.Screenshot;

import java.io.IOException;

import org.junit.rules.TestWatcher;
import org.junit.runner.Description;

/**
 * When the test fail happen, the screen capture will help the developer to judge
 * what does the UI looks like, where is the asserted view, and why test fail.
 */
public class ScreenshotCaptureRule extends TestWatcher {
    private static final String TAG = ScreenshotCaptureRule.class.getSimpleName();

    @Override
    protected void failed(Throwable e, Description description) {
        super.failed(e, description);

        ScreenCapture capture = Screenshot.capture();
        capture.setFormat(Bitmap.CompressFormat.PNG);
        capture.setName(description.getMethodName());

        try {
            new BasicScreenCaptureProcessor().process(capture);
        } catch (IOException e1) {
            Log.e(TAG, "Can't handle the capture. " + e1.getMessage());
        }
    }
}
+0 −123
Original line number Diff line number Diff line
/*
 * Copyright (C) 2019 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.documentsui.picker;

import static androidx.test.espresso.Espresso.onView;
import static androidx.test.espresso.matcher.ViewMatchers.withText;

import static com.google.common.truth.Truth.assertThat;

import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Color;

import androidx.test.espresso.ViewAssertion;
import androidx.test.filters.MediumTest;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.rule.ActivityTestRule;
import androidx.test.runner.AndroidJUnit4;
import androidx.test.runner.screenshot.ScreenCapture;
import androidx.test.runner.screenshot.Screenshot;

import com.android.documentsui.FuzzyColor;
import com.android.documentsui.R;
import com.android.documentsui.ScreenshotCaptureRule;

import java.util.ArrayList;
import java.util.List;

import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.RuleChain;
import org.junit.rules.TestName;
import org.junit.runner.RunWith;

@RunWith(AndroidJUnit4.class)
@MediumTest
public class PickActivityTest {
    @Rule
    public ActivityTestRule mActivityTestRule = new ActivityTestRule(PickActivity.class,
            false, false);

    @Rule
    public RuleChain mRuleChain = RuleChain.outerRule(mActivityTestRule)
            .around(new ScreenshotCaptureRule());
    @Rule
    public TestName mTestName = new TestName();

    private static List<FuzzyColor> getFuzzyHistogram(Bitmap bitmap,
            FuzzyColor.Threshold threshold) {
        List<FuzzyColor> histogram = new ArrayList<>();
        FuzzyColor.setThreshold(threshold);

        final int size = bitmap.getWidth() * bitmap.getHeight();
        final int [] colorPixels = new int[size];
        bitmap.getPixels(colorPixels, 0, bitmap.getWidth(), 0, 0,
                bitmap.getWidth(), bitmap.getHeight());
        for (int color : colorPixels) {
            if (Color.alpha(color) < 127) {
                continue;
            }

            FuzzyColor target = null;
            for (FuzzyColor matcher : histogram) {
                if (matcher.equals(color)) {
                    matcher.add(1);
                    target = matcher;
                }
            }

            if (target == null) {
                target = new FuzzyColor(color);
                target.add(1);
                histogram.add(target);
            }
        }

        histogram.sort((o1, o2) -> o2.getCount() - o1.getCount());

        return histogram;
    }

    static ViewAssertion assertColorCorrect(TestName testName, FuzzyColor.Threshold threshold) {
        return (view, noViewFoundException) -> {
            ScreenCapture capture = Screenshot.capture(view);
            capture.setName(testName.getMethodName());
            capture.setFormat(Bitmap.CompressFormat.PNG);
            Bitmap bitmap = capture.getBitmap();

            List<FuzzyColor> fuzzyHistogram = getFuzzyHistogram(bitmap, threshold);

            assertThat(fuzzyHistogram.size()).named("The number of dominant color")
                    .isGreaterThan(1);
        };
    }

    @Test
    public void onCreate_actionCreate_shouldLaunchSuccess() throws InterruptedException {
        Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
        intent.addCategory(Intent.CATEGORY_OPENABLE);
        intent.setType("text/plain");
        intent.putExtra(Intent.EXTRA_TITLE, "foobar.txt");

        mActivityTestRule.launchActivity(intent);
        InstrumentationRegistry.getInstrumentation().waitForIdleSync();

        onView(withText(R.string.menu_save)).check(assertColorCorrect(mTestName, null));
    }
}