Monday, January 12, 2009

find out the version of ksh/dtksh in Solaris

It took me quite some minutes to find out in Google how to find out the versions of ksh and dtksh in Solaris.

1. Start a shell
$ ksh
or
$ dtksh
2. Enter vi mod
$ set -o vi
Note: The option is letter 'o' , not number zero "0".
3. Press ESC to enter command mode
4. Press Ctrl-V

Here are outputs in Solaris 8 & 9
$ Version M-11/16/88
$ Version M-12/28/93

Tuesday, January 6, 2009

ScrollTextView - scrolling TextView for Android

I wrote a class derived from Android.Widget.TextView to customize a TextView which text can be scrolled.
The derived class, named ScrollTextView, provides an effect just like the HTML marquee tag.
Moreover, the scrolling can be restarted, paused and resumed.

Here are the source codes.

The key points are:
  • setHorizontallyScrolling() and use android.widget.Scroller to make the text scroll;
  • Use the attached TextPaint of the TextView to measure the length of the text in pixel;
  • setSingleLine() and setEllipsize(null) to make the text not wrapped and ellipsized;
  • Override computeScroll() to restart the scrolling when finished
Here are the source codes.

/*************************************************************************/
package com.dirtybear.android;

import android.content.Context;
import android.graphics.Rect;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.view.animation.LinearInterpolator;
import android.widget.Scroller;
import android.widget.TextView;

public class ScrollTextView extends TextView {

// scrolling feature
private Scroller mSlr;

// milliseconds for a round of scrolling
private int mRndDuration = 250;

// the X offset when paused
private int mXPaused = 0;

// whether it's being paused
private boolean mPaused = true;

/*
* constructor
*/
public ScrollTextView(Context context) {
this(context, null);
// customize the TextView
setSingleLine();
setEllipsize(null);
setVisibility(INVISIBLE);
}

/*
* constructor
*/
public ScrollTextView(Context context, AttributeSet attrs) {
this(context, attrs, android.R.attr.textViewStyle);
// customize the TextView
setSingleLine();
setEllipsize(null);
setVisibility(INVISIBLE);
}

/*
* constructor
*/
public ScrollTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// customize the TextView
setSingleLine();
setEllipsize(null);
setVisibility(INVISIBLE);
}

/**
* begin to scroll the text from the original position
*/
public void startScroll() {
// begin from the very right side
mXPaused = -1 * getWidth();
// assume it's paused
mPaused = true;
resumeScroll();
}

/**
* resume the scroll from the pausing point
*/
public void resumeScroll() {

if (!mPaused)
return;

// Do not know why it would not scroll sometimes
// if setHorizontallyScrolling is called in constructor.
setHorizontallyScrolling(true);

// use LinearInterpolator for steady scrolling
mSlr = new Scroller(this.getContext(), new LinearInterpolator());
setScroller(mSlr);

int scrollingLen = calculateScrollingLen();
int distance = scrollingLen - (getWidth() + mXPaused);
int duration = (new Double(mRndDuration * distance * 1.00000
/ scrollingLen)).intValue();

setVisibility(VISIBLE);
mSlr.startScroll(mXPaused, 0, distance, 0, duration);
mPaused = false;
}

/**
* calculate the scrolling length of the text in pixel
*
* @return the scrolling length in pixels
*/
private int calculateScrollingLen() {
TextPaint tp = getPaint();
Rect rect = new Rect();
String strTxt = getText().toString();
tp.getTextBounds(strTxt, 0, strTxt.length(), rect);
int scrollingLen = rect.width() + getWidth();
rect = null;
return scrollingLen;
}

/**
* pause scrolling the text
*/
public void pauseScroll() {
if (null == mSlr)
return;

if (mPaused)
return;

mPaused = true;

// abortAnimation sets the current X to be the final X,
// and sets isFinished to be true
// so current position shall be saved
mXPaused = mSlr.getCurrX();

mSlr.abortAnimation();
}

@Override
/*
* override the computeScroll to restart scrolling when finished so as that
* the text is scrolled forever
*/
public void computeScroll() {
super.computeScroll();

if (null == mSlr) return;

if (mSlr.isFinished() && (!mPaused)) {
this.startScroll();
}
}

public int getRndDuration() {
return mRndDuration;
}

public void setRndDuration(int duration) {
this.mRndDuration = duration;
}

public boolean isPaused() {
return mPaused;
}
}
/*************************************************************************/

Issues to be fixed:
  1. Do not know why it would not scroll sometimes if setHorizontallyScrolling is called in constructor;
  2. The scrolling is not smooth enough. Maybe it's because of the single thread model of Android UI;

Tested on:
Windows XP
Android SDK 1.0 rc2
Android Emulator 1.0
Android Debug Bridge version 1.0.20