@Override
  public void run(MediaSet baseSet) {
    final int total = baseSet.getTotalMediaItemCount();
    final SmallItem[] buf = new SmallItem[total];
    // Separate items to two sets: with or without lat-long.
    final double[] latLong = new double[2];
    baseSet.enumerateTotalMediaItems(
        new MediaSet.ItemConsumer() {
          public void consume(int index, MediaItem item) {
            if (index < 0 || index >= total) return;
            SmallItem s = new SmallItem();
            s.path = item.getPath();
            item.getLatLong(latLong);
            s.lat = latLong[0];
            s.lng = latLong[1];
            buf[index] = s;
          }
        });

    final ArrayList<SmallItem> withLatLong = new ArrayList<SmallItem>();
    final ArrayList<SmallItem> withoutLatLong = new ArrayList<SmallItem>();
    final ArrayList<Point> points = new ArrayList<Point>();
    for (int i = 0; i < total; i++) {
      SmallItem s = buf[i];
      if (s == null) continue;
      if (GalleryUtils.isValidLocation(s.lat, s.lng)) {
        withLatLong.add(s);
        points.add(new Point(s.lat, s.lng));
      } else {
        withoutLatLong.add(s);
      }
    }

    ArrayList<ArrayList<SmallItem>> clusters = new ArrayList<ArrayList<SmallItem>>();

    int m = withLatLong.size();
    if (m > 0) {
      // cluster the items with lat-long
      Point[] pointsArray = new Point[m];
      pointsArray = points.toArray(pointsArray);
      int[] bestK = new int[1];
      int[] index = kMeans(pointsArray, bestK);

      for (int i = 0; i < bestK[0]; i++) {
        clusters.add(new ArrayList<SmallItem>());
      }

      for (int i = 0; i < m; i++) {
        clusters.get(index[i]).add(withLatLong.get(i));
      }
    }

    ReverseGeocoder geocoder = new ReverseGeocoder(mContext);
    mNames = new ArrayList<String>();
    boolean hasUnresolvedAddress = false;
    mClusters = new ArrayList<ArrayList<SmallItem>>();
    for (ArrayList<SmallItem> cluster : clusters) {
      String name = generateName(cluster, geocoder);
      if (name != null) {
        mNames.add(name);
        mClusters.add(cluster);
      } else {
        // move cluster-i to no location cluster
        withoutLatLong.addAll(cluster);
        hasUnresolvedAddress = true;
      }
    }

    if (withoutLatLong.size() > 0) {
      mNames.add(mNoLocationString);
      mClusters.add(withoutLatLong);
    }

    if (hasUnresolvedAddress) {
      mHandler.post(
          new Runnable() {
            public void run() {
              Toast.makeText(mContext, R.string.no_connectivity, Toast.LENGTH_LONG).show();
            }
          });
    }
  }