1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.example.android.bluetoothadvertisements; 18 19 import android.bluetooth.le.ScanResult; 20 import android.content.Context; 21 import android.os.SystemClock; 22 import android.view.LayoutInflater; 23 import android.view.View; 24 import android.view.ViewGroup; 25 import android.widget.BaseAdapter; 26 import android.widget.TextView; 27 28 import java.util.ArrayList; 29 import java.util.concurrent.TimeUnit; 30 31 /** 32 * Holds and displays {@link ScanResult}s, used by {@link ScannerFragment}. 33 */ 34 public class ScanResultAdapter extends BaseAdapter { 35 36 private ArrayList<ScanResult> mArrayList; 37 38 private Context mContext; 39 40 private LayoutInflater mInflater; 41 42 ScanResultAdapter(Context context, LayoutInflater inflater) { 43 super(); 44 mContext = context; 45 mInflater = inflater; 46 mArrayList = new ArrayList<>(); 47 } 48 49 @Override 50 public int getCount() { 51 return mArrayList.size(); 52 } 53 54 @Override 55 public Object getItem(int position) { 56 return mArrayList.get(position); 57 } 58 59 @Override 60 public long getItemId(int position) { 61 return mArrayList.get(position).getDevice().getAddress().hashCode(); 62 } 63 64 @Override 65 public View getView(int position, View view, ViewGroup parent) { 66 67 // Reuse an old view if we can, otherwise create a new one. 68 if (view == null) { 69 view = mInflater.inflate(R.layout.listitem_scanresult, null); 70 } 71 72 TextView deviceNameView = (TextView) view.findViewById(R.id.device_name); 73 TextView deviceAddressView = (TextView) view.findViewById(R.id.device_address); 74 TextView lastSeenView = (TextView) view.findViewById(R.id.last_seen); 75 76 ScanResult scanResult = mArrayList.get(position); 77 78 String name = scanResult.getDevice().getName(); 79 if (name == null) { 80 name = mContext.getResources().getString(R.string.no_name); 81 } 82 deviceNameView.setText(name); 83 deviceAddressView.setText(scanResult.getDevice().getAddress()); 84 lastSeenView.setText(getTimeSinceString(mContext, scanResult.getTimestampNanos())); 85 86 return view; 87 } 88 89 /** 90 * Search the adapter for an existing device address and return it, otherwise return -1. 91 */ 92 private int getPosition(String address) { 93 int position = -1; 94 for (int i = 0; i < mArrayList.size(); i++) { 95 if (mArrayList.get(i).getDevice().getAddress().equals(address)) { 96 position = i; 97 break; 98 } 99 } 100 return position; 101 } 102 103 104 /** 105 * Add a ScanResult item to the adapter if a result from that device isn't already present. 106 * Otherwise updates the existing position with the new ScanResult. 107 */ 108 public void add(ScanResult scanResult) { 109 110 int existingPosition = getPosition(scanResult.getDevice().getAddress()); 111 112 if (existingPosition >= 0) { 113 // Device is already in list, update its record. 114 mArrayList.set(existingPosition, scanResult); 115 } else { 116 // Add new Device's ScanResult to list. 117 mArrayList.add(scanResult); 118 } 119 } 120 121 /** 122 * Clear out the adapter. 123 */ 124 public void clear() { 125 mArrayList.clear(); 126 } 127 128 /** 129 * Takes in a number of nanoseconds and returns a human-readable string giving a vague 130 * description of how long ago that was. 131 */ 132 public static String getTimeSinceString(Context context, long timeNanoseconds) { 133 String lastSeenText = context.getResources().getString(R.string.last_seen) + " "; 134 135 long timeSince = SystemClock.elapsedRealtimeNanos() - timeNanoseconds; 136 long secondsSince = TimeUnit.SECONDS.convert(timeSince, TimeUnit.NANOSECONDS); 137 138 if (secondsSince < 5) { 139 lastSeenText += context.getResources().getString(R.string.just_now); 140 } else if (secondsSince < 60) { 141 lastSeenText += secondsSince + " " + context.getResources() 142 .getString(R.string.seconds_ago); 143 } else { 144 long minutesSince = TimeUnit.MINUTES.convert(secondsSince, TimeUnit.SECONDS); 145 if (minutesSince < 60) { 146 if (minutesSince == 1) { 147 lastSeenText += minutesSince + " " + context.getResources() 148 .getString(R.string.minute_ago); 149 } else { 150 lastSeenText += minutesSince + " " + context.getResources() 151 .getString(R.string.minutes_ago); 152 } 153 } else { 154 long hoursSince = TimeUnit.HOURS.convert(minutesSince, TimeUnit.MINUTES); 155 if (hoursSince == 1) { 156 lastSeenText += hoursSince + " " + context.getResources() 157 .getString(R.string.hour_ago); 158 } else { 159 lastSeenText += hoursSince + " " + context.getResources() 160 .getString(R.string.hours_ago); 161 } 162 } 163 } 164 165 return lastSeenText; 166 } 167 } 168