1 /*******************************************************************************
2  * This file is part of BOINC.
3  * http://boinc.berkeley.edu
4  * Copyright (C) 2012 University of California
5  *
6  * BOINC is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU Lesser General Public License
8  * as published by the Free Software Foundation,
9  * either version 3 of the License, or (at your option) any later version.
10  *
11  * BOINC is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14  * See the GNU Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with BOINC.  If not, see <http://www.gnu.org/licenses/>.
18  ******************************************************************************/
19 package edu.berkeley.boinc;
20 
21 import edu.berkeley.boinc.adapter.ClientLogListAdapter;
22 import edu.berkeley.boinc.rpc.Message;
23 import edu.berkeley.boinc.utils.*;
24 
25 import java.util.ArrayList;
26 import java.util.List;
27 import android.os.AsyncTask;
28 import android.os.Bundle;
29 import android.os.RemoteException;
30 import android.support.v4.app.Fragment;
31 import android.util.Log;
32 import android.view.LayoutInflater;
33 import android.view.View;
34 import android.view.ViewGroup;
35 import android.widget.AbsListView;
36 import android.widget.ListView;
37 import android.widget.AbsListView.OnScrollListener;
38 
39 public class EventLogClientFragment extends Fragment {
40 
41 	// message retrieval
42 	private Integer pastMsgsLoadingRange = 50; // amount messages loaded when end of list is reached
43 	private EventLogActivity a;
44 
45 	@Override
onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)46 	public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
47 		a = ((EventLogActivity)getActivity());
48 
49     	View layout = inflater.inflate(R.layout.eventlog_client_layout, container, false);
50 
51     	a.clientLogList = (ListView) layout.findViewById(R.id.clientLogList);
52     	a.clientLogListAdapter = new ClientLogListAdapter(getActivity(), a.clientLogList, R.id.clientLogList, a.clientLogData);
53     	a.clientLogList.setOnScrollListener(new EndlessScrollListener(5));
54 
55 		return layout;
56 	}
57 
init()58 	public void init() {
59 		new RetrievePastClientMsgs().execute(); // read messages
60 	}
61 
update()62 	public void update() {
63 		new RetrieveRecentClientMsgs().execute(); // refresh messages
64 	}
65 
66 	// appends older messages to data list
loadPastMsgs(List<edu.berkeley.boinc.rpc.Message> tmpA)67 	private void loadPastMsgs(List<edu.berkeley.boinc.rpc.Message> tmpA) {
68 		// Append old messages to the event log
69 		try {
70 			for(int x = tmpA.size()-1; x >= 0; x--) {
71 				a.clientLogData.add(tmpA.get(x));
72 			}
73 		} catch (Exception e) {} //IndexOutOfBoundException
74 
75 		a.clientLogListAdapter.notifyDataSetChanged();
76 	}
77 
78 	// updates data list with most recent messages
loadRecentMsgs(ArrayList<edu.berkeley.boinc.rpc.Message> tmpA)79 	private void loadRecentMsgs(ArrayList<edu.berkeley.boinc.rpc.Message> tmpA) {
80 		// Prepend new messages to the event log
81 		try {
82 			int y = 0;
83 			for (int x = tmpA.size()-1; x >= 0; x--) {
84 				a.clientLogData.add(y, tmpA.get(x));
85 				y++;
86 			}
87 		} catch (Exception e) {} //IndexOutOfBoundException
88 		a.clientLogListAdapter.notifyDataSetChanged();
89 	}
90 
91 	// onScrollListener for list view, implementing "endless scrolling"
92 	public final class EndlessScrollListener implements OnScrollListener {
93 
94         private int visibleThreshold = 5;
95         private int previousTotal = 0;
96         private boolean loading = true;
97 
EndlessScrollListener(int visibleThreshold)98         public EndlessScrollListener(int visibleThreshold) {
99             this.visibleThreshold = visibleThreshold;
100         }
101 
102         @Override
onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount)103         public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
104             if (loading) {
105                 if (totalItemCount > previousTotal) {
106                     loading = false;
107                     previousTotal = totalItemCount;
108                 }
109             }
110             if (!loading && (totalItemCount - visibleItemCount) <= (firstVisibleItem + visibleThreshold)) {
111                 new RetrievePastClientMsgs().execute();
112                 loading = true;
113             }
114         }
115 
116         @Override
onScrollStateChanged(AbsListView view, int scrollState)117         public void onScrollStateChanged(AbsListView view, int scrollState) {
118         }
119     }
120 
121 	private final class RetrieveRecentClientMsgs extends AsyncTask<Void,Void,ArrayList<edu.berkeley.boinc.rpc.Message>> {
122 
123 		private Integer mostRecentSeqNo = 0;
124 
125 		@Override
onPreExecute()126 		protected void onPreExecute() {
127 			if(!a.clientLogData.isEmpty()) mostRecentSeqNo = a.clientLogData.get(0).seqno;
128 		}
129 
130 		@Override
doInBackground(Void... params)131 		protected ArrayList<edu.berkeley.boinc.rpc.Message> doInBackground(Void... params) {
132 			try {
133 				return (ArrayList<edu.berkeley.boinc.rpc.Message>) ((EventLogActivity)getActivity()).getMonitorService().getMessages(mostRecentSeqNo);
134 			} catch (RemoteException e) {
135 				// TODO Auto-generated catch block
136 				e.printStackTrace();
137 				return new ArrayList<edu.berkeley.boinc.rpc.Message>();
138 			}
139 		}
140 
141 		@Override
onPostExecute(ArrayList<edu.berkeley.boinc.rpc.Message> result)142 		protected void onPostExecute(ArrayList<edu.berkeley.boinc.rpc.Message> result) {
143 			// back in UI thread
144 			loadRecentMsgs(result);
145 		}
146 	}
147 
148 	private final class RetrievePastClientMsgs extends AsyncTask<Void,Void,List<edu.berkeley.boinc.rpc.Message>> {
149 
150 		//private int mostRecentSeqNo = 0; // most recent (highest) seqNo
151 		private int pastSeqNo = -1; // oldest (lowest) seqNo currently loaded to GUI
152 		//private int lastclientLogDataListIndex = 0; // index of last element (oldest message) in clientLogData
153 
154 		@Override
onPreExecute()155 		protected void onPreExecute() {
156 			if(!a.clientLogData.isEmpty()) {
157 				pastSeqNo = a.clientLogData.get(a.clientLogData.size() - 1).seqno;
158 				if(pastSeqNo==0) {
159 					if(Logging.DEBUG) Log.d("RetrievePastMsgs", "cancel, oldest messages already loaded");
160 					cancel(true); // cancel if all past messages are present
161 				}
162 			}
163 		}
164 
165 		@Override
doInBackground(Void... params)166 		protected List<Message> doInBackground(Void... params) {
167 			if(Logging.DEBUG) Log.d("RetrievePastMsgs", "calling monitor with: " + pastSeqNo + " / " + pastMsgsLoadingRange);
168 			try {
169 				return ((EventLogActivity)getActivity()).getMonitorService().getEventLogMessages(pastSeqNo, pastMsgsLoadingRange);
170 			} catch (RemoteException e) {
171 				// TODO Auto-generated catch block
172 				e.printStackTrace();
173 				return new ArrayList<edu.berkeley.boinc.rpc.Message>();
174 			}
175 		}
176 
177 		@Override
onPostExecute(List<edu.berkeley.boinc.rpc.Message> result)178 		protected void onPostExecute(List<edu.berkeley.boinc.rpc.Message> result) {
179 			// back in UI thread
180 			loadPastMsgs(result);
181 		}
182 	}
183 }
184