Program: 25613
Project: 25613
Buggy source:
@Override public void draw(Canvas canvas){
  if (info == null) {
    if (bitmapFetcher != null) {
      if (bitmapFetcher.sampleWidth == 0 && bitmapFetcher.sampleHeight == 0) {
        if (canvas.getWidth() != 1)         bitmapFetcher.sampleWidth=canvas.getWidth();
        if (canvas.getHeight() != 1)         bitmapFetcher.sampleHeight=canvas.getHeight();
        bitmapFetcher.recomputeDecodeKey();
        info=ion.bitmapCache.get(bitmapFetcher.bitmapKey);
      }
      if (info == null) {
        callback.register(ion,bitmapFetcher.bitmapKey);
        if (BitmapFetcher.shouldDeferImageView(ion)) {
          bitmapFetcher.defer();
        }
 else {
          bitmapFetcher.execute();
        }
      }
      bitmapFetcher=null;
    }
    if (info == null) {
      drawDrawable(canvas,tryGetPlaceholderResource());
      return;
    }
  }
  if (info.drawTime == 0)   info.drawTime=SystemClock.uptimeMillis();
  long destAlpha=0xFF;
  if (fadeIn) {
    destAlpha=((SystemClock.uptimeMillis() - info.drawTime) << 8) / FADE_DURATION;
    destAlpha=Math.min(destAlpha,0xFF);
  }
  if (destAlpha != 255) {
    Drawable placeholder=tryGetPlaceholderResource();
    if (placeholder != null) {
      drawDrawable(canvas,placeholder);
    }
  }
  if (info.decoder != null) {
    Rect clip=canvas.getClipBounds();
    Rect bounds=getBounds();
    float zoom=(float)canvas.getWidth() / (float)clip.width();
    float zoomWidth=zoom * bounds.width();
    float zoomHeight=zoom * bounds.height();
    double wlevel=Math.log(zoomWidth / TILE_DIM) / LOG_2;
    double hlevel=Math.log(zoomHeight / TILE_DIM) / LOG_2;
    double maxLevel=Math.max(wlevel,hlevel);
    int visibleLeft=Math.max(0,clip.left);
    int visibleRight=Math.min(bounds.width(),clip.right);
    int visibleTop=Math.max(0,clip.top);
    int visibleBottom=Math.min(bounds.height(),clip.bottom);
    int level=(int)Math.floor(maxLevel);
    level=Math.min(this.maxLevel,level);
    level=Math.max(level,0);
    int levelTiles=1 << level;
    int textureTileDim=textureDim / levelTiles;
    final boolean DEBUG_ZOOM=false;
    if (info.bitmap != null) {
      canvas.drawBitmap(info.bitmap,null,getBounds(),paint);
      if (DEBUG_ZOOM) {
        paint.setColor(Color.RED);
        paint.setAlpha(0x80);
        canvas.drawRect(getBounds(),paint);
        paint.setAlpha(0xFF);
      }
    }
 else {
      paint.setColor(Color.BLACK);
      canvas.drawRect(getBounds(),paint);
    }
    int sampleSize=1;
    while (textureTileDim / sampleSize > TILE_DIM)     sampleSize<<=1;
    for (int y=0; y < levelTiles; y++) {
      int top=textureTileDim * y;
      int bottom=textureTileDim * (y + 1);
      bottom=Math.min(bottom,bounds.bottom);
      if (bottom < visibleTop)       continue;
      if (top > visibleBottom)       break;
      for (int x=0; x < levelTiles; x++) {
        int left=textureTileDim * x;
        int right=textureTileDim * (x + 1);
        right=Math.min(right,bounds.right);
        if (right < visibleLeft)         continue;
        if (left > visibleRight)         break;
        Rect texRect=new Rect(left,top,right,bottom);
        String tileKey=FileCache.toKeyString(info.key,"String_Node_Str",level,"String_Node_Str",x,"String_Node_Str",y);
        BitmapInfo tile=ion.bitmapCache.get(tileKey);
        if (tile != null && tile.bitmap != null) {
          canvas.drawBitmap(tile.bitmap,null,texRect,paint);
          continue;
        }
        if (ion.bitmapsPending.tag(tileKey) == null) {
          LoadBitmapRegion region=new LoadBitmapRegion(ion,tileKey,info.decoder,texRect,sampleSize);
        }
        ion.bitmapsPending.add(tileKey,tileCallback);
        int parentLeft=0;
        int parentTop=0;
        int parentUp=1;
        int parentLevel=level - parentUp;
        if (x % 2 == 1)         parentLeft++;
        if (y % 2 == 1)         parentTop++;
        int parentX=x >> 1;
        int parentY=y >> 1;
        while (parentLevel >= 0) {
          tileKey=FileCache.toKeyString(info.key,"String_Node_Str",parentLevel,"String_Node_Str",parentX,"String_Node_Str",parentY);
          tile=ion.bitmapCache.get(tileKey);
          if (tile != null && tile.bitmap != null)           break;
          if (parentX % 2 == 1) {
            parentLeft+=1 << parentUp;
          }
          if (parentY % 2 == 1) {
            parentTop+=1 << parentUp;
          }
          parentLevel--;
          parentUp++;
          parentX>>=1;
          parentY>>=1;
        }
        if (tile == null || tile.bitmap == null)         continue;
        int subLevelTiles=1 << parentLevel;
        int subtileDim=textureDim / subLevelTiles;
        int subSampleSize=1;
        while (subtileDim / subSampleSize > TILE_DIM)         subSampleSize<<=1;
        int subTextureDim=subtileDim / subSampleSize;
        subTextureDim>>=parentUp;
        int sourceLeft=subTextureDim * parentLeft;
        int sourceTop=subTextureDim * parentTop;
        Rect sourceRect=new Rect(sourceLeft,sourceTop,sourceLeft + subTextureDim,sourceTop + subTextureDim);
        canvas.drawBitmap(tile.bitmap,sourceRect,texRect,paint);
        if (DEBUG_ZOOM) {
          paint.setColor(Color.RED);
          paint.setAlpha(0x80);
          canvas.drawRect(texRect,paint);
          paint.setAlpha(0xFF);
        }
      }
    }
  }
 else   if (info.gifDecoder != null) {
    GifFrame lastFrame=gifDecoder.gifDecoder.getLastFrame();
    if (lastFrame != null) {
      paint.setAlpha((int)destAlpha);
      canvas.drawBitmap(lastFrame.image,null,getBounds(),paint);
      paint.setAlpha(0xFF);
      long delay=lastFrame.delay;
      if (!invalidateScheduled) {
        invalidateScheduled=true;
        unscheduleSelf(invalidate);
        scheduleSelf(invalidate,SystemClock.uptimeMillis() + Math.max(delay,16));
      }
    }
    if (gifDecoder.gifDecoder.getStatus() == GifDecoder.STATUS_FINISH && repeatAnimation)     gifDecoder.gifDecoder.restart();
    gifDecoder.scheduleNextFrame();
  }
 else   if (info.bitmap != null) {
    paint.setAlpha((int)destAlpha);
    canvas.drawBitmap(info.bitmap,null,getBounds(),paint);
    paint.setAlpha(0xFF);
  }
 else {
    Drawable error=tryGetErrorResource();
    if (error != null) {
      error.setAlpha((int)destAlpha);
      drawDrawable(canvas,error);
      error.setAlpha(0xFF);
    }
  }
  if (destAlpha != 255)   invalidateSelf();
  if (true)   return;
  canvas.save();
  canvas.rotate(45);
  paint.setColor(Color.WHITE);
  canvas.drawRect(0,-10,7.5f,10,paint);
  int sourceColor;
switch (loadedFrom) {
case Loader.LoaderEmitter.LOADED_FROM_CACHE:
    sourceColor=Color.CYAN;
  break;
case Loader.LoaderEmitter.LOADED_FROM_CONDITIONAL_CACHE:
sourceColor=Color.YELLOW;
break;
case Loader.LoaderEmitter.LOADED_FROM_MEMORY:
sourceColor=Color.GREEN;
break;
default :
sourceColor=Color.RED;
break;
}
paint.setColor(sourceColor);
canvas.drawRect(0,-9,6.5f,9,paint);
canvas.restore();
}

Fixed version (ground truth):
@Override public void draw(Canvas canvas){
  if (info == null) {
    drawDrawable(canvas,tryGetPlaceholderResource());
    if (bitmapFetcher != null) {
      if (bitmapFetcher.sampleWidth == 0 && bitmapFetcher.sampleHeight == 0) {
        if (canvas.getWidth() != 1)         bitmapFetcher.sampleWidth=canvas.getWidth();
        if (canvas.getHeight() != 1)         bitmapFetcher.sampleHeight=canvas.getHeight();
        bitmapFetcher.recomputeDecodeKey();
        BitmapInfo found=ion.bitmapCache.get(bitmapFetcher.bitmapKey);
        if (found != null) {
          drawDrawable(canvas,tryGetPlaceholderResource());
          callback.onCompleted(null,found);
          return;
        }
      }
      callback.register(ion,bitmapFetcher.bitmapKey);
      if (BitmapFetcher.shouldDeferImageView(ion)) {
        bitmapFetcher.defer();
      }
 else {
        bitmapFetcher.execute();
      }
      bitmapFetcher=null;
    }
    return;
  }
  if (info.drawTime == 0)   info.drawTime=SystemClock.uptimeMillis();
  long destAlpha=0xFF;
  if (fadeIn) {
    destAlpha=((SystemClock.uptimeMillis() - info.drawTime) << 8) / FADE_DURATION;
    destAlpha=Math.min(destAlpha,0xFF);
  }
  if (destAlpha != 255) {
    Drawable placeholder=tryGetPlaceholderResource();
    if (placeholder != null) {
      drawDrawable(canvas,placeholder);
    }
  }
  if (info.decoder != null) {
    Rect clip=canvas.getClipBounds();
    Rect bounds=getBounds();
    float zoom=(float)canvas.getWidth() / (float)clip.width();
    float zoomWidth=zoom * bounds.width();
    float zoomHeight=zoom * bounds.height();
    double wlevel=Math.log(zoomWidth / TILE_DIM) / LOG_2;
    double hlevel=Math.log(zoomHeight / TILE_DIM) / LOG_2;
    double maxLevel=Math.max(wlevel,hlevel);
    int visibleLeft=Math.max(0,clip.left);
    int visibleRight=Math.min(bounds.width(),clip.right);
    int visibleTop=Math.max(0,clip.top);
    int visibleBottom=Math.min(bounds.height(),clip.bottom);
    int level=(int)Math.floor(maxLevel);
    level=Math.min(this.maxLevel,level);
    level=Math.max(level,0);
    int levelTiles=1 << level;
    int textureTileDim=textureDim / levelTiles;
    final boolean DEBUG_ZOOM=false;
    if (info.bitmap != null) {
      canvas.drawBitmap(info.bitmap,null,getBounds(),paint);
      if (DEBUG_ZOOM) {
        paint.setColor(Color.RED);
        paint.setAlpha(0x80);
        canvas.drawRect(getBounds(),paint);
        paint.setAlpha(0xFF);
      }
    }
 else {
      paint.setColor(Color.BLACK);
      canvas.drawRect(getBounds(),paint);
    }
    int sampleSize=1;
    while (textureTileDim / sampleSize > TILE_DIM)     sampleSize<<=1;
    for (int y=0; y < levelTiles; y++) {
      int top=textureTileDim * y;
      int bottom=textureTileDim * (y + 1);
      bottom=Math.min(bottom,bounds.bottom);
      if (bottom < visibleTop)       continue;
      if (top > visibleBottom)       break;
      for (int x=0; x < levelTiles; x++) {
        int left=textureTileDim * x;
        int right=textureTileDim * (x + 1);
        right=Math.min(right,bounds.right);
        if (right < visibleLeft)         continue;
        if (left > visibleRight)         break;
        Rect texRect=new Rect(left,top,right,bottom);
        String tileKey=FileCache.toKeyString(info.key,"String_Node_Str",level,"String_Node_Str",x,"String_Node_Str",y);
        BitmapInfo tile=ion.bitmapCache.get(tileKey);
        if (tile != null && tile.bitmap != null) {
          canvas.drawBitmap(tile.bitmap,null,texRect,paint);
          continue;
        }
        if (ion.bitmapsPending.tag(tileKey) == null) {
          LoadBitmapRegion region=new LoadBitmapRegion(ion,tileKey,info.decoder,texRect,sampleSize);
        }
        ion.bitmapsPending.add(tileKey,tileCallback);
        int parentLeft=0;
        int parentTop=0;
        int parentUp=1;
        int parentLevel=level - parentUp;
        if (x % 2 == 1)         parentLeft++;
        if (y % 2 == 1)         parentTop++;
        int parentX=x >> 1;
        int parentY=y >> 1;
        while (parentLevel >= 0) {
          tileKey=FileCache.toKeyString(info.key,"String_Node_Str",parentLevel,"String_Node_Str",parentX,"String_Node_Str",parentY);
          tile=ion.bitmapCache.get(tileKey);
          if (tile != null && tile.bitmap != null)           break;
          if (parentX % 2 == 1) {
            parentLeft+=1 << parentUp;
          }
          if (parentY % 2 == 1) {
            parentTop+=1 << parentUp;
          }
          parentLevel--;
          parentUp++;
          parentX>>=1;
          parentY>>=1;
        }
        if (tile == null || tile.bitmap == null)         continue;
        int subLevelTiles=1 << parentLevel;
        int subtileDim=textureDim / subLevelTiles;
        int subSampleSize=1;
        while (subtileDim / subSampleSize > TILE_DIM)         subSampleSize<<=1;
        int subTextureDim=subtileDim / subSampleSize;
        subTextureDim>>=parentUp;
        int sourceLeft=subTextureDim * parentLeft;
        int sourceTop=subTextureDim * parentTop;
        Rect sourceRect=new Rect(sourceLeft,sourceTop,sourceLeft + subTextureDim,sourceTop + subTextureDim);
        canvas.drawBitmap(tile.bitmap,sourceRect,texRect,paint);
        if (DEBUG_ZOOM) {
          paint.setColor(Color.RED);
          paint.setAlpha(0x80);
          canvas.drawRect(texRect,paint);
          paint.setAlpha(0xFF);
        }
      }
    }
  }
 else   if (info.gifDecoder != null) {
    GifFrame lastFrame=gifDecoder.gifDecoder.getLastFrame();
    if (lastFrame != null) {
      paint.setAlpha((int)destAlpha);
      canvas.drawBitmap(lastFrame.image,null,getBounds(),paint);
      paint.setAlpha(0xFF);
      long delay=lastFrame.delay;
      if (!invalidateScheduled) {
        invalidateScheduled=true;
        unscheduleSelf(invalidate);
        scheduleSelf(invalidate,SystemClock.uptimeMillis() + Math.max(delay,16));
      }
    }
    if (gifDecoder.gifDecoder.getStatus() == GifDecoder.STATUS_FINISH && repeatAnimation)     gifDecoder.gifDecoder.restart();
    gifDecoder.scheduleNextFrame();
  }
 else   if (info.bitmap != null) {
    paint.setAlpha((int)destAlpha);
    canvas.drawBitmap(info.bitmap,null,getBounds(),paint);
    paint.setAlpha(0xFF);
  }
 else {
    Drawable error=tryGetErrorResource();
    if (error != null) {
      error.setAlpha((int)destAlpha);
      drawDrawable(canvas,error);
      error.setAlpha(0xFF);
    }
  }
  if (destAlpha != 255)   invalidateSelf();
  if (true)   return;
  canvas.save();
  canvas.rotate(45);
  paint.setColor(Color.WHITE);
  canvas.drawRect(0,-10,7.5f,10,paint);
  int sourceColor;
switch (loadedFrom) {
case Loader.LoaderEmitter.LOADED_FROM_CACHE:
    sourceColor=Color.CYAN;
  break;
case Loader.LoaderEmitter.LOADED_FROM_CONDITIONAL_CACHE:
sourceColor=Color.YELLOW;
break;
case Loader.LoaderEmitter.LOADED_FROM_MEMORY:
sourceColor=Color.GREEN;
break;
default :
sourceColor=Color.RED;
break;
}
paint.setColor(sourceColor);
canvas.drawRect(0,-9,6.5f,9,paint);
canvas.restore();
}