/* * Copyright (C) 2015 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.tools.idea.editors.theme.widgets; import com.android.ide.common.rendering.api.LayoutLog; import com.android.layoutlib.bridge.Bridge; import android.content.Context; import android.graphics.Canvas; import android.util.AttributeSet; import android.view.View; import android.view.ViewGroup; /** * {@link ViewGroup} that wraps another view and catches any possible exceptions that the child view * might generate. * This is used by the theme editor to stop custom views from breaking the preview. */ // TODO: This view is just a temporary solution that will be replaced by adding a try / catch // for custom views in the ClassConverter public class ErrorCatcher extends ViewGroup { public ErrorCatcher(Context context) { super(context); } public ErrorCatcher(Context context, AttributeSet attrs) { super(context, attrs); } public ErrorCatcher(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } public ErrorCatcher(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { assert getChildCount() == 1 : "ErrorCatcher can only have one child"; View child = getChildAt(0); try { measureChild(child, widthMeasureSpec, heightMeasureSpec); setMeasuredDimension(resolveSize(child.getMeasuredWidth(), widthMeasureSpec), resolveSize(child.getMeasuredHeight(), heightMeasureSpec)); } catch (Throwable t) { Bridge.getLog().warning(LayoutLog.TAG_BROKEN, "Failed to do onMeasure for view " + child.getClass().getCanonicalName(), t); setMeasuredDimension(resolveSize(0, widthMeasureSpec), resolveSize(0, heightMeasureSpec)); } } @Override protected boolean drawChild(Canvas canvas, View child, long drawingTime) { try { return super.drawChild(canvas, child, drawingTime); } catch (Throwable t) { Bridge.getLog().warning(LayoutLog.TAG_BROKEN, "Failed to draw for view " + child.getClass().getCanonicalName(), t); } return false; } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { assert getChildCount() == 1 : "ErrorCatcher can only have one child"; View child = getChildAt(0); try { child.layout(0, 0, child.getMeasuredWidth(), child.getMeasuredHeight()); } catch (Throwable e) { Bridge.getLog().warning(LayoutLog.TAG_BROKEN, "Failed to do onLayout for view " + child.getClass().getCanonicalName(), e); } } }