android custom component

android logo

I recently created an android custom component. To get started, I simply wanted to use the android framework’s CheckedTextView as the starting point. This is because I had an existing project having walked through a tutorial video on safari.oreilly.com. In the tutorial, CheckedTextView was used to create a custom list item for a ListView. I wanted to change the list item to replace the checkbox with something else.

How hard could it be?

I cloned the framework source code

git clone git://android.git.kernel.org/platform/frameworks/base.git

extracted the class’ source,

~/base/core/java/android/widget/CheckedTextView.java

and created a new class with the CheckedTextView source and changed the package name.

package com.example.proj.widget;
    ⋮
public CheckedTextView(
  Context context, AttributeSet attrs, int defStyle) {
    ⋮
}

I had four problems to solve just to get the class to compile.

  1. import
  2. initialization
  3. constructor
  4. superclass

Problem 1: import

// ERROR: The import com.android.internal.R cannot be resolved
import com.android.internal.R;

Solution 1:

You cannot import the internal android class. But you will need both android’s public R class and your own project’s R class. Remove the internal import.

// Okay!
//import com.android.internal.R;

Problem 2: initialization

private static final int[] CHECKED_STATE_SET = {
  // ERROR: R cannot be resolved
  R.attr.state_checked
};

Solution 2:

Provide the android namespace for R.

private static final int[] CHECKED_STATE_SET = {
  // Okay!
  android.R.attr.state_checked
};

Problem 3: constructor

public CheckedTextView(
  Context context, AttributeSet attrs, int defStyle) {

    super(context, attrs, defStyle);

    TypedArray a = context.obtainStyledAttributes(
      attrs,
      // ERROR: R.styleable cannot be resolved
      R.styleable.CheckedTextView,
      defStyle, 0);

    Drawable d = a.getDrawable(
      // ERROR: R.styleable cannot be resolved
      R.styleable.CheckedTextView_checkMark);

    if (d != null) {
        setCheckMarkDrawable(d);
    }

    boolean checked = a.getBoolean(
      // ERROR: R.styleable cannot be resolved
      R.styleable.CheckedTextView_checked,
      false);

    setChecked(checked);
    a.recycle();
}

Solution 3:

In the android source files, check and checkMark attributes are publicly defined by android so they’re okay.

~/base/core/res/res/values/public.xml
<resources>
  <!--
    ⋮
    -->
  <publictype="attr"name="checked"id="0x01010106"/>
  <publictype="attr"name="button"id="0x01010107"/>
  <publictype="attr"name="checkMark"id="0x01010108"/>
  <!--
    ⋮
    -->
</resources>

CheckedTextView is defined by android but it is not available for import!

~/base/core/res/res/values/attrs.xml
<resources>
  <!--
    ⋮
    -->
  <declare-styleable name="CheckedTextView">
    <!-- Indicates the initial checked state of this text. -->
    <attr name="checked" />
    <!-- Drawable used for the check mark graphic. -->
    <attr name="checkMark" format="reference" />
  </declare-styleable>
  <!--
    ⋮
    -->
</resources>

The solution is to fetch pull the styleable definition out of the android source code and place in your own XML file.

In your eclipse project, create (or update) the XML file res/values/attrs.xml

<resources>
  <declare-styleable name="MyCheckedTextView">
    <attr name="android:checked" />
    <attr name="android:checkMark" />
  </declare-styleable>
</resources>

I belive that the local filename isn’t relevant but all the examples I saw used attrs.xml. The attribute names need the android: prefix as they have already been defined in the framework.

Notice that in my custom attrs.xml file, I didn’t include the format attribute on android:checkMark. This is because checkMark has already been defined in the framework; we are just referencing it here.

Since this is a custom definition, I changed the name of my class to MyCheckedTextView (and, of course, changed the constructor names accordingly.)

// old class declaration
public class CheckedTextView extends TextView implements Checkable {
// new class declaration
public class MyCheckedTextView extends TextView implements Checkable {

Finally, change the constructor code to use your project’s R class rather than android’s R class.

public MyCheckedTextView(
  Context context, AttributeSet attrs, int defStyle) {

    super(context, attrs, defStyle);

    TypedArray a = context.obtainStyledAttributes(
      attrs,
      // Okay!
      com.example.proj.R.styleable.MyCheckedTextView,
      defStyle, 0);

    Drawable d = a.getDrawable(
      // Okay!
      com.example.proj.R.styleable.MyCheckedTextView_checkMark);

    if (d != null) {
        setCheckMarkDrawable(d);
    }

    boolean checked = a.getBoolean(
      // Okay!
      com.example.proj.R.styleable.MyCheckedTextView_checked,
      false);

    setChecked(checked);
    a.recycle();
}

Problem 4: superclass

mPaddingRight is a protected field in the View class. For some reason, it isn’t visible.


    mCheckMarkWidth = d.getIntrinsicWidth();
    // ERROR: mPaddingRight cannot be resolved
    mPaddingRight = mCheckMarkWidth + mBasePaddingRight;
    d.setState(getDrawableState());
  } else {
    // ERROR: mPaddingRight cannot be resolved
    mPaddingRight = mBasePaddingRight;
  }
  mCheckMarkDrawable = d;
  requestLayout();
}

@Override
public void setPadding(
  int left, int top, int right, int bottom) {
  super.setPadding(left, top, right, bottom);
  // ERROR: mPaddingRight cannot be resolved
  mBasePaddingRight = mPaddingRight;
}

Solution 4:

The superclass has a getter available but no setter. Use super’s getter and create a local setter that wraps super’s more generic setPadding method.

public void setCheckMarkDrawable(Drawable d) {
  if (mCheckMarkDrawable != null) {
    mCheckMarkDrawable.setCallback(null);
    unscheduleDrawable(mCheckMarkDrawable);
  }
  if (d != null) {
    d.setCallback(this);
    d.setVisible(getVisibility() == VISIBLE, false);
    d.setState(CHECKED_STATE_SET);
    setMinHeight(d.getIntrinsicHeight());
        
    mCheckMarkWidth = d.getIntrinsicWidth();
    // Okay!
    setPaddingRight(mCheckMarkWidth + mBasePaddingRight);
      d.setState(getDrawableState());
  } else {
    // Okay!
    setPaddingRight(mBasePaddingRight);
  }
  mCheckMarkDrawable = d;
  requestLayout();
}
    
// setPadding(
//     leftPadding   >= 0 ? leftPadding   : mPaddingLeft,
//     topPadding    >= 0 ? topPadding    : mPaddingTop,
//     rightPadding  >= 0 ? rightPadding  : mPaddingRight,
//     bottomPadding >= 0 ? bottomPadding : mPaddingBottom
// );
private void setPaddingRight(int padding) {
  //  Update: use super's setter
  //  or right padding will be screwed up 
  //  setPadding(0, 0, padding, 0);
  super.setPadding(0, 0, padding, 0);
}

@Override
public void setPadding(
  int left, int top, int right, int bottom) {
  super.setPadding(left, top, right, bottom);

  // Okay!
  mBasePaddingRight = getPaddingRight();
}

It now compiles. The checkbox doesn’t render in exactly the same place as does the actual android version of CheckedTextView. I suspect that the source code from the git repository doesn’t correspond with the SDK. Everything functions but the right padding is off. Update: fixed, see problem 4.

I couldn’t have done this without help from those who’ve gone before:

  • How do I use obtainStyledAttributes(int []) with internal Themes of Android stackoverflow
  • Android Hello, Gallery tutorial — “R.styleable cannot be resolved” stackoverflow
  • Declaring a custom android UI element using XML stackoverflow
  • How to retrieve XML attribute for custom control stackoverflow

MCPO Rich Dowdy, 1934 – 2010

Master Chief Petty Officer, Gas Turbine System Technician

It is with heavy heart that I say farewell to Master Chief Petty Officer Rich Dowdy. He passed Thursday, September 2, 2010 at the U.S. Naval Hospital at Balboa.

I married into the family thirteen years ago. The first time I met Rich Dowdy, he gave me the hairy eyeball. Somehow I passed muster, even if I was an old Army soldier. In time, I was accepted into the family.

Rich was a helluva fishing buddy. We could fish all day and not say a word. He and I agreed on most of the important things in life except the Army-Navy game (which we simply didn’t mention).

Below is a picture of Rich and me on the USS Midway and one of the very few pictures in which he is smiling. I know the ladders were hell on his knees that day but he wouldn’t let anyone know it. He was like that. Down in the engine room, Rich’s eyes simply lit up. Being something of a gearhead myself, I could have stayed all day while the Master Chief gave me a personal tour. This was sacred ground, the heart and soul of a great ship.

Rich Dowdy was a sailor who held firmly the line, a family man who did more than most, and a friend who shall evermore be missed. I’ll see you again on the far shore, Rich.

Fair winds and following seas.

Master Chief Petty Officer Rich Dowdy on the USS Midway

eight sides open

haiku: watchful dragonfly, sits calmly upon a reed, open on eight sides

An expression piece from my ITP GLBM7600 Intro to Transpersonal Theory class. I thought of it again yesterday while in another class. BTW, ‘eight sides open’ refers to a state of panoramic awareness. Though eight sides open has been described in many cultures, I draw upon the tradition of Musashi. The dragonfly shows utter equanimity and absolute awareness.

MIT 9.00

open yale logo

I recently finished Paul Bloom’s intro psych course and thought I’d continue my survey with Jeremy Wolfe’s MIT 9.00: Introduction to Psychology. I’m only two lectures in and already I sense Dr. Wolfe’s class has heavier technical leanings. That’s not a bad thing. To read broadly expands awareness.

I tried comparing the syllabi from Yale and MIT. There is some overlap but there is far more unique content than not. At least that’s my impression comparing the two sets of reading assignments. I’ll know more when I finish the balance of the 23 lectures.

So far, I’m pleased. Dr. Bloom has a speaking style that stands apart; he is a hard act to follow. Listening to another lecturer rehash the same syllabus would invite comparison on delivery rather than on content. Happily, this isn’t the case. Even when discussing common material, the lecturers maintain unique courses. As an example, both lecturers talk about Thorndike’s work with cats and puzzle boxes. Even though they talk about the same experiment, the context created by the speakers gives each of their respective lectures a different cast.

loyal and gentle friend

Truffles, my sitting partner

Truffles (1996 – 2010)
Loyal and Gentle Friend

“Look in my eyes, Lord, and my sins
will play out on them as on a screen.
Read them all.

Forgive what you can, and send
me on my path. I will walk on,
until you bid me rest.”
—Shepherd Book

Ten Apple Announcements That Would Not Disappoint

wwdc2010 badge

There are a lot of haters out there but I’m still rooting for Apple. I want Apple to succeed. I’m not going to WWDC 2010 (tapped out of conference budget).

I wish I were going.

Job’s “you won’t be disappointed” promise has my head spinning. I like surprises. I hope Apple doesn’t disappoint.

So, what would I like to see announced? Here’s my top ten list of wishful thinking.

1. CloudWorks

I liked iTools until it became NotFree and then MobileMe. It just seemed regressive in the age of free online calendars and email. I guess I’ve never gotten over it.

I’d like to see MobileMe move to CloudWorks, a name I made up to describe the mythical Apple Cloud.

iLife

MobileMe backs iLife right now. There are a few issues to solve when iLife is backed by CloudWorks.

2. iPhoto backed by CloudWorks

A Freemium flickr-like model with auto-connection to iPhoto (and Aperature). Some base level service at no charge then additional service levels at a competitive cost.

3. iMovie backed by CloudWorks

A vimeo or viddler like service with auto-connection to iMovie. Some base level service at no charge then additional service levels at a competitive cost. The real advantage is HTML5 video streaming.

iWorks

iWorks is, ummm, okay. Except for Numbers. I cannot yet replace Excel with Numbers.

4. Super iWeb backed by CloudWorks

I know, I know. iWeb publishes to MobileMe now. I would like to see a tiered pricing plan. iWeb isn’t a web application authoring system. It’s a kinder, gentler DreamWeaver or FrontPage. Not everyone want’s to create the next twitter of foursquare. Sometimes a simple website is appropriate. Maybe $1.99/month for the basic service (charged to the App Store). Bandwidth and storage overages are competitive.

I’d like to see iWeb extended as a client editor for WordPress and/or MoveableType. Even better, a deal with one of these vendors to provide the service on CloudWorks.

5. Pages backed by CloudWorks

I use Pages to write papers for school (which I must export into Word format for online submission). Pages is more pleasing to use than Word so long as I don’t need to do much formatting. Besides, I do most of my draft writing using a combination of BBEdit and Scrivener. This blog article was drafted in BBEdit, for example. However, I’d like to save my Pages documents to CloudWorks with revision control. When I grant someone permission to pull the document down, they can select one of three formats: Pages, Word or PDF.

While we’re at it, I’d like to see a repository in CloudWorks for templates. CloudWorks users can submit templates to the repository and other members can rate the template. Like a APA compliant template.

6. Keynote backed by CloudWorks

Keynote is love/hate. It too is more pleasing to use than PowerPoint but almost nobody I interact with uses Keynote so I have that extra export to PowerPoint step. My favorite presentation tool is OmniGraffle. It’s a joy to work with and I like the way it looks in presentation mode. However, there is only one person I share presentations with who has OmniGraffle. Just one. I end up exporting to PDF.

I’d like to save my Keynote presentations to CloudWorks with revision control. When I grant someone permission to pull the document down, they can select one of three formats: Keynote, PowerPoint or PDF. Additionally, there is an HTML5 presentation feature that allows for online slideshow viewing.

Fix Things

There just two things I’d like fixed. They may seem small but it’s my blog and I’m making a statement.

7. Fix iTunes U

Maybe no one but me uses iTunes U and therefore no one will be disappointed if there are no improvements here. Except for me. I’ll be disappointed. For example, the ability to sort the lectures within a course. That would be nice.

It seems as if Apple has conceded K-12 to Windows. I would like to see the Mac emerge as strong leader in online education. That’s just me being selfish as I like school.

8. Fix the Cocoa Finder

I was happy to hear Apple moved Finder from Carbon to Cocoa… until I used it. There are subtle annoying quirks that showed up in the new Finder. For example, when I tab between desktops in Spaces, the focus is wrong when I get there. Even when the application has the focus (in the menu) upon arrival to a new desktop, the actual window doesn’t have focus.

Two More Things

9. iPhone on Verizon

I know this is a very United States centric request but this is where I live. ATT service at my house sucks. I’d immediately switch to Verizon. I don’t much care for Verizon but they do have great coverage (including my house).

10. Full CSS3, HTML5 Support in Safari

Whatever that means. I’d be happy if Safari reached functional parity with Chrome (except for the audio/video elements, cause that’s just not going to happen.) Safari is not far off.

Will any of this emerge at WWDC 2010? Who knows? Maybe what’s coming is so stunning that it eclipses any of my current desires. <-- grin -->