Android Open Source - bv-android-sdk Product Widget Provider






From Project

Back to project page bv-android-sdk.

License

The source code is released under:

Apache License

If you think the Android project bv-android-sdk listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

package com.example.productwidgetexample;
//w w w  .j a  v a  2  s .com
import java.util.ArrayList;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.RemoteViews;

import com.bazaarvoice.OnBazaarResponse;

/**
 * ProductWidgetProvider.java<br>
 * ProductWidgetExample<br>
 * 
 * <p>
 * This is the main class that defines the functionality of the widget. When it
 * updates, it downloads a new list of products asynchronously. To navigate
 * between products, the widget sends an intent to itself with the desired
 * direction of navigation.
 * 
 * <p>
 * Of mentionable note:
 * <ul>
 * <li>Every time you call
 * {@link AppWidgetManager#updateAppWidget(ComponentName, RemoteViews)} you need
 * to set all of the click listeners that you want because Android likes to
 * recycle old RemoteViews to save resources.</li>
 * 
 * <li>The flags set for the intent used to launch the ReviewsActivity are
 * deliberate to ensure that old activities are reused but are delivered new
 * intents.</li>
 * 
 * <li>The widget settings are set in res/xml/browse_widget_info.xml</li>
 * 
 * <p>
 * Created on 7/27/12. Copyright (c) 2012 BazaarVoice. All rights reserved.
 * 
 * @author Bazaarvoice Engineering
 * 
 */
public class ProductWidgetProvider extends AppWidgetProvider {

  public static final String TRIGGER = "trigger";
  @SuppressWarnings("unused")
  private static final String TAG = "Widget";

  private static ArrayList<BazaarProduct> products;
  private static int curProduct;

  /**
   * Called when an instance of this widget is added to the home screen and
   * whenever an update goes off as set in res/xml/browse_widget_info.xml.
   */
  @Override
  public void onUpdate(Context context, AppWidgetManager appWidgetManager,
      int[] appWidgetIds) {
    super.onUpdate(context, appWidgetManager, appWidgetIds);
    RemoteViews root = new RemoteViews(context.getPackageName(),
        R.layout.browse_widget);

    root.setViewVisibility(R.id.progressBar, View.VISIBLE);
    root.setViewVisibility(R.id.productHolder, View.GONE);
    root.setViewVisibility(R.id.bottomButtons, View.GONE);
    refreshWidget(context, root);

    // Use asynctask to avoid ANR timeout
    AsyncDownloadProducts task = new AsyncDownloadProducts();
    task.execute(new Context[] { context });
  }

  /**
   * Sets all of the listeners needed to the RemoteViews object and updates
   * the widget UI.
   * 
   * @param context
   *            the application context
   * @param root
   *            the view representing the widget
   */
  private void refreshWidget(Context context, RemoteViews root) {
    root.setOnClickPendingIntent(R.id.back,
        getNavigationIntent(context, R.id.back));
    root.setOnClickPendingIntent(R.id.forward,
        getNavigationIntent(context, R.id.forward));
    updateProductView(context, root);

    AppWidgetManager appWidgetManager = AppWidgetManager
        .getInstance(context);
    ComponentName thisWidget = new ComponentName(context,
        ProductWidgetProvider.class);
    appWidgetManager.updateAppWidget(thisWidget, root);
  }

  /**
   * Returns the correct PendingIntent for the given button resource id. The
   * back button and the forward button need to have different intents.
   * 
   * @param context
   *            the application context
   * @param id
   *            the resource id of the button this PendingIntent is for
   * @return the correct PendingIntent
   */
  private PendingIntent getNavigationIntent(Context context, int id) {
    Intent clickIntent = new Intent(context, ProductWidgetProvider.class);
    clickIntent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
    clickIntent.putExtra(TRIGGER, id);

    PendingIntent pendingIntent = PendingIntent.getBroadcast(context, id,
        clickIntent, PendingIntent.FLAG_UPDATE_CURRENT);
    return pendingIntent;
  }

  /**
   * Sets the image, text, rating, and listener for the product information on the
   * widget to match the current product in the list.
   * 
   * @param context
   *            the application context
   * @param root
   *            the view representing the widget
   */
  public void updateProductView(Context context, RemoteViews root) {
    if (products == null || products.size() == 0) {
      return;
    }
    BazaarProduct product = products.get(curProduct);
    root.setImageViewBitmap(R.id.productImage, product.getImageBitmap());
    root.setTextViewText(R.id.productTitle, product.getName());

    int resId = 0;
    switch ((int) product.getAverageRating()) {
    case (1):
      resId = R.drawable.one_star;
      break;
    case (2):
      resId = R.drawable.two_star;
      break;
    case (3):
      resId = R.drawable.three_star;
      break;
    case (4):
      resId = R.drawable.four_star;
      break;
    case (5):
      resId = R.drawable.five_star;
      break;
    default:
      resId = R.drawable.three_star;
      break;
    }
    root.setImageViewResource(R.id.productRating, resId);

    Intent intent = new Intent(context, ReviewsActivity.class);
    intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    intent.putExtra("product", product);
    PendingIntent pendingIntent = PendingIntent.getActivity(context, 0,
        intent, PendingIntent.FLAG_CANCEL_CURRENT);
    root.setOnClickPendingIntent(R.id.productImage, pendingIntent);
  }

  /**
   * Handles incoming intents. If it is from a navigation action, calls
   * onNavigate().
   */
  @Override
  public void onReceive(Context context, Intent intent) {
    Log.i("onReceive", "intent received");
    String action = intent.getAction();
    Bundle extras = intent.getExtras();
    Integer id = (Integer) (extras == null ? null : extras.get(TRIGGER));
    if (AppWidgetManager.ACTION_APPWIDGET_UPDATE.equals(action)
        && id != null) {
      onNavigate(context, id);
    } else {
      super.onReceive(context, intent);
    }
  }

  /**
   * Changes the current product index depending on which direction button was
   * clicked and refreshes the widget.
   * 
   * @param context
   *            the application context
   * @param id
   *            the resource id of the button pressed
   */
  protected void onNavigate(Context context, Integer id) {
    if (products == null)
      return;

    RemoteViews root = new RemoteViews(context.getPackageName(),
        R.layout.browse_widget);

    if (id == R.id.back) {
      curProduct = (curProduct - 1) % products.size();
      if (curProduct < 0) {
        curProduct += products.size();
      }
    } else if (id == R.id.forward) {
      curProduct = (curProduct + 1) % products.size();
    }
    refreshWidget(context, root);
  }
  

  /**
   * Handles the background download of a list of BazaarProducts.
   * 
   * <p>
   * Created on 7/27/12. Copyright (c) 2012 BazaarVoice. All rights reserved.
   * 
   * @author Bazaarvoice Engineering
   */
  private class AsyncDownloadProducts extends
      AsyncTask<Context, Void, RemoteViews> {

    private Context context;

    /**
     * A simple counter to make sure the download thread waits for all of
     * the images to be downloaded.
     * 
     * <p>
     * Created on 7/27/12. Copyright (c) 2012 BazaarVoice. All rights
     * reserved.
     * 
     * @author Bazaarvoice Engineering
     */
    private class Counter {
      int value;

      public Counter(int i) {
        value = i;
      }

      @SuppressWarnings("unused")
      public void increment() {
        value++;
      }

      public void decrement() {
        value--;
      }

      public int getValue() {
        return value;
      }

      public void setValue(int val) {
        value = val;
      }
    }

    /**
     * Sends a request for products, downloads the images, and updates the
     * widget UI.
     */
    @Override
    protected RemoteViews doInBackground(Context... params) {
      context = params[0];
      curProduct = 0;
      products = new ArrayList<BazaarProduct>();
      final Counter counter = new Counter(1);
      final RemoteViews root = new RemoteViews(context.getPackageName(),
          R.layout.browse_widget);

      BazaarFunctions.runProductQuery(new OnBazaarResponse() {

        @Override
        public void onException(String message, Throwable exception) {
          Log.e("Product Query", "ERROR:" + message + exception.getMessage());
          counter.setValue(0);
        }

        @Override
        public void onResponse(JSONObject json) {
          Log.i("Product Query", "Query:" + json.toString());
          try {
            JSONArray results = json.getJSONArray("Results");
            
            /*
             * Download the image for each product before updating the view
             */
            counter.setValue(results.length());
            for (int i = 0; i < results.length(); i++) {
              final BazaarProduct newProduct = new BazaarProduct(
                  results.getJSONObject(i));
              products.add(newProduct);
              newProduct
                  .downloadImage(new OnImageDownloadComplete() {

                    @Override
                    public void onFinish(Bitmap image) {
                      counter.decrement();

                      /*
                       * Scale image down to work with
                       * less powerful phones.
                       */
                      double factor = (image.getHeight() >= 200) ? image
                          .getHeight() / 200 : 1;
                      Bitmap smaller = Bitmap
                          .createScaledBitmap(
                              image,
                              (int) (image
                                  .getWidth() / factor),
                              (int) (image
                                  .getHeight() / factor),
                              false);
                      newProduct.setImageBitmap(smaller);
                    }

                  });
            }
          } catch (JSONException e) {
            Log.e("Product Query", "ERROR:" + e.getMessage() + " : " + e.getStackTrace().toString());
          }
        }

      });

      /*
       * Wait for each product's image to be downloaded.
       */
      while (counter.getValue() > 0) {
        try {
          Thread.sleep(2000);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      }

      updateProductView(context, root);

      root.setViewVisibility(R.id.progressBar, View.GONE);
      root.setViewVisibility(R.id.productHolder, View.VISIBLE);
      root.setViewVisibility(R.id.bottomButtons, View.VISIBLE);
      return root;
    }

    /**
     * Refreshes the newly created widget UI.
     */
    @Override
    protected void onPostExecute(RemoteViews root) {
      refreshWidget(context, root);
    }
  }
}




Java Source Code List

com.bazaarvoice.BazaarException.java
com.bazaarvoice.BazaarParams.java
com.bazaarvoice.BazaarRequest.java
com.bazaarvoice.DisplayParams.java
com.bazaarvoice.Media.java
com.bazaarvoice.OnBazaarResponse.java
com.bazaarvoice.SubmissionMediaParams.java
com.bazaarvoice.SubmissionParams.java
com.bazaarvoice.example.browseproducts.BazaarFunctions.java
com.bazaarvoice.example.browseproducts.BazaarProduct.java
com.bazaarvoice.example.browseproducts.BazaarReview.java
com.bazaarvoice.example.browseproducts.BazaarUIThreadResponse.java
com.bazaarvoice.example.browseproducts.ImageDownloader.java
com.bazaarvoice.example.browseproducts.MainActivity.java
com.bazaarvoice.example.browseproducts.OnImageDownloadComplete.java
com.bazaarvoice.example.browseproducts.ProductAdapter.java
com.bazaarvoice.example.browseproducts.ProductsActivity.java
com.bazaarvoice.example.browseproducts.ReviewAdapter.java
com.bazaarvoice.example.browseproducts.ReviewDisplayActivity.java
com.bazaarvoice.example.browseproducts.ReviewsActivity.java
com.bazaarvoice.example.reviewsubmission.BazaarFunctions.java
com.bazaarvoice.example.reviewsubmission.BazaarReview.java
com.bazaarvoice.example.reviewsubmission.CameraUtils.java
com.bazaarvoice.example.reviewsubmission.ImageDownloader.java
com.bazaarvoice.example.reviewsubmission.MainActivity.java
com.bazaarvoice.example.reviewsubmission.OnImageDownloadComplete.java
com.bazaarvoice.example.reviewsubmission.OnImageUploadComplete.java
com.bazaarvoice.example.reviewsubmission.RatingActivity.java
com.bazaarvoice.example.reviewsubmission.RatingPreviewActivity.java
com.bazaarvoice.example.reviewsubmission.ReviewSubmissionApp.java
com.bazaarvoice.intentexample.BazaarFunctions.java
com.bazaarvoice.intentexample.BazaarUIThreadResponse.java
com.bazaarvoice.intentexample.CameraUtils.java
com.bazaarvoice.intentexample.MainActivity.java
com.bazaarvoice.types.Action.java
com.bazaarvoice.types.ApiVersion.java
com.bazaarvoice.types.Equality.java
com.bazaarvoice.types.FeedbackContentType.java
com.bazaarvoice.types.FeedbackType.java
com.bazaarvoice.types.FeedbackVoteType.java
com.bazaarvoice.types.IncludeStatsType.java
com.bazaarvoice.types.IncludeType.java
com.bazaarvoice.types.MediaParamsContentType.java
com.bazaarvoice.types.RequestType.java
com.chute.android.photopickerplus.adapter.AlbumsAdapter.java
com.chute.android.photopickerplus.adapter.PhotoSelectCursorAdapter.java
com.chute.android.photopickerplus.adapter.PhotosAdapter.java
com.chute.android.photopickerplus.app.AlbumsActivity.java
com.chute.android.photopickerplus.app.ChooseServiceActivity.java
com.chute.android.photopickerplus.app.GridActivity.java
com.chute.android.photopickerplus.app.PhotoPickerPlusApp.java
com.chute.android.photopickerplus.dao.MediaDAO.java
com.chute.android.photopickerplus.util.AppUtil.java
com.chute.android.photopickerplus.util.Constants.java
com.chute.android.photopickerplus.util.NotificationUtil.java
com.chute.android.photopickerplus.util.intent.AlbumsActivityIntentWrapper.java
com.chute.android.photopickerplus.util.intent.IntentUtil.java
com.chute.android.photopickerplus.util.intent.IntentWrapper.java
com.chute.android.photopickerplus.util.intent.PhotoActivityIntentWrapper.java
com.chute.android.photopickerplus.util.intent.PhotoPickerPlusIntentWrapper.java
com.chute.android.photopickerplus.util.intent.PhotosIntentWrapper.java
com.example.productwidgetexample.BazaarFunctions.java
com.example.productwidgetexample.BazaarProduct.java
com.example.productwidgetexample.BazaarReview.java
com.example.productwidgetexample.BazaarUIThreadResponse.java
com.example.productwidgetexample.ImageDownloader.java
com.example.productwidgetexample.OnImageDownloadComplete.java
com.example.productwidgetexample.ProductWidgetProvider.java
com.example.productwidgetexample.ReviewAdapter.java
com.example.productwidgetexample.ReviewsActivity.java