/* * Copyright (c) 2014-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ package com.facebook.stetho.inspector.elements.android; import android.annotation.TargetApi; import android.graphics.Canvas; import android.graphics.Rect; import android.graphics.Region; import android.graphics.drawable.ColorDrawable; import android.os.Build; import android.view.View; import android.view.ViewGroup; import android.view.ViewGroup.MarginLayoutParams; abstract class ViewHighlightOverlays { abstract void highlightView(View view, Rect bounds, int mainColor); abstract void removeHighlight(View view); static ViewHighlightOverlays newInstance() { // This may not be needed since ViewHighlighter.newInstance() is already instantiating a // NoopHighlighter for SDK_INT < JELLY_BEAN_MR2, but just to make sure... if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { return new ViewHighlightOverlaysJellybeanMR2(); } return new NoOpViewHighlightOverlays(); } private static class NoOpViewHighlightOverlays extends ViewHighlightOverlays { @Override void highlightView(View view, Rect bounds, int mainColor) { } @Override void removeHighlight(View view) { } } @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2) private static class ViewHighlightOverlaysJellybeanMR2 extends ViewHighlightOverlays { private static final int MARGIN_OVERLAY_COLOR = 0xaaf4ca9e; private static final int PADDING_OVERLAY_COLOR = 0xaabedab6; private final MainHighlightDrawable mMainHighlightDrawable = new MainHighlightDrawable(); private final HighlightDrawable[] mHighlightDrawables = { mMainHighlightDrawable, new PaddingTopHighlightDrawable(), new PaddingBottomHighlightDrawable(), new PaddingRightHighlightDrawable(), new PaddingLeftHighlightDrawable(), new MarginTopHighlightDrawable(), new MarginBottomHighlightDrawable(), new MarginRightHighlightDrawable(), new MarginLeftHighlightDrawable() }; ViewHighlightOverlaysJellybeanMR2() { } @Override void highlightView(View view, Rect bounds, int mainColor) { mMainHighlightDrawable.setColor(mainColor); if (bounds.isEmpty()) { mMainHighlightDrawable.setBounds(0, 0, view.getWidth(), view.getHeight()); } else { mMainHighlightDrawable.setBounds(bounds); } int total = mHighlightDrawables.length; for (int i = 0; i < total; i++) { HighlightDrawable drawable = mHighlightDrawables[i]; drawable.highlightView(view); view.getOverlay().add(drawable); } } @Override void removeHighlight(View view) { for (ColorDrawable drawable : mHighlightDrawables) { view.getOverlay().remove(drawable); } } static abstract class HighlightDrawable extends ColorDrawable { protected final Rect mMargins = new Rect(); protected final Rect mPaddings = new Rect(); HighlightDrawable(int color) { super(color); } public HighlightDrawable() { } void highlightView(View view) { ViewGroup.LayoutParams layoutParams = view.getLayoutParams(); if (layoutParams instanceof MarginLayoutParams) { MarginLayoutParams marginLayoutParams = (MarginLayoutParams) layoutParams; mMargins.left = marginLayoutParams.leftMargin; mMargins.top = marginLayoutParams.topMargin; mMargins.right = marginLayoutParams.rightMargin; mMargins.bottom = marginLayoutParams.bottomMargin; } else { mMargins.left = 0; mMargins.top = 0; mMargins.right = 0; mMargins.bottom = 0; } mPaddings.left = view.getPaddingLeft(); mPaddings.top = view.getPaddingTop(); mPaddings.right = view.getPaddingRight(); mPaddings.bottom = view.getPaddingBottom(); } } static class MainHighlightDrawable extends HighlightDrawable { @Override void highlightView(View view) { super.highlightView(view); } @Override public void draw(Canvas canvas) { // We don't have access to the OverlayViewGroup instance directly, but we can manipulate // its Canvas via the Drawables' draw(). This allows us to draw outside the View bounds, // so we can position the margin overlays correctly. Rect newRect = canvas.getClipBounds(); // Make the Canvas Rect bigger according to the View margins. newRect.inset(-(mMargins.right + mMargins.left), -(mMargins.top + mMargins.bottom)); canvas.clipRect(newRect, Region.Op.REPLACE); super.draw(canvas); } } static class PaddingTopHighlightDrawable extends HighlightDrawable { PaddingTopHighlightDrawable() { super(PADDING_OVERLAY_COLOR); } @Override void highlightView(View view) { super.highlightView(view); setBounds(mPaddings.left, 0, view.getWidth() - mPaddings.right, mPaddings.top); } } static class PaddingBottomHighlightDrawable extends HighlightDrawable { PaddingBottomHighlightDrawable() { super(PADDING_OVERLAY_COLOR); } @Override void highlightView(View view) { super.highlightView(view); setBounds(mPaddings.left, view.getHeight() - mPaddings.bottom, view.getWidth() - mPaddings.right, view.getHeight()); } } static class PaddingRightHighlightDrawable extends HighlightDrawable { PaddingRightHighlightDrawable() { super(PADDING_OVERLAY_COLOR); } @Override void highlightView(View view) { super.highlightView(view); setBounds(view.getWidth() - mPaddings.right, 0, view.getWidth(), view.getHeight()); } } static class PaddingLeftHighlightDrawable extends HighlightDrawable { PaddingLeftHighlightDrawable() { super(PADDING_OVERLAY_COLOR); } @Override void highlightView(View view) { super.highlightView(view); setBounds(0, 0, mPaddings.left, view.getHeight()); } } static class MarginTopHighlightDrawable extends HighlightDrawable { MarginTopHighlightDrawable() { super(MARGIN_OVERLAY_COLOR); } @Override void highlightView(View view) { super.highlightView(view); setBounds(0, 0, view.getWidth(), mMargins.top); } @Override public void draw(Canvas canvas) { canvas.translate(0, -mMargins.top); super.draw(canvas); } } static class MarginBottomHighlightDrawable extends HighlightDrawable { MarginBottomHighlightDrawable() { super(MARGIN_OVERLAY_COLOR); } @Override void highlightView(View view) { super.highlightView(view); setBounds(0, view.getHeight() - mMargins.bottom, view.getWidth(), view.getHeight()); } @Override public void draw(Canvas canvas) { canvas.translate(0, mMargins.bottom + mMargins.top); super.draw(canvas); } } static class MarginRightHighlightDrawable extends HighlightDrawable { MarginRightHighlightDrawable() { super(MARGIN_OVERLAY_COLOR); } @Override void highlightView(View view) { super.highlightView(view); setBounds(view.getWidth() - mMargins.right, 0, view.getWidth(), view.getHeight() + mMargins.top + mMargins.bottom); } @Override public void draw(Canvas canvas) { canvas.translate(mMargins.right, -(mMargins.top + mMargins.bottom)); super.draw(canvas); } } static class MarginLeftHighlightDrawable extends HighlightDrawable { MarginLeftHighlightDrawable() { super(MARGIN_OVERLAY_COLOR); } @Override void highlightView(View view) { super.highlightView(view); setBounds(0, 0, mMargins.left, view.getHeight() + mMargins.top + mMargins.bottom); } @Override public void draw(Canvas canvas) { canvas.translate(-(mMargins.left + mMargins.right), 0); super.draw(canvas); } } } }