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

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

Merge "Prototype color changing support"

parents 840f86b7 355fe21e
Loading
Loading
Loading
Loading
+6 −2
Original line number Original line Diff line number Diff line
@@ -76,11 +76,14 @@ public class LightBarController implements BatteryController.BatteryStateChangeC
    private final Rect mLastDockedBounds = new Rect();
    private final Rect mLastDockedBounds = new Rect();
    private boolean mQsCustomizing;
    private boolean mQsCustomizing;


    private final Context mContext;

    public LightBarController(Context ctx) {
    public LightBarController(Context ctx) {
        mDarkModeColor = Color.valueOf(ctx.getColor(R.color.dark_mode_icon_color_single_tone));
        mDarkModeColor = Color.valueOf(ctx.getColor(R.color.dark_mode_icon_color_single_tone));
        mStatusBarIconController = Dependency.get(DarkIconDispatcher.class);
        mStatusBarIconController = Dependency.get(DarkIconDispatcher.class);
        mBatteryController = Dependency.get(BatteryController.class);
        mBatteryController = Dependency.get(BatteryController.class);
        mBatteryController.addCallback(this);
        mBatteryController.addCallback(this);
        mContext = ctx;
    }
    }


    public void setNavigationBar(LightBarTransitionsController navigationBar) {
    public void setNavigationBar(LightBarTransitionsController navigationBar) {
@@ -217,8 +220,9 @@ public class LightBarController implements BatteryController.BatteryStateChangeC


    private void updateNavigation() {
    private void updateNavigation() {
        if (mNavigationBarController != null) {
        if (mNavigationBarController != null) {
            mNavigationBarController.setIconsDark(
            if (!NavBarTintController.isEnabled(mContext)) {
                    mNavigationLight, animateChange());
                mNavigationBarController.setIconsDark(mNavigationLight, animateChange());
            }
        }
        }
    }
    }


+20 −3
Original line number Original line Diff line number Diff line
@@ -16,12 +16,16 @@


package com.android.systemui.statusbar.phone;
package com.android.systemui.statusbar.phone;


import static com.android.systemui.statusbar.phone.NavBarTintController.MIN_COLOR_ADAPT_TRANSITION_TIME;
import static com.android.systemui.statusbar.phone.NavBarTintController.NAV_COLOR_TRANSITION_TIME_SETTING;

import android.animation.ValueAnimator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.Context;
import android.os.Bundle;
import android.os.Bundle;
import android.os.Handler;
import android.os.Handler;
import android.os.SystemClock;
import android.os.SystemClock;
import android.util.MathUtils;
import android.util.MathUtils;
import android.provider.Settings;
import android.util.TimeUtils;
import android.util.TimeUtils;


import com.android.systemui.Dependency;
import com.android.systemui.Dependency;
@@ -42,13 +46,14 @@ import java.io.PrintWriter;
public class LightBarTransitionsController implements Dumpable, Callbacks,
public class LightBarTransitionsController implements Dumpable, Callbacks,
        StatusBarStateController.StateListener {
        StatusBarStateController.StateListener {


    public static final long DEFAULT_TINT_ANIMATION_DURATION = 120;
    public static final int DEFAULT_TINT_ANIMATION_DURATION = 120;
    private static final String EXTRA_DARK_INTENSITY = "dark_intensity";
    private static final String EXTRA_DARK_INTENSITY = "dark_intensity";


    private final Handler mHandler;
    private final Handler mHandler;
    private final DarkIntensityApplier mApplier;
    private final DarkIntensityApplier mApplier;
    private final KeyguardMonitor mKeyguardMonitor;
    private final KeyguardMonitor mKeyguardMonitor;
    private final StatusBarStateController mStatusBarStateController;
    private final StatusBarStateController mStatusBarStateController;
    private NavBarTintController mColorAdaptionController;


    private boolean mTransitionDeferring;
    private boolean mTransitionDeferring;
    private long mTransitionDeferringStartTime;
    private long mTransitionDeferringStartTime;
@@ -67,6 +72,8 @@ public class LightBarTransitionsController implements Dumpable, Callbacks,
        }
        }
    };
    };


    private final Context mContext;

    public LightBarTransitionsController(Context context, DarkIntensityApplier applier) {
    public LightBarTransitionsController(Context context, DarkIntensityApplier applier) {
        mApplier = applier;
        mApplier = applier;
        mHandler = new Handler();
        mHandler = new Handler();
@@ -76,6 +83,7 @@ public class LightBarTransitionsController implements Dumpable, Callbacks,
                .addCallback(this);
                .addCallback(this);
        mStatusBarStateController.addCallback(this);
        mStatusBarStateController.addCallback(this);
        mDozeAmount = mStatusBarStateController.getDozeAmount();
        mDozeAmount = mStatusBarStateController.getDozeAmount();
        mContext = context;
    }
    }


    public void destroy(Context context) {
    public void destroy(Context context) {
@@ -106,7 +114,7 @@ public class LightBarTransitionsController implements Dumpable, Callbacks,
    public void appTransitionCancelled() {
    public void appTransitionCancelled() {
        if (mTransitionPending && mTintChangePending) {
        if (mTransitionPending && mTintChangePending) {
            mTintChangePending = false;
            mTintChangePending = false;
            animateIconTint(mPendingDarkIntensity, 0 /* delay */, DEFAULT_TINT_ANIMATION_DURATION);
            animateIconTint(mPendingDarkIntensity, 0 /* delay */, getTintAnimationDuration());
        }
        }
        mTransitionPending = false;
        mTransitionPending = false;
    }
    }
@@ -146,8 +154,17 @@ public class LightBarTransitionsController implements Dumpable, Callbacks,
                    Math.max(0, mTransitionDeferringStartTime - SystemClock.uptimeMillis()),
                    Math.max(0, mTransitionDeferringStartTime - SystemClock.uptimeMillis()),
                    mTransitionDeferringDuration);
                    mTransitionDeferringDuration);
        } else {
        } else {
            animateIconTint(dark ? 1.0f : 0.0f, 0 /* delay */, DEFAULT_TINT_ANIMATION_DURATION);
            animateIconTint(dark ? 1.0f : 0.0f, 0 /* delay */, getTintAnimationDuration());
        }
    }

    public long getTintAnimationDuration() {
        if (NavBarTintController.isEnabled(mContext)) {
            return Math.max(Settings.Global.getInt(mContext.getContentResolver(),
                    NAV_COLOR_TRANSITION_TIME_SETTING, DEFAULT_TINT_ANIMATION_DURATION),
                    MIN_COLOR_ADAPT_TRANSITION_TIME);
        }
        }
        return DEFAULT_TINT_ANIMATION_DURATION;
    }
    }


    public float getCurrentDarkIntensity() {
    public float getCurrentDarkIntensity() {
+208 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2018 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.systemui.statusbar.phone;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.Color;
import android.graphics.Rect;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.provider.Settings;
import android.util.DisplayMetrics;
import android.view.SurfaceControl;

public class NavBarTintController {
    public static final String NAV_COLOR_TRANSITION_TIME_SETTING = "navbar_color_adapt_transition";
    public static final int MIN_COLOR_ADAPT_TRANSITION_TIME = 400;

    private final HandlerThread mColorAdaptHandlerThread = new HandlerThread("ColorExtractThread");
    private Handler mColorAdaptionHandler;

    // Poll time for each iteration to color sample
    private static final int COLOR_ADAPTION_TIMEOUT = 300;

    // Passing the threshold of this luminance value will make the button black otherwise white
    private static final float LUMINANCE_THRESHOLD = 0.3f;

    // The home button's icon is actually smaller than the button's size, the percentage will
    // cut into the button's size to determine the icon size
    private static final float PERCENTAGE_BUTTON_PADDING = 0.3f;

    // The distance from the home button to color sample around
    private static final int COLOR_SAMPLE_MARGIN = 20;

    private boolean mRunning;

    private final NavigationBarView mNavigationBarView;
    private final LightBarTransitionsController mLightBarController;
    private final Handler mMainHandler = new Handler(Looper.getMainLooper());

    public NavBarTintController(NavigationBarView navigationBarView,
            LightBarTransitionsController lightBarController) {
        mNavigationBarView = navigationBarView;
        mLightBarController = lightBarController;
    }

    public void start() {
        if (!isEnabled(mNavigationBarView.getContext())) {
            return;
        }
        if (mColorAdaptionHandler == null) {
            mColorAdaptHandlerThread.start();
            mColorAdaptionHandler = new Handler(mColorAdaptHandlerThread.getLooper());
        }
        mColorAdaptionHandler.removeCallbacksAndMessages(null);
        mColorAdaptionHandler.post(this::updateTint);
        mRunning = true;
    }

    public void end() {
        if (mColorAdaptionHandler != null) {
            mColorAdaptionHandler.removeCallbacksAndMessages(null);
        }
        mRunning = false;
    }

    public void stop() {
        end();
        if (mColorAdaptionHandler != null) {
            mColorAdaptHandlerThread.quitSafely();
        }
    }

    private void updateTint() {
        int[] navPos = new int[2];
        int[] butPos = new int[2];
        if (mNavigationBarView.getHomeButton().getCurrentView() == null) {
            return;
        }

        // Determine the area of the home icon in the larger home button
        mNavigationBarView.getHomeButton().getCurrentView().getLocationInSurface(butPos);
        final int navWidth = mNavigationBarView.getHomeButton().getCurrentView().getWidth();
        final int navHeight = mNavigationBarView.getHomeButton().getCurrentView().getHeight();
        final int xPadding = (int) (PERCENTAGE_BUTTON_PADDING * navWidth);
        final int yPadding = (int) (PERCENTAGE_BUTTON_PADDING * navHeight);
        final Rect homeButtonRect = new Rect(butPos[0] + xPadding, butPos[1] + yPadding,
                navWidth + butPos[0]  - xPadding, navHeight + butPos[1] - yPadding);
        if (mNavigationBarView.getCurrentView() == null || homeButtonRect.isEmpty()) {
            scheduleColorAdaption();
            return;
        }
        mNavigationBarView.getCurrentView().getLocationOnScreen(navPos);
        homeButtonRect.offset(navPos[0], navPos[1]);

        // Apply a margin area around the button region to sample the colors, crop from screenshot
        final Rect cropRect = new Rect(homeButtonRect);
        cropRect.inset(-COLOR_SAMPLE_MARGIN, -COLOR_SAMPLE_MARGIN);
        if (cropRect.isEmpty()) {
            scheduleColorAdaption();
            return;
        }

        // Determine the size of the home area
        Rect homeArea = new Rect(COLOR_SAMPLE_MARGIN, COLOR_SAMPLE_MARGIN,
                homeButtonRect.width() + COLOR_SAMPLE_MARGIN,
                homeButtonRect.height() + COLOR_SAMPLE_MARGIN);

        // Get the screenshot around the home button icon to determine the color
        DisplayMetrics mDisplayMetrics = new DisplayMetrics();
        mNavigationBarView.getContext().getDisplay().getRealMetrics(mDisplayMetrics);
        final Bitmap hardBitmap = SurfaceControl
                .screenshot(new Rect(), mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels,
                        mNavigationBarView.getContext().getDisplay().getRotation());
        if (hardBitmap != null && cropRect.bottom <= hardBitmap.getHeight()) {
            final Bitmap cropBitmap = Bitmap.createBitmap(hardBitmap, cropRect.left, cropRect.top,
                    cropRect.width(), cropRect.height());
            final Bitmap softBitmap = cropBitmap.copy(Config.ARGB_8888, false);

            // Get the luminance value to determine if the home button should be black or white
            final int[] pixels = new int[softBitmap.getByteCount() / 4];
            softBitmap.getPixels(pixels, 0, softBitmap.getWidth(), 0, 0, softBitmap.getWidth(),
                    softBitmap.getHeight());
            float r = 0, g = 0, blue = 0;

            int width = cropRect.width();
            int total = 0;
            for (int i = 0; i < pixels.length; i += 4) {
                int x = i % width;
                int y = i / width;
                if (!homeArea.contains(x, y)) {
                    r += Color.red(pixels[i]);
                    g += Color.green(pixels[i]);
                    blue += Color.blue(pixels[i]);
                    total++;
                }
            }

            r /= total;
            g /= total;
            blue /= total;

            r = Math.max(Math.min(r / 255f, 1), 0);
            g = Math.max(Math.min(g / 255f, 1), 0);
            blue = Math.max(Math.min(blue / 255f, 1), 0);

            if (r <= 0.03928) {
                r /= 12.92;
            } else {
                r = (float) Math.pow((r + 0.055) / 1.055, 2.4);
            }
            if (g <= 0.03928) {
                g /= 12.92;
            } else {
                g = (float) Math.pow((g + 0.055) / 1.055, 2.4);
            }
            if (blue <= 0.03928) {
                blue /= 12.92;
            } else {
                blue = (float) Math.pow((blue + 0.055) / 1.055, 2.4);
            }

            if (r * 0.2126 + g * 0.7152 + blue * 0.0722 > LUMINANCE_THRESHOLD) {
                // Black
                mMainHandler.post(
                        () -> mLightBarController
                                .setIconsDark(true /* dark */, true /* animate */));
            } else {
                // White
                mMainHandler.post(
                        () -> mLightBarController
                                .setIconsDark(false /* dark */, true /* animate */));
            }
            cropBitmap.recycle();
            hardBitmap.recycle();
        }
        scheduleColorAdaption();
    }

    private void scheduleColorAdaption() {
        mColorAdaptionHandler.removeCallbacksAndMessages(null);
        if (!mRunning || !isEnabled(mNavigationBarView.getContext())) {
            return;
        }
        mColorAdaptionHandler.postDelayed(this::updateTint, COLOR_ADAPTION_TIMEOUT);
    }

    public static boolean isEnabled(Context context) {
        return Settings.Global.getInt(context.getContentResolver(),
                NavigationPrototypeController.NAV_COLOR_ADAPT_ENABLE_SETTING, 0) == 1;
    }
}
+10 −0
Original line number Original line Diff line number Diff line
@@ -851,6 +851,16 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
            if (Intent.ACTION_SCREEN_OFF.equals(action)
            if (Intent.ACTION_SCREEN_OFF.equals(action)
                    || Intent.ACTION_SCREEN_ON.equals(action)) {
                    || Intent.ACTION_SCREEN_ON.equals(action)) {
                notifyNavigationBarScreenOn();
                notifyNavigationBarScreenOn();

                if (Intent.ACTION_SCREEN_ON.equals(action)) {
                    // Enabled and screen is on, start it again if enabled
                    if (NavBarTintController.isEnabled(getContext())) {
                        mNavigationBarView.getColorAdaptionController().start();
                    }
                } else {
                    // Screen off disable it
                    mNavigationBarView.getColorAdaptionController().end();
                }
            }
            }
            if (Intent.ACTION_USER_SWITCHED.equals(action)) {
            if (Intent.ACTION_USER_SWITCHED.equals(action)) {
                // The accessibility settings may be different for the new user
                // The accessibility settings may be different for the new user
+17 −0
Original line number Original line Diff line number Diff line
@@ -149,6 +149,7 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
    private RecentsOnboarding mRecentsOnboarding;
    private RecentsOnboarding mRecentsOnboarding;
    private NotificationPanelView mPanelView;
    private NotificationPanelView mPanelView;


    private NavBarTintController mColorAdaptionController;
    private NavigationPrototypeController mPrototypeController;
    private NavigationPrototypeController mPrototypeController;
    private NavigationGestureAction[] mDefaultGestureMap;
    private NavigationGestureAction[] mDefaultGestureMap;
    private QuickScrubAction mQuickScrubAction;
    private QuickScrubAction mQuickScrubAction;
@@ -277,6 +278,15 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
        public void onBackButtonVisibilityChanged(boolean visible) {
        public void onBackButtonVisibilityChanged(boolean visible) {
            getBackButton().setVisibility(visible ? VISIBLE : GONE);
            getBackButton().setVisibility(visible ? VISIBLE : GONE);
        }
        }

        @Override
        public void onColorAdaptChanged(boolean enabled) {
            if (enabled) {
                mColorAdaptionController.start();
            } else {
                mColorAdaptionController.end();
            }
        }
    };
    };


    public NavigationBarView(Context context, AttributeSet attrs) {
    public NavigationBarView(Context context, AttributeSet attrs) {
@@ -334,6 +344,11 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
        mPrototypeController = new NavigationPrototypeController(mHandler, mContext);
        mPrototypeController = new NavigationPrototypeController(mHandler, mContext);
        mPrototypeController.register();
        mPrototypeController.register();
        mPrototypeController.setOnPrototypeChangedListener(mPrototypeListener);
        mPrototypeController.setOnPrototypeChangedListener(mPrototypeListener);
        mColorAdaptionController = new NavBarTintController(this, getLightTransitionsController());
    }

    public NavBarTintController getColorAdaptionController() {
        return mColorAdaptionController;
    }
    }


    public BarTransitions getBarTransitions() {
    public BarTransitions getBarTransitions() {
@@ -1097,6 +1112,7 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
        Dependency.get(PluginManager.class).addPluginListener(this,
        Dependency.get(PluginManager.class).addPluginListener(this,
                NavGesture.class, false /* Only one */);
                NavGesture.class, false /* Only one */);
        setUpSwipeUpOnboarding(isQuickStepSwipeUpEnabled());
        setUpSwipeUpOnboarding(isQuickStepSwipeUpEnabled());
        mColorAdaptionController.start();
    }
    }


    @Override
    @Override
@@ -1107,6 +1123,7 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
            mGestureHelper.destroy();
            mGestureHelper.destroy();
        }
        }
        mPrototypeController.unregister();
        mPrototypeController.unregister();
        mColorAdaptionController.stop();
        setUpSwipeUpOnboarding(false);
        setUpSwipeUpOnboarding(false);
        for (int i = 0; i < mButtonDispatchers.size(); ++i) {
        for (int i = 0; i < mButtonDispatchers.size(); ++i) {
            mButtonDispatchers.valueAt(i).onDestroy();
            mButtonDispatchers.valueAt(i).onDestroy();
Loading