summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java23
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavBarTintController.java208
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationPrototypeController.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java5
7 files changed, 272 insertions, 5 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java
index e0c5516417ba..1e00da5ad962 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java
@@ -76,11 +76,14 @@ public class LightBarController implements BatteryController.BatteryStateChangeC
private final Rect mLastDockedBounds = new Rect();
private boolean mQsCustomizing;
+ private final Context mContext;
+
public LightBarController(Context ctx) {
mDarkModeColor = Color.valueOf(ctx.getColor(R.color.dark_mode_icon_color_single_tone));
mStatusBarIconController = Dependency.get(DarkIconDispatcher.class);
mBatteryController = Dependency.get(BatteryController.class);
mBatteryController.addCallback(this);
+ mContext = ctx;
}
public void setNavigationBar(LightBarTransitionsController navigationBar) {
@@ -217,8 +220,9 @@ public class LightBarController implements BatteryController.BatteryStateChangeC
private void updateNavigation() {
if (mNavigationBarController != null) {
- mNavigationBarController.setIconsDark(
- mNavigationLight, animateChange());
+ if (!NavBarTintController.isEnabled(mContext)) {
+ mNavigationBarController.setIconsDark(mNavigationLight, animateChange());
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java
index 57cc7d6c1ecb..7876aa5d89d0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java
@@ -16,12 +16,16 @@
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.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.os.SystemClock;
import android.util.MathUtils;
+import android.provider.Settings;
import android.util.TimeUtils;
import com.android.systemui.Dependency;
@@ -42,13 +46,14 @@ import java.io.PrintWriter;
public class LightBarTransitionsController implements Dumpable, Callbacks,
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 final Handler mHandler;
private final DarkIntensityApplier mApplier;
private final KeyguardMonitor mKeyguardMonitor;
private final StatusBarStateController mStatusBarStateController;
+ private NavBarTintController mColorAdaptionController;
private boolean mTransitionDeferring;
private long mTransitionDeferringStartTime;
@@ -67,6 +72,8 @@ public class LightBarTransitionsController implements Dumpable, Callbacks,
}
};
+ private final Context mContext;
+
public LightBarTransitionsController(Context context, DarkIntensityApplier applier) {
mApplier = applier;
mHandler = new Handler();
@@ -76,6 +83,7 @@ public class LightBarTransitionsController implements Dumpable, Callbacks,
.addCallback(this);
mStatusBarStateController.addCallback(this);
mDozeAmount = mStatusBarStateController.getDozeAmount();
+ mContext = context;
}
public void destroy(Context context) {
@@ -106,7 +114,7 @@ public class LightBarTransitionsController implements Dumpable, Callbacks,
public void appTransitionCancelled() {
if (mTransitionPending && mTintChangePending) {
mTintChangePending = false;
- animateIconTint(mPendingDarkIntensity, 0 /* delay */, DEFAULT_TINT_ANIMATION_DURATION);
+ animateIconTint(mPendingDarkIntensity, 0 /* delay */, getTintAnimationDuration());
}
mTransitionPending = false;
}
@@ -146,8 +154,17 @@ public class LightBarTransitionsController implements Dumpable, Callbacks,
Math.max(0, mTransitionDeferringStartTime - SystemClock.uptimeMillis()),
mTransitionDeferringDuration);
} 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() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavBarTintController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavBarTintController.java
new file mode 100644
index 000000000000..9ecee1825f07
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavBarTintController.java
@@ -0,0 +1,208 @@
+/*
+ * 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;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
index ae0a1452905d..55655d5b6240 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -851,6 +851,16 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
if (Intent.ACTION_SCREEN_OFF.equals(action)
|| Intent.ACTION_SCREEN_ON.equals(action)) {
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)) {
// The accessibility settings may be different for the new user
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 30e840926698..6a7983af862d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -149,6 +149,7 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
private RecentsOnboarding mRecentsOnboarding;
private NotificationPanelView mPanelView;
+ private NavBarTintController mColorAdaptionController;
private NavigationPrototypeController mPrototypeController;
private NavigationGestureAction[] mDefaultGestureMap;
private QuickScrubAction mQuickScrubAction;
@@ -277,6 +278,15 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
public void onBackButtonVisibilityChanged(boolean visible) {
getBackButton().setVisibility(visible ? VISIBLE : GONE);
}
+
+ @Override
+ public void onColorAdaptChanged(boolean enabled) {
+ if (enabled) {
+ mColorAdaptionController.start();
+ } else {
+ mColorAdaptionController.end();
+ }
+ }
};
public NavigationBarView(Context context, AttributeSet attrs) {
@@ -334,6 +344,11 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
mPrototypeController = new NavigationPrototypeController(mHandler, mContext);
mPrototypeController.register();
mPrototypeController.setOnPrototypeChangedListener(mPrototypeListener);
+ mColorAdaptionController = new NavBarTintController(this, getLightTransitionsController());
+ }
+
+ public NavBarTintController getColorAdaptionController() {
+ return mColorAdaptionController;
}
public BarTransitions getBarTransitions() {
@@ -1097,6 +1112,7 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
Dependency.get(PluginManager.class).addPluginListener(this,
NavGesture.class, false /* Only one */);
setUpSwipeUpOnboarding(isQuickStepSwipeUpEnabled());
+ mColorAdaptionController.start();
}
@Override
@@ -1107,6 +1123,7 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
mGestureHelper.destroy();
}
mPrototypeController.unregister();
+ mColorAdaptionController.stop();
setUpSwipeUpOnboarding(false);
for (int i = 0; i < mButtonDispatchers.size(); ++i) {
mButtonDispatchers.valueAt(i).onDestroy();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationPrototypeController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationPrototypeController.java
index b11b6d472713..40ac79376b06 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationPrototypeController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationPrototypeController.java
@@ -37,6 +37,7 @@ public class NavigationPrototypeController extends ContentObserver {
static final String NAVBAR_EXPERIMENTS_DISABLED = "navbarexperiments_disabled";
private final String GESTURE_MATCH_SETTING = "quickstepcontroller_gesture_match_map";
+ public static final String NAV_COLOR_ADAPT_ENABLE_SETTING = "navbar_color_adapt_enable";
@Retention(RetentionPolicy.SOURCE)
@IntDef({ACTION_DEFAULT, ACTION_QUICKSTEP, ACTION_QUICKSCRUB, ACTION_BACK})
@@ -73,6 +74,7 @@ public class NavigationPrototypeController extends ContentObserver {
public void register() {
registerObserver(HIDE_BACK_BUTTON_SETTING);
registerObserver(GESTURE_MATCH_SETTING);
+ registerObserver(NAV_COLOR_ADAPT_ENABLE_SETTING);
}
/**
@@ -96,6 +98,9 @@ public class NavigationPrototypeController extends ContentObserver {
} else if (path.endsWith(HIDE_BACK_BUTTON_SETTING)) {
mListener.onBackButtonVisibilityChanged(
!getGlobalBool(HIDE_BACK_BUTTON_SETTING));
+ } else if (path.endsWith(NAV_COLOR_ADAPT_ENABLE_SETTING)) {
+ mListener.onColorAdaptChanged(
+ NavBarTintController.isEnabled(mContext));
}
} catch (SettingNotFoundException e) {
e.printStackTrace();
@@ -138,5 +143,6 @@ public class NavigationPrototypeController extends ContentObserver {
public interface OnPrototypeChangedListener {
void onGestureRemap(@GestureAction int[] actions);
void onBackButtonVisibilityChanged(boolean visible);
+ void onColorAdaptChanged(boolean enabled);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 1d6a1e81246c..78249ec44b33 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -2225,6 +2225,11 @@ public class StatusBar extends SystemUI implements DemoMode,
mNavigationBar.getBarTransitions().setAutoDim(false);
}
mHandler.removeCallbacks(mAutoDim);
+
+ // Do not dim the navigation buttons if the its tint is controlled by the bar's background
+ if (NavBarTintController.isEnabled(mContext)) {
+ return;
+ }
if (mState != StatusBarState.KEYGUARD && mState != StatusBarState.SHADE_LOCKED) {
mHandler.postDelayed(mAutoDim, AUTOHIDE_TIMEOUT_MS);
}