/* * Copyright 2014 Google Inc. All rights reserved. * * 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 com.google.samples.apps.iosched.nearby; import android.app.Activity; import android.os.Handler; import android.text.Html; import android.text.TextUtils; import android.util.Log; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.ImageView; import android.widget.TextView; import com.google.samples.apps.iosched.R; import java.util.*; import static com.google.samples.apps.iosched.util.LogUtils.makeLogTag; /** * Adapter class for building views related to BLE devices. */ public class NearbyDeviceAdapter extends BaseAdapter { String TAG = makeLogTag("NearbyDeviceAdapter"); private ArrayList<NearbyDevice> mNearbyDevices; private Activity mActivity; private Handler mHandler = new Handler(); private long mLastChangeRequestTime = 0; private long NOTIFY_DELAY = 300; NearbyDeviceAdapter(Activity activity) { mNearbyDevices = new ArrayList<NearbyDevice>(); mActivity = activity; } @Override public int getCount() { return mNearbyDevices.size(); } @Override public Object getItem(int i) { return mNearbyDevices.get(i); } @Override public long getItemId(int i) { NearbyDevice device = mNearbyDevices.get(i); return System.identityHashCode(device); } @Override public View getView(int i, View view, ViewGroup container) { if (view == null) { view = mActivity.getLayoutInflater().inflate(R.layout.ble_listitem_device, null); } NearbyDevice device = mNearbyDevices.get(i); DeviceMetadata deviceMetadata = device.getInfo(); TextView infoView; infoView = (TextView) view.findViewById(R.id.title); if (deviceMetadata != null) { String title = deviceMetadata.title; if (!TextUtils.isEmpty(title)) { infoView.setText(Html.fromHtml(deviceMetadata.title)); infoView.setVisibility(View.VISIBLE); } else { infoView.setVisibility(View.GONE); } } else { infoView.setText(R.string.loading); infoView.setVisibility(View.VISIBLE); } infoView = (TextView) view.findViewById(R.id.url); if (deviceMetadata != null) { infoView.setText(deviceMetadata.siteUrl); } else { infoView.setText(device.getUrl()); } infoView = (TextView) view.findViewById(R.id.description); if (deviceMetadata != null) { String description = deviceMetadata.description; if (!TextUtils.isEmpty(description)) { infoView.setText(Html.fromHtml(deviceMetadata.description)); infoView.setVisibility(View.VISIBLE); } else { infoView.setVisibility(View.GONE); } } else { infoView.setVisibility(View.INVISIBLE); } ImageView iconView = (ImageView) view.findViewById(R.id.icon); if (deviceMetadata != null) { iconView.setImageBitmap(deviceMetadata.icon); } else { iconView.setImageResource(R.drawable.empty_nearby_icon); } return view; } public void addDevice(final NearbyDevice device) { mActivity.runOnUiThread(new Runnable() { @Override public void run() { mNearbyDevices.add(device); device.setAdapter(NearbyDeviceAdapter.this); queueChangedNotification(); } }); } public NearbyDevice getExistingDevice(NearbyDevice candidateDevice) { for (NearbyDevice device : mNearbyDevices) { if (device.getUrl().equals(candidateDevice.getUrl())) { return device; } } return null; } public ArrayList<NearbyDevice> removeExpiredDevices() { // Get a list of devices that we need to remove. ArrayList<NearbyDevice> toRemove = new ArrayList<NearbyDevice>(); for (NearbyDevice device : mNearbyDevices) { if (device.isLastSeenAfter(NearbyDeviceManager.MAX_INACTIVE_TIME)) { toRemove.add(device); } } // Remove those devices from the list and notify the listener. for (final NearbyDevice device : toRemove) { mActivity.runOnUiThread(new Runnable() { @Override public void run() { mNearbyDevices.remove(device); queueChangedNotification(); } }); } return toRemove; } public void updateListUI() { mActivity.runOnUiThread(new Runnable() { @Override public void run() { queueChangedNotification(); } }); } private Runnable mNotifyRunnable = new Runnable() { @Override public void run() { notifyDataSetChanged(); } }; public void queueChangedNotification() { long now = System.currentTimeMillis(); // If a notification was recently issued, create a pending notification. if (now - mLastChangeRequestTime < NOTIFY_DELAY) { // Ignore if there's a pending timer already. mHandler.removeCallbacks(mNotifyRunnable); mHandler.postDelayed(mNotifyRunnable, NOTIFY_DELAY); } else { // Otherwise, if there's no active timer, notify immediately. Log.i(TAG, "queueChangedNotification: Immediately notifying."); notifyDataSetChanged(); } } @Override public void notifyDataSetChanged() { Log.i(TAG, "queueChangedNotification: notifyDataSetChanged"); Collections.sort(mNearbyDevices, mRssiComparator); super.notifyDataSetChanged(); // Cancel the pending notification timer if there is one. mHandler.removeCallbacks(mNotifyRunnable); mLastChangeRequestTime = System.currentTimeMillis(); } private Comparator<NearbyDevice> mRssiComparator = new Comparator<NearbyDevice>() { @Override public int compare(NearbyDevice lhs, NearbyDevice rhs) { return rhs.getAverageRSSI() - lhs.getAverageRSSI(); } }; }