diff options
| author | 2019-03-13 07:02:52 +0000 | |
|---|---|---|
| committer | 2019-03-13 07:02:52 +0000 | |
| commit | bc52466f9ae3e1f6c15c1f5a7f3d1eedfe2f8154 (patch) | |
| tree | 054f7beb131611a0e2ff86dd0e6adadc8ebcccbf | |
| parent | 0869d3ec9b80c8338ee503fad63a2bb60995a3b1 (diff) | |
| parent | 600c1864854941c96c6d8b92a6b91611a85d3600 (diff) | |
Merge "Use system composition sampling listener"
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 |