FileDocCategorySizeDatePackage
IconLoader.javaAPI DocAndroid 1.5 API11897Wed May 06 22:42:02 BST 2009com.android.internal.telephony.gsm.stk

IconLoader

public class IconLoader extends android.os.Handler
Class for loading icons from the SIM card. Has two states: single, for loading one icon. Multi, for loading icons list.

Fields Summary
private int
mState
private ImageDescriptor
mId
private android.graphics.Bitmap
mCurrentIcon
private int
mRecordNumber
private com.android.internal.telephony.gsm.SIMFileHandler
mSimFH
private android.os.Message
mEndMsg
private byte[]
mIconData
private int[]
mRecordNumbers
private int
mCurrentRecordIndex
private android.graphics.Bitmap[]
mIcons
private HashMap
mIconsCache
private static IconLoader
sLoader
private static final int
STATE_SINGLE_ICON
private static final int
STATE_MULTI_ICONS
private static final int
EVENT_READ_EF_IMG_RECOED_DONE
private static final int
EVENT_READ_ICON_DONE
private static final int
EVENT_READ_CLUT_DONE
private static final int
CLUT_LOCATION_OFFSET
private static final int
CLUT_ENTRY_SIZE
Constructors Summary
private IconLoader(android.os.Looper looper, com.android.internal.telephony.gsm.SIMFileHandler fh)



          
        super(looper);
        mSimFH = fh;

        mIconsCache = new HashMap<Integer, Bitmap>(50);
    
Methods Summary
private static intbitToBnW(int bit)
Decode one bit to a black and white color: 0 is black 1 is white

param
bit to decode
return
RGB color

        if(bit == 1){
            return Color.WHITE;
        } else {
            return Color.BLACK;
        }
    
static com.android.internal.telephony.gsm.stk.IconLoadergetInstance(android.os.Handler caller, com.android.internal.telephony.gsm.SIMFileHandler fh)

        if (sLoader != null) {
            return sLoader;
        }
        if (fh != null) {
            HandlerThread thread = new HandlerThread("Stk Icon Loader");
            thread.start();
            return new IconLoader(thread.getLooper(), fh);
        }
        return null;
    
private static intgetMask(int numOfBits)
Calculate bit mask for a given number of bits. The mask should enable to make a bitwise and to the given number of bits.

param
numOfBits number of bits to calculate mask for.
return
bit mask

        int mask = 0x00;

        switch (numOfBits) {
        case 1:
            mask = 0x01;
            break;
        case 2:
            mask = 0x03;
            break;
        case 3:
            mask = 0x07;
            break;
        case 4:
            mask = 0x0F;
            break;
        case 5:
            mask = 0x1F;
            break;
        case 6:
            mask = 0x3F;
            break;
        case 7:
            mask = 0x7F;
            break;
        case 8:
            mask = 0xFF;
            break;
        }
        return mask;
    
private booleanhandleImageDescriptor(byte[] rawData)
Handles Image descriptor parsing and required processing. This is the first step required to handle retrieving icons from the SIM.

param
data byte [] containing Image Instance descriptor as defined in TS 51.011.

        mId = ImageDescriptor.parse(rawData, 1);
        if (mId == null) {
            return false;
        }
        return true;
    
public voidhandleMessage(android.os.Message msg)

        AsyncResult ar;

        try {
            switch (msg.what) {
            case EVENT_READ_EF_IMG_RECOED_DONE:
                ar = (AsyncResult) msg.obj;
                if (handleImageDescriptor((byte[]) ar.result)) {
                    readIconData();
                } else {
                    throw new Exception("Unable to parse image descriptor");
                }
                break;
            case EVENT_READ_ICON_DONE:
                ar = (AsyncResult) msg.obj;
                byte[] rawData = ((byte[]) ar.result);
                if (mId.codingScheme == ImageDescriptor.CODING_SCHEME_BASIC) {
                    mCurrentIcon = parseToBnW(rawData, rawData.length);
                    mIconsCache.put(mRecordNumber, mCurrentIcon);
                    postIcon();
                } else if (mId.codingScheme == ImageDescriptor.CODING_SCHEME_COLOUR) {
                    mIconData = rawData;
                    readClut();
                }
                break;
            case EVENT_READ_CLUT_DONE:
                ar = (AsyncResult) msg.obj;
                byte [] clut = ((byte[]) ar.result);
                mCurrentIcon = parseToRGB(mIconData, mIconData.length,
                        false, clut);
                mIconsCache.put(mRecordNumber, mCurrentIcon);
                postIcon();
                break;
            }
        } catch (Exception e) {
            StkLog.d(this, "Icon load failed");
            // post null icon back to the caller.
            postIcon();
        }
    
voidloadIcon(int recordNumber, android.os.Message msg)

        if (msg == null) {
            return;
        }
        mEndMsg = msg;
        mState = STATE_SINGLE_ICON;
        startLoadingIcon(recordNumber);
    
voidloadIcons(int[] recordNumbers, android.os.Message msg)

        if (recordNumbers == null || recordNumbers.length == 0 || msg == null) {
            return;
        }
        mEndMsg = msg;
        // initialize multi icons load variables.
        mIcons = new Bitmap[recordNumbers.length];
        mRecordNumbers = recordNumbers;
        mCurrentRecordIndex = 0;
        mState = STATE_MULTI_ICONS;
        startLoadingIcon(recordNumbers[0]);
    
public static android.graphics.BitmapparseToBnW(byte[] data, int length)
Convert a TS 131.102 image instance of code scheme '11' into Bitmap

param
data The raw data
param
length The length of image body
return
The bitmap

        int valueIndex = 0;
        int width = data[valueIndex++] & 0xFF;
        int height = data[valueIndex++] & 0xFF;
        int numOfPixels = width*height;

        int[] pixels = new int[numOfPixels];

        int pixelIndex = 0;
        int bitIndex = 7;
        byte currentByte = 0x00;
        while (pixelIndex < numOfPixels) {
            // reassign data and index for every byte (8 bits).
            if (pixelIndex % 8 == 0) {
                currentByte = data[valueIndex++];
                bitIndex = 7;
            }
            pixels[pixelIndex++] = bitToBnW((currentByte >> bitIndex-- ) & 0x01);
        }

        if (pixelIndex != numOfPixels) {
            StkLog.d("IconLoader", "parseToBnW; size error");
        }
        return Bitmap.createBitmap(pixels, width, height, Bitmap.Config.ARGB_8888);
    
public static android.graphics.BitmapparseToRGB(byte[] data, int length, boolean transparency, byte[] clut)
a TS 131.102 image instance of code scheme '11' into color Bitmap

param
data The raw data
param
length the length of image body
param
transparency with or without transparency
param
clut coulor lookup table
return
The color bitmap

        int valueIndex = 0;
        int width = data[valueIndex++] & 0xFF;
        int height = data[valueIndex++] & 0xFF;
        int bitsPerImg = data[valueIndex++] & 0xFF;
        int numOfClutEntries = data[valueIndex++] & 0xFF;

        if (true == transparency) {
            clut[numOfClutEntries - 1] = Color.TRANSPARENT;
        }

        int numOfPixels = width * height;
        int[] pixels = new int[numOfPixels];

        valueIndex = 6;
        int pixelIndex = 0;
        int bitsStartOffset = 8 - bitsPerImg;
        int bitIndex = bitsStartOffset;
        byte currentByte = data[valueIndex++];
        int mask = getMask(bitsPerImg);
        boolean bitsOverlaps = (8 % bitsPerImg == 0);
        while (pixelIndex < numOfPixels) {
            // reassign data and index for every byte (8 bits).
            if (bitIndex < 0) {
                currentByte = data[valueIndex++];
                bitIndex = bitsOverlaps ? (bitsStartOffset) : (bitIndex * -1);
            }
            int clutEntry = ((currentByte >> bitIndex) & mask);
            int clutIndex = clutEntry * CLUT_ENTRY_SIZE;
            pixels[pixelIndex++] = Color.rgb(clut[clutIndex],
                    clut[clutIndex + 1], clut[clutIndex + 2]);
            bitIndex -= bitsPerImg;
        }

        return Bitmap.createBitmap(pixels, width, height,
                Bitmap.Config.ARGB_8888);
    
private voidpostIcon()

        if (mState == STATE_SINGLE_ICON) {
            mEndMsg.obj = mCurrentIcon;
            mEndMsg.sendToTarget();
        } else if (mState == STATE_MULTI_ICONS) {
            mIcons[mCurrentRecordIndex++] = mCurrentIcon;
            // If not all icons were loaded, start loading the next one.
            if (mCurrentRecordIndex < mRecordNumbers.length) {
                startLoadingIcon(mRecordNumbers[mCurrentRecordIndex]);
            } else {
                mEndMsg.obj = mIcons;
                mEndMsg.sendToTarget();
            }
        }
    
private voidreadClut()

        int length = mIconData[3] * CLUT_ENTRY_SIZE;
        Message msg = this.obtainMessage(EVENT_READ_CLUT_DONE);
        mSimFH.loadEFImgTransparent(mId.imageId,
                mIconData[CLUT_LOCATION_OFFSET],
                mIconData[CLUT_LOCATION_OFFSET + 1], length, msg);
    
private voidreadIconData()

        Message msg = this.obtainMessage(EVENT_READ_ICON_DONE);
        mSimFH.loadEFImgTransparent(mId.imageId, 0, 0, mId.length ,msg);
    
private voidreadId()

        if (mRecordNumber < 0) {
            mCurrentIcon = null;
            postIcon();
            return;
        }
        Message msg = this.obtainMessage(EVENT_READ_EF_IMG_RECOED_DONE);
        mSimFH.loadEFImgLinearFixed(mRecordNumber, msg);
    
private voidstartLoadingIcon(int recordNumber)

        // Reset the load variables.
        mId = null;
        mIconData = null;
        mCurrentIcon = null;
        mRecordNumber = recordNumber;

        // make sure the icon was not already loaded and saved in the local cache.
        if (mIconsCache.containsKey(recordNumber)) {
            mCurrentIcon = mIconsCache.get(recordNumber);
            postIcon();
            return;
        }

        // start the first phase ==> loading Image Descriptor.
        readId();