CandidateListAdapter.java :  » App » android-dependencymanager » de » finkhaeuser » dm » Android Open Source

Android Open Source » App » android dependencymanager 
android dependencymanager » de » finkhaeuser » dm » CandidateListAdapter.java
/**
 * This file is part of the Android DependencyManager project hosted at
 * http://code.google.com/p/android-dependencymanager/
 *
 * Copyright (C) 2009 Jens Finkhaeuser <jens@finkhaeuser.de>
 *
 * 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 de.finkhaeuser.dm;

import android.view.View;
import android.view.ViewGroup;
import android.view.LayoutInflater;

import android.widget.BaseAdapter;
import android.widget.TextView;
import android.widget.ImageView;
import android.widget.AbsListView;

import android.graphics.drawable.Drawable;

import android.content.Context;

import android.net.Uri;

import android.database.Cursor;
import android.database.ContentObserver;

import android.os.Handler;

import java.util.HashMap;
import java.util.LinkedList;

import de.finkhaeuser.dm.common.DependencyManagerContract;
import de.finkhaeuser.dm.common.DependencyManagerContract.CandidateColumns;

import android.util.Log;


/**
 * List Adapter for a cursor as returned from DependencyResolutionProvider.
 **/
public class CandidateListAdapter extends BaseAdapter
{
  /***************************************************************************
   * Private constants
   **/
  // Log ID
  private static final String LTAG = "CandidateListAdapter";

  // View types. These are indices into mLayoutIds, so must start at zero and
  // be sequential numbers.
  private static final int VIEW_TYPE_APP    = 0;
  private static final int VIEW_TYPE_SEARCH = 1;



  /***************************************************************************
   * The ScrollListener triggers thumbnail downloads if scrolling stops, and
   * interrupts them when it starts again.
   **/
  public static class ScrollListener implements AbsListView.OnScrollListener
  {
    private CandidateListAdapter  mAdapter;

    private boolean           mSentInitial = false;
    private int               mFirst;
    private int               mCount;

    public ScrollListener(CandidateListAdapter adapter)
    {
      mAdapter = adapter;
    }



    public int getFirst()
    {
      return mFirst;
    }



    public int getCount()
    {
      return mCount;
    }



    public void onScroll(AbsListView view, int firstVisibleItem,
        int visibleItemCount, int totalItemCount)
    {
      mFirst = firstVisibleItem;
      mCount = visibleItemCount;

      if (!mSentInitial && visibleItemCount > 0) {
        mSentInitial = true;
        mAdapter.startHeavyLifting(mFirst, mCount);
      }
    }



    public void onScrollStateChanged(AbsListView view, int scrollState)
    {
      if (SCROLL_STATE_IDLE != scrollState) {
        mAdapter.cancelHeavyLifting();
        return;
      }

      mAdapter.startHeavyLifting(mFirst, mCount);
    }
  }



  /***************************************************************************
   * Data members
   **/
  private Context             mContext;
  private int[]               mLayoutIds;

  // Result cursor
  private Cursor              mCursor;

  // Maps back and forth between the views currently returned from getView,
  // and the position in mMedia they display.
  private HashMap<Integer, View>  mPositionToView = new HashMap<Integer, View>();
  private HashMap<View, Integer>  mViewToPosition = new HashMap<View, Integer>();



  /***************************************************************************
   * Static data members
   **/
  // The no_image drawable does not need to be loader every time.
  private static Drawable   smNoImage;



  /***************************************************************************
   * Implementation
   **/
  public CandidateListAdapter(Context context, int[] layoutIds, Cursor cursor)
  {
    mContext = context;
    mLayoutIds = layoutIds;
    mCursor = cursor;

    mCursor.registerContentObserver(new ContentObserver(new Handler()) {
        public void onChange(boolean selfChange)
        {
          mCursor.requery();
          notifyDataSetChanged();
        }
    });
  }



  /***************************************************************************
   * Adapter Implementation
   **/
  public int getCount()
  {
    if (null == mCursor) {
      return 0;
    }
    return mCursor.getCount();
  }



  public Object getItem(int position)
  {
    // XXX unused.
    return null;
  }



  public long getItemId(int position)
  {
    // XXX We're not filtering, so this is fine.
    return position;
  }



  public int getViewTypeCount()
  {
    // We return two types of views: one for apps, and one for external
    // searches.
    return 2;
  }



  public int getItemViewType(int position)
  {
    mCursor.moveToPosition(position);
    if (mCursor.isNull(mCursor.getColumnIndex(
            CandidateColumns.EXTERNAL_SEARCH_URI)))
    {
      return VIEW_TYPE_APP;
    }
    return VIEW_TYPE_SEARCH;
  }



  public View getView(int position, View convertView, ViewGroup parent)
  {
    // Create new view, if required.
    View view = convertView;
    if (null == view) {
      int layoutId = mLayoutIds[getItemViewType(position)];
      LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
          Context.LAYOUT_INFLATER_SERVICE);
      view = inflater.inflate(layoutId, null);
    }

    // Grab the position the view currently points to.
    Integer cur_position = mViewToPosition.get(view);
    if (null != cur_position) {
      // The view has been used already at some point.
      if (cur_position != position) {
        // The view is currently used for a different position. We'll need
        // to update both maps.
        mPositionToView.remove(cur_position);
      }
    }
    mViewToPosition.put(view, position);
    mPositionToView.put(position, view);

    // Load item data.
    mCursor.moveToPosition(position);

    String store_name = mCursor.getString(mCursor.getColumnIndex(
          CandidateColumns.STORE_DISPLAY_NAME));
    String store_package = mCursor.getString(mCursor.getColumnIndex(
          CandidateColumns.STORE_PACKAGE));
    String display_name = mCursor.getString(mCursor.getColumnIndex(
          CandidateColumns.DISPLAY_NAME));
    String uri_str = mCursor.getString(mCursor.getColumnIndex(
          CandidateColumns.ICON_URI));
    Uri icon_uri = null;
    if (null != uri_str) {
      icon_uri = Uri.parse(uri_str);
    }

    Uri search_uri = null;
    String app_package = null;
    String app_vendor = null;
    int app_price = -1;
    String app_currency = null;
    String app_matches = null;
    if (!mCursor.isNull(mCursor.getColumnIndex(
            CandidateColumns.EXTERNAL_SEARCH_URI)))
    {
      uri_str = mCursor.getString(mCursor.getColumnIndex(
            CandidateColumns.EXTERNAL_SEARCH_URI));
      if (null != uri_str) {
        search_uri = Uri.parse(uri_str);
      }
    }
    else {
      app_package = mCursor.getString(mCursor.getColumnIndex(
            CandidateColumns.APP_PACKAGE));
      app_vendor = mCursor.getString(mCursor.getColumnIndex(
            CandidateColumns.APP_VENDOR_NAME));
      if (!mCursor.isNull(mCursor.getColumnIndex(
              CandidateColumns.APP_PRICE)))
      {
        app_price = mCursor.getInt(mCursor.getColumnIndex(
              CandidateColumns.APP_PRICE));
        app_currency = mCursor.getString(mCursor.getColumnIndex(
              CandidateColumns.APP_CURRENCY));
      }
      app_matches = mCursor.getString(mCursor.getColumnIndex(
            CandidateColumns.APP_MATCHES));
    }

    // Fill view
    setText(view, R.id.display_name, display_name,
        R.string.def_display_name);
    setText(view, R.id.app_vendor_name, app_vendor,
        R.string.def_app_vendor_name);
    setText(view, R.id.store_display_name, store_name,
        R.string.def_store_display_name);
    if (app_price > 0) {
      // TODO This needs a bit of work. Not all currencies' smaller unit divides
      //  the bigger by 100, and the formatting leaves a bit to be desired.
      String price = String.format("%.2f %s", app_price / 100f, app_currency);
      setText(view, R.id.app_price, price, R.string.def_app_price);
    }
    else {
      setText(view, R.id.app_price, null, R.string.app_price_free);
    }

    // Set icon to default - real icons will be loaded later.
    if (null == smNoImage) {
      smNoImage = mContext.getResources().getDrawable(R.drawable.default_icon);
    }
    ImageView image_view = (ImageView) view.findViewById(R.id.icon);
    if (null != image_view) {
      image_view.setImageDrawable(smNoImage);
    }

    return view;
  }



  private void setText(View parent, int viewId, String text, int defaultId)
  {
    TextView view = (TextView) parent.findViewById(viewId);
    if (null == view) {
      return;
    }

    if (null == text) {
      text = mContext.getResources().getString(defaultId);
    }

    view.setText(text);
  }



  private void startHeavyLifting(int first, int count)
  {
    // TODO load icons for first... count here.
  }



  private void cancelHeavyLifting()
  {
    // TODO cancel loading of icons here.
  }
}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.