/******************************************************************************* * Copyright (c) 2011 Adam Shanks (ChainsDD) * * 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.noshufou.android.su.widget; import android.content.Context; import android.content.res.Resources; import android.graphics.Canvas; import android.graphics.Typeface; import android.graphics.drawable.Drawable; import android.text.TextUtils; import android.text.TextUtils.TruncateAt; import android.util.AttributeSet; import android.view.Gravity; import android.view.View; import android.view.ViewGroup; import android.widget.Checkable; import android.widget.ImageView; import android.widget.TextView; import android.widget.ImageView.ScaleType; import com.noshufou.android.su.R; public class AppListItem extends ViewGroup implements Checkable { // private static final String TAG = "Su.AppListItem"; private final Context mContext; private final int mPreferredHeight; private final int mPaddingTop; private final int mPaddingRight; private final int mPaddingBottom; private final int mPaddingLeft; private final int mIconViewSize; private final int mGapBetweenImageAndText; private final int mHeaderPaddingLeft; private boolean mChecked = false; private boolean mHorizontalDividerVisible; private Drawable mHorizontalDividerDrawable; private int mHorizontalDividerHeight; private boolean mHeaderVisible; private Drawable mHeaderBackgroundDrawable; private int mHeaderBackgroundHeight; private TextView mHeaderTextView; private ImageView mIconView; private TextView mNameTextView; private TextView mLogTextView; private ImageView mStatusButton; private int mLine1Height; private int mLine2Height; public AppListItem(Context context, AttributeSet attrs) { super(context, attrs); mContext = context; Resources resources = context.getResources(); mPreferredHeight = resources.getDimensionPixelSize(R.dimen.list_item_perferred_height); mPaddingTop = resources.getDimensionPixelSize(R.dimen.list_item_padding_top); mPaddingBottom = resources.getDimensionPixelSize(R.dimen.list_item_padding_bottom); mPaddingLeft = resources.getDimensionPixelSize(R.dimen.list_item_padding_left); mPaddingRight = resources.getDimensionPixelSize(R.dimen.list_item_padding_right); mIconViewSize = resources.getDimensionPixelSize(R.dimen.list_item_icon_size); mGapBetweenImageAndText = resources.getDimensionPixelSize(R.dimen.list_item_gap_between_image_and_text); mHeaderPaddingLeft = resources.getDimensionPixelSize(R.dimen.list_item_header_padding_left); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int width = resolveSize(0, widthMeasureSpec); int height = 0; mLine1Height = 0; mLine2Height = 0; mNameTextView.measure(0, 0); mLine1Height = mNameTextView.getMeasuredHeight(); if (isVisible(mLogTextView)) { mLogTextView.measure(0, 0); mLine2Height = mLogTextView.getMeasuredHeight(); } height += mLine1Height + mLine2Height; if (isVisible(mStatusButton)) { mStatusButton.measure(0, 0); } height = Math.max(height, mPreferredHeight); if (mHeaderVisible) { ensureHeaderBackground(); mHeaderTextView.measure( MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(mHeaderBackgroundHeight, MeasureSpec.EXACTLY)); height += mHeaderBackgroundDrawable.getIntrinsicHeight(); } setMeasuredDimension(width, height); } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { int height = bottom - top; int width = right - left; int topBound = 0; if (mHeaderVisible) { mHeaderBackgroundDrawable.setBounds( 0, 0, width, mHeaderBackgroundHeight); mHeaderTextView.layout(mHeaderPaddingLeft, 0, width, mHeaderBackgroundHeight); topBound += mHeaderBackgroundHeight; } if (mHorizontalDividerVisible) { ensureHorizontalDivider(); mHorizontalDividerDrawable.setBounds( 0, height - mHorizontalDividerHeight, width, height); } int leftBound = mPaddingLeft; int rightBound = right; if (mIconView != null) { int iconTop = topBound + (height - topBound - mIconViewSize) / 2; mIconView.layout( leftBound, iconTop, leftBound + mIconViewSize, iconTop + mIconViewSize); leftBound += mIconViewSize + mGapBetweenImageAndText; } topBound += mPaddingTop; topBound += mPaddingTop; int bottomBound = height - mPaddingBottom; rightBound -= mPaddingRight; int line1RightBound = rightBound; int totalTextHeight = mLine1Height + mLine2Height; int textTopBound = (bottomBound + topBound - totalTextHeight) / 2; if (isVisible(mStatusButton)) { int buttonWidth = mStatusButton.getMeasuredWidth(); line1RightBound -= buttonWidth; mStatusButton.layout( rightBound - buttonWidth, textTopBound, rightBound, textTopBound + mLine1Height); } mNameTextView.layout( leftBound, textTopBound, line1RightBound - mGapBetweenImageAndText, textTopBound + mLine1Height); if (isVisible(mLogTextView)) { mLogTextView.layout( leftBound, textTopBound + mLine1Height, rightBound, textTopBound + mLine1Height + mLine2Height); } } private boolean isVisible(View view) { return view != null && view.getVisibility() == View.VISIBLE; } public void setHorizontalDivider(int res) { mHorizontalDividerDrawable = mContext.getResources().getDrawable(res); mHorizontalDividerHeight = mHorizontalDividerDrawable.getIntrinsicHeight(); } /** * Loads the drawable for the horizontal divider if it has not yet been loaded. */ private void ensureHorizontalDivider() { if (mHorizontalDividerDrawable == null) { mHorizontalDividerDrawable = mContext.getResources().getDrawable( R.drawable.app_list_divider); mHorizontalDividerHeight = mHorizontalDividerDrawable.getIntrinsicHeight(); } } public void setHeaderBackground(int res) { mHeaderBackgroundDrawable = mContext.getResources().getDrawable(res); mHeaderBackgroundHeight = mHeaderBackgroundDrawable.getIntrinsicHeight(); } /** * Loads the drawable for the header background if it has not yet been loaded. */ private void ensureHeaderBackground() { if (mHeaderBackgroundDrawable == null) { mHeaderBackgroundDrawable = mContext.getResources().getDrawable( R.drawable.app_list_header); mHeaderBackgroundHeight = mHeaderBackgroundDrawable.getIntrinsicHeight(); } } @Override public void dispatchDraw(Canvas canvas) { if (mHeaderVisible) { mHeaderBackgroundDrawable.draw(canvas); } if (mHorizontalDividerVisible) { mHorizontalDividerDrawable.draw(canvas); } super.dispatchDraw(canvas); } /** * Sets the flag that determines whether a divider should be drawn at the bottom * of the view. */ public void setDividerVisible(boolean visible) { mHorizontalDividerVisible = visible; } /** * Sets section header or makes it invisible if the title is null. */ public void setSectionHeader(String title) { if (!TextUtils.isEmpty(title)) { if (mHeaderTextView == null) { mHeaderTextView = new TextView(mContext); mHeaderTextView.setTypeface(mHeaderTextView.getTypeface(), Typeface.BOLD); mHeaderTextView.setTextColor(mContext.getResources() .getColor(R.color.dim_foreground_light)); mHeaderTextView.setTextSize(14); mHeaderTextView.setGravity(Gravity.LEFT|Gravity.CENTER_VERTICAL); addView(mHeaderTextView); } mHeaderTextView.setText(title); mHeaderTextView.setVisibility(View.VISIBLE); mHeaderVisible = true; } else { if (mHeaderTextView != null) { mHeaderTextView.setVisibility(View.GONE); } mHeaderVisible = false; } } /** * Returns the text view for the app name, creating it if necessary. */ public void setNameText(CharSequence text) { if (!TextUtils.isEmpty(text)) { if (mNameTextView == null) { mNameTextView = new TextView(mContext); mNameTextView.setSingleLine(true); mNameTextView.setEllipsize(TruncateAt.END); mNameTextView.setTextAppearance(mContext, android.R.style.TextAppearance_Large); mNameTextView.setGravity(Gravity.CENTER_VERTICAL); addView(mNameTextView); } mNameTextView.setText(text); mNameTextView.setVisibility(View.VISIBLE); } else { if (mNameTextView != null) { mNameTextView.setVisibility(View.GONE); } } } /** * Adds or updates a text view for log information. */ public void setLogText(CharSequence text) { if (!TextUtils.isEmpty(text)) { if (mLogTextView == null) { mLogTextView = new TextView(mContext); mLogTextView.setSingleLine(true); mLogTextView.setEllipsize(TruncateAt.END); mLogTextView.setTextAppearance(mContext, android.R.style.TextAppearance_Small); addView(mLogTextView); } mLogTextView.setText(text); mLogTextView.setVisibility(View.VISIBLE); } else { if (mLogTextView != null) { mLogTextView.setVisibility(View.GONE); } } } /** * Sets the app icon, creating it if necessary. */ public void setAppIcon(Drawable icon) { if (icon != null) { if (mIconView == null) { mIconView = new ImageView(mContext); addView(mIconView); } mIconView.setImageDrawable(icon); mIconView.setVisibility(View.VISIBLE); } else { if (mIconView != null) { mIconView.setVisibility(View.GONE); } } } /** * Sets up the status icon, creating it if necessary. */ public void setStatusButton(Drawable icon, int id, long appId) { if (icon != null) { if (mStatusButton == null) { mStatusButton = new ImageView(mContext); mStatusButton.setId(id); mStatusButton.setScaleType(ScaleType.CENTER); addView(mStatusButton); } mStatusButton.setImageDrawable(icon); mStatusButton.setTag(appId); mStatusButton.setVisibility(View.VISIBLE); } else { if (mStatusButton != null) { mStatusButton.setVisibility(View.GONE); } } } @Override public boolean isChecked() { return mChecked; } @Override public void setChecked(boolean checked) { mChecked = checked; setBackgroundResource(checked?R.drawable.list_activated:android.R.color.transparent); } @Override public void toggle() { setChecked(!mChecked); } }