summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Winson Chung <winsonc@google.com> 2019-03-13 07:02:52 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2019-03-13 07:02:52 +0000
commitbc52466f9ae3e1f6c15c1f5a7f3d1eedfe2f8154 (patch)
tree054f7beb131611a0e2ff86dd0e6adadc8ebcccbf
parent0869d3ec9b80c8338ee503fad63a2bb60995a3b1 (diff)
parent600c1864854941c96c6d8b92a6b91611a85d3600 (diff)
Merge "Use system composition sampling listener"
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavBarTintController.java262
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java15
3 files changed, 120 insertions, 159 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavBarTintController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavBarTintController.java
index 409d60fa6c17..2d54970cdfa8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavBarTintController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavBarTintController.java
@@ -16,203 +16,159 @@
package com.android.systemui.statusbar.phone;
+import static android.view.Display.DEFAULT_DISPLAY;
+
import android.content.Context;
-import android.content.res.Resources;
-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;
+import android.view.CompositionSamplingListener;
import android.view.View;
-import com.android.systemui.R;
+import java.io.PrintWriter;
+
+/**
+ * Updates the nav bar tint based on the color of the content behind the nav bar.
+ */
+public class NavBarTintController implements View.OnAttachStateChangeListener,
+ View.OnLayoutChangeListener {
-public class NavBarTintController {
public static final int MIN_COLOR_ADAPT_TRANSITION_TIME = 400;
public static final int DEFAULT_COLOR_ADAPT_TRANSITION_TIME = 1700;
- 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 margin from the bounds of the view to color sample around
- private static final int COLOR_SAMPLE_MARGIN = 10;
-
- private boolean mRunning;
-
+ private final Handler mHandler = new Handler();
private final NavigationBarView mNavigationBarView;
private final LightBarTransitionsController mLightBarController;
- private final Handler mMainHandler = new Handler(Looper.getMainLooper());
- private final int mBarRadius;
- private final int mBarBottom;
+
+ private final CompositionSamplingListener mSamplingListener;
+ private final Runnable mUpdateSamplingListener = this::updateSamplingListener;
+ private final Rect mSamplingBounds = new Rect();
+ private boolean mSamplingEnabled = false;
+ private boolean mSamplingListenerRegistered = false;
+
+ private float mLastMediaLuma;
+ private boolean mUpdateOnNextDraw;
public NavBarTintController(NavigationBarView navigationBarView,
LightBarTransitionsController lightBarController) {
+ mSamplingListener = new CompositionSamplingListener(
+ navigationBarView.getContext().getMainExecutor()) {
+ @Override
+ public void onSampleCollected(float medianLuma) {
+ updateTint(medianLuma);
+ }
+ };
mNavigationBarView = navigationBarView;
+ mNavigationBarView.addOnAttachStateChangeListener(this);
+ mNavigationBarView.addOnLayoutChangeListener(this);
mLightBarController = lightBarController;
+ }
- final Resources res = navigationBarView.getResources();
- mBarRadius = res.getDimensionPixelSize(R.dimen.navigation_handle_radius);
- mBarBottom = res.getDimensionPixelSize(R.dimen.navigation_handle_bottom);
+ void onDraw() {
+ if (mUpdateOnNextDraw) {
+ mUpdateOnNextDraw = false;
+ requestUpdateSamplingListener();
+ }
}
- public void start() {
+ 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;
+ mSamplingEnabled = true;
+ // Defer calling updateSamplingListener since we may have just reinflated prior to this
+ requestUpdateSamplingListener();
}
- public void end() {
- if (mColorAdaptionHandler != null) {
- mColorAdaptionHandler.removeCallbacksAndMessages(null);
- }
- mRunning = false;
+ void stop() {
+ mSamplingEnabled = false;
+ requestUpdateSamplingListener();
}
- public void stop() {
- end();
- if (mColorAdaptionHandler != null) {
- mColorAdaptHandlerThread.quitSafely();
- }
+ @Override
+ public void onViewAttachedToWindow(View view) {
+ requestUpdateSamplingListener();
+ }
+
+ @Override
+ public void onViewDetachedFromWindow(View view) {
+ // Defer calling updateSamplingListener the attach info has not yet been reset
+ requestUpdateSamplingListener();
}
- private void updateTint() {
- int[] navPos = new int[2];
- int[] butPos = new int[2];
+ @Override
+ public void onLayoutChange(View v, int left, int top, int right, int bottom,
+ int oldLeft, int oldTop, int oldRight, int oldBottom) {
+ mSamplingBounds.setEmpty();
+ // TODO: Extend this to 2/3 button layout as well
View view = mNavigationBarView.getHomeHandle().getCurrentView();
- if (view == null) {
- return;
+ if (view != null) {
+ int[] pos = new int[2];
+ view.getLocationOnScreen(pos);
+ final Rect samplingBounds = new Rect(pos[0], pos[1],
+ pos[0] + view.getWidth(), pos[1] + view.getHeight());
+ if (!samplingBounds.equals(mSamplingBounds)) {
+ mSamplingBounds.set(samplingBounds);
+ requestUpdateSamplingListener();
+ }
}
+ }
- // Determine the area of the icon within its view bounds
- view.getLocationInSurface(butPos);
- final int navWidth = view.getWidth();
- final int navHeight = view.getHeight();
- int viewBottom = butPos[1] + navHeight - mBarBottom;
- final Rect viewIconRect = new Rect(butPos[0], viewBottom - mBarRadius * 2,
- butPos[0] + navWidth, viewBottom);
+ private void requestUpdateSamplingListener() {
+ mHandler.removeCallbacks(mUpdateSamplingListener);
+ mHandler.post(mUpdateSamplingListener);
+ }
- if (mNavigationBarView.getCurrentView() == null || viewIconRect.isEmpty()) {
- scheduleColorAdaption();
- return;
+ private void updateSamplingListener() {
+ if (mSamplingListenerRegistered) {
+ mSamplingListenerRegistered = false;
+ CompositionSamplingListener.unregister(mSamplingListener);
}
- mNavigationBarView.getCurrentView().getLocationOnScreen(navPos);
- viewIconRect.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(viewIconRect);
- 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,
- viewIconRect.width() + COLOR_SAMPLE_MARGIN,
- viewIconRect.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()
- && cropRect.left + cropRect.width() <= hardBitmap.getWidth()) {
- 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 (mSamplingEnabled && !mSamplingBounds.isEmpty()
+ && mNavigationBarView.isAttachedToWindow()) {
+ if (!mNavigationBarView.getViewRootImpl().getSurfaceControl().isValid()) {
+ // The view may still be attached, but the surface backing the window can be
+ // destroyed, so wait until the next draw to update the listener again
+ mUpdateOnNextDraw = true;
+ return;
}
- 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();
+ mSamplingListenerRegistered = true;
+ CompositionSamplingListener.register(mSamplingListener, DEFAULT_DISPLAY,
+ mNavigationBarView.getViewRootImpl().getSurfaceControl().getHandle(),
+ mSamplingBounds);
}
- scheduleColorAdaption();
}
- private void scheduleColorAdaption() {
- mColorAdaptionHandler.removeCallbacksAndMessages(null);
- if (!mRunning || !isEnabled(mNavigationBarView.getContext())) {
- return;
+ private void updateTint(float medianLuma) {
+ mLastMediaLuma = medianLuma;
+ if (medianLuma > LUMINANCE_THRESHOLD) {
+ // Black
+ mLightBarController.setIconsDark(true /* dark */, true /* animate */);
+ } else {
+ // White
+ mLightBarController.setIconsDark(false /* dark */, true /* animate */);
}
- mColorAdaptionHandler.postDelayed(this::updateTint, COLOR_ADAPTION_TIMEOUT);
+ }
+
+ void dump(PrintWriter pw) {
+ pw.println("NavBarTintController:");
+ pw.println(" navBar isAttached: " + mNavigationBarView.isAttachedToWindow());
+ pw.println(" navBar isScValid: " + (mNavigationBarView.isAttachedToWindow()
+ ? mNavigationBarView.getViewRootImpl().getSurfaceControl().isValid()
+ : "false"));
+ pw.println(" mSamplingListenerRegistered: " + mSamplingListenerRegistered);
+ pw.println(" mSamplingBounds: " + mSamplingBounds);
+ pw.println(" mLastMediaLuma: " + mLastMediaLuma);
}
public static boolean isEnabled(Context context) {
- return Settings.Global.getInt(context.getContentResolver(),
- NavigationPrototypeController.NAV_COLOR_ADAPT_ENABLE_SETTING, 0) == 1
- && Settings.Global.getInt(context.getContentResolver(),
- NavigationPrototypeController.SHOW_HOME_HANDLE_SETTING, 0) == 1;
+ return context.getDisplayId() == DEFAULT_DISPLAY
+ && Settings.Global.getInt(context.getContentResolver(),
+ NavigationPrototypeController.NAV_COLOR_ADAPT_ENABLE_SETTING, 0) == 1
+ && Settings.Global.getInt(context.getContentResolver(),
+ NavigationPrototypeController.SHOW_HOME_HANDLE_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 b68c7c679d1c..09789019d6ef 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -991,7 +991,7 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
}
} else {
// Screen off disable it
- mNavigationBarView.getColorAdaptionController().end();
+ mNavigationBarView.getColorAdaptionController().stop();
}
}
if (Intent.ACTION_USER_SWITCHED.equals(action)) {
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 b540fb49af01..a64ff0fce73c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -333,7 +333,7 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
if (enabled) {
mColorAdaptionController.start();
} else {
- mColorAdaptionController.end();
+ mColorAdaptionController.stop();
}
}
@@ -486,6 +486,12 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
}
}
+ @Override
+ protected void dispatchDraw(Canvas canvas) {
+ super.dispatchDraw(canvas);
+ mColorAdaptionController.onDraw();
+ }
+
private void updateNavigationGestures() {
if (mGestureHelper instanceof QuickStepController) {
final int[] assignedMap = mPrototypeController.getGestureActionMap();
@@ -990,7 +996,7 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
if (visible) {
mColorAdaptionController.start();
} else {
- mColorAdaptionController.end();
+ mColorAdaptionController.stop();
}
}
@@ -1244,7 +1250,7 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
mColorAdaptionController.start();
} else {
- mColorAdaptionController.end();
+ mColorAdaptionController.stop();
}
}
@@ -1330,7 +1336,6 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
Dependency.get(PluginManager.class).addPluginListener(this,
NavGesture.class, false /* Only one */);
setUpSwipeUpOnboarding(isQuickStepSwipeUpEnabled());
- mColorAdaptionController.start();
if (mPrototypeController.isEnabled()) {
WindowManager wm = (WindowManager) getContext()
@@ -1363,7 +1368,6 @@ 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();
@@ -1454,6 +1458,7 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
mGestureHelper.dump(pw);
}
mRecentsOnboarding.dump(pw);
+ mColorAdaptionController.dump(pw);
}
@Override