blob: 7f4a6b1ba085f7296d95de5888c44323d7132c56 [file] [log] [blame]
Jose Pascoalca875e52014-11-24 12:34:59 +00001/*
2 * Copyright (C) 2013 Fairphone 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 */
16package com.fairphone.fplauncher3.widgets.appswitcher;
17
18import java.util.ArrayList;
19import java.util.Calendar;
Jose Pascoal23699092015-01-13 19:55:32 +000020import java.util.Date;
Jose Pascoalca875e52014-11-24 12:34:59 +000021import java.util.HashMap;
22import java.util.LinkedList;
23import java.util.List;
24import java.util.Map;
25
26import android.content.ComponentName;
Jose Pascoal71794192015-01-15 12:47:08 +000027import android.content.Context;
Jose Pascoalca875e52014-11-24 12:34:59 +000028import android.util.Log;
29
Jose Pascoal23699092015-01-13 19:55:32 +000030import com.fairphone.fplauncher3.widgets.appswitcher.ApplicationRunInformation.APP_AGE;
31
Jose Pascoalca875e52014-11-24 12:34:59 +000032/**
33 * This class processes the count for the most used apps and the most recent.
34 *
35 * @author Tiago Costa
36 *
37 */
Tiago Costa4a8d6ab2015-01-12 16:19:07 +000038public class ApplicationRunInfoManager
39{
Jose Pascoalca875e52014-11-24 12:34:59 +000040
Tiago Costa4a8d6ab2015-01-12 16:19:07 +000041 public static final int RECENT_APP_MAX_COUNT_LIMIT = 5;
42 public static final int MOST_APP_MAX_COUNT_LIMIT = 5;
43 public static final int MINIMAL_COUNT = 2;
Filipe Gonçalvesa804b282015-06-23 17:47:42 +010044 private static final String TAG = ApplicationRunInfoManager.class.getSimpleName();
Jose Pascoalca875e52014-11-24 12:34:59 +000045
Tiago Costa4a8d6ab2015-01-12 16:19:07 +000046 private LimitedQueue<ApplicationRunInformation> _mostUsed;
47 private LimitedQueue<ApplicationRunInformation> _recentApps;
Filipe Gonçalves312cb312016-05-04 15:33:43 +010048 private Map<String, ApplicationRunInformation> _appRunInfos;
Jose Pascoalca875e52014-11-24 12:34:59 +000049
Tiago Costa4a8d6ab2015-01-12 16:19:07 +000050 private int _mostUsedAppsLimit;
51 private int _recentAppsLimit;
Jose Pascoalf354dfe2015-02-10 19:21:21 +000052 private final boolean _updateLists;
Tiago Costa4a8d6ab2015-01-12 16:19:07 +000053
54 public ApplicationRunInfoManager(boolean updateLists)
55 {
Tiago Costa4a8d6ab2015-01-12 16:19:07 +000056 this._updateLists = updateLists;
Filipe Gonçalves312cb312016-05-04 15:33:43 +010057 _appRunInfos = new HashMap<String, ApplicationRunInformation>();
Tiago Costa4a8d6ab2015-01-12 16:19:07 +000058 if (_updateLists)
59 {
60 setUpLimits(MOST_APP_MAX_COUNT_LIMIT, RECENT_APP_MAX_COUNT_LIMIT);
61 }
Tiago Costa4a8d6ab2015-01-12 16:19:07 +000062 }
63
64 public static ApplicationRunInformation generateApplicationRunInfo(ComponentName component, boolean isFreshInstall, boolean isUpdated)
65 {
66 ApplicationRunInformation appInfo = new ApplicationRunInformation(component);
Jose Pascoalca875e52014-11-24 12:34:59 +000067 appInfo.incrementCount();
68 appInfo.setLastExecution(Calendar.getInstance().getTime());
69 appInfo.setIsNewApp(isFreshInstall);
70 appInfo.setIsPinnedApp(false);
Tiago Costa4a8d6ab2015-01-12 16:19:07 +000071 appInfo.setIsUpdatedApp(isUpdated);
Jose Pascoalca875e52014-11-24 12:34:59 +000072
73 return appInfo;
74 }
Tiago Costa4a8d6ab2015-01-12 16:19:07 +000075
76 public static ApplicationRunInformation generateApplicationRunInfo(ComponentName component, boolean isFreshInstall)
77 {
78 return generateApplicationRunInfo(component, isFreshInstall, false);
79 }
Jose Pascoalca875e52014-11-24 12:34:59 +000080
Tiago Costa4a8d6ab2015-01-12 16:19:07 +000081 public void setUpLimits(int maxMostUsed, int maxRecentApps)
82 {
83 _mostUsedAppsLimit = maxMostUsed;
84 _recentAppsLimit = maxRecentApps;
Jose Pascoalca875e52014-11-24 12:34:59 +000085
Tiago Costa4a8d6ab2015-01-12 16:19:07 +000086 // refactor the limits
87 setUpNewLimits();
88 }
89
90 private void setUpNewLimits()
91 {
92 _mostUsed = new LimitedQueue<ApplicationRunInformation>(_mostUsedAppsLimit);
93 _recentApps = new LimitedQueue<ApplicationRunInformation>(_recentAppsLimit);
94
95 // update the information
96 if (_appRunInfos != null)
97 {
98 updateAppInformation();
99 }
100 }
101
102 public void loadNewRunInformation(List<ApplicationRunInformation> allApps)
103 {
104 // clear the current state
105 resetState();
106
107 // add application to the bag
108 for (ApplicationRunInformation appInfo : allApps)
109 {
110 _appRunInfos.put(ApplicationRunInformation.serializeComponentName(appInfo.getComponentName()), appInfo);
111 }
112
113 // update the information
114 updateAppInformation();
115 }
116
117 public void resetState()
118 {
119 if (_updateLists)
120 {
121 _mostUsed.clear();
122 _recentApps.clear();
123 }
124 _appRunInfos.clear();
125 }
126
127 public void applicationStarted(ApplicationRunInformation appInfo)
128 {
Jose Pascoalca875e52014-11-24 12:34:59 +0000129 // obtain the cached app information
130 ApplicationRunInformation cachedApp = _appRunInfos.get(ApplicationRunInformation.serializeComponentName(appInfo.getComponentName()));
131 // if does not exist, create one
Tiago Costa4a8d6ab2015-01-12 16:19:07 +0000132 if (cachedApp == null)
133 {
Filipe Gonçalvesa804b282015-06-23 17:47:42 +0100134 Log.d(TAG, "No entry yet");
Jose Pascoalca875e52014-11-24 12:34:59 +0000135 _appRunInfos.put(ApplicationRunInformation.serializeComponentName(appInfo.getComponentName()), appInfo);
Tiago Costa4a8d6ab2015-01-12 16:19:07 +0000136
Jose Pascoalca875e52014-11-24 12:34:59 +0000137 cachedApp = appInfo;
Tiago Costa4a8d6ab2015-01-12 16:19:07 +0000138
Jose Pascoalca875e52014-11-24 12:34:59 +0000139 cachedApp.resetCount();
140 }
Tiago Costa4a8d6ab2015-01-12 16:19:07 +0000141
Jose Pascoalca875e52014-11-24 12:34:59 +0000142 // increment count
143 cachedApp.incrementCount();
Tiago Costa4a8d6ab2015-01-12 16:19:07 +0000144
145 Log.d(TAG, "Logging application : " + cachedApp.getComponentName() + " : " + cachedApp.getCount());
146
Jose Pascoalca875e52014-11-24 12:34:59 +0000147 // set the current time for the last execution
148 cachedApp.setLastExecution(appInfo.getLastExecution());
Tiago Costa4a8d6ab2015-01-12 16:19:07 +0000149
150 cachedApp.setIsNewApp(false);
Jose Pascoald9412b82015-01-12 19:56:12 +0000151 cachedApp.setIsUpdatedApp(false);
Tiago Costa4a8d6ab2015-01-12 16:19:07 +0000152 cachedApp.setIsPinnedApp(appInfo.isPinnedApp());
153
154 // update the informations
155 updateAppInformation();
156 }
157
Jose Pascoal23699092015-01-13 19:55:32 +0000158 public boolean applicationPinned(ApplicationRunInformation appInfo)
Tiago Costa4a8d6ab2015-01-12 16:19:07 +0000159 {
160 // obtain the cached app information
161 ApplicationRunInformation cachedApp = _appRunInfos.get(ApplicationRunInformation.serializeComponentName(appInfo.getComponentName()));
162 // if does not exist, create one
163 if (cachedApp == null)
164 {
165 _appRunInfos.put(ApplicationRunInformation.serializeComponentName(appInfo.getComponentName()), appInfo);
166
167 cachedApp = appInfo;
168 cachedApp.setIsPinnedApp(false);
Jose Pascoal23699092015-01-13 19:55:32 +0000169 cachedApp.setIsNewApp(false);
170 cachedApp.setIsUpdatedApp(false);
Tiago Costa4a8d6ab2015-01-12 16:19:07 +0000171 cachedApp.resetCount();
172 }
Tiago Costa4a8d6ab2015-01-12 16:19:07 +0000173 cachedApp.setIsPinnedApp(!cachedApp.isPinnedApp());
Jose Pascoal23699092015-01-13 19:55:32 +0000174 return cachedApp.isPinnedApp();
Tiago Costa4a8d6ab2015-01-12 16:19:07 +0000175 }
176
177 public void applicationInstalled(ApplicationRunInformation appInfo)
178 {
179 // obtain the cached app information
180 ApplicationRunInformation cachedApp = _appRunInfos.get(ApplicationRunInformation.serializeComponentName(appInfo.getComponentName()));
181 // if does not exist, create one
182 if (cachedApp == null)
183 {
184 _appRunInfos.put(ApplicationRunInformation.serializeComponentName(appInfo.getComponentName()), appInfo);
185
186 cachedApp = appInfo;
187
188 cachedApp.resetCount();
189 }
190
Tiago Costa4a8d6ab2015-01-12 16:19:07 +0000191 Log.d(TAG, "Logging application : " + cachedApp.getComponentName() + " : " + cachedApp.getCount());
192
193 // set the current time for the last execution
194 cachedApp.setLastExecution(appInfo.getLastExecution());
195
Jose Pascoalca875e52014-11-24 12:34:59 +0000196 cachedApp.setIsNewApp(true);
Tiago Costa4a8d6ab2015-01-12 16:19:07 +0000197 cachedApp.setIsUpdatedApp(false);
Jose Pascoalca875e52014-11-24 12:34:59 +0000198 cachedApp.setIsPinnedApp(false);
199 }
Tiago Costa4a8d6ab2015-01-12 16:19:07 +0000200
201 public void applicationUpdated(ApplicationRunInformation appInfo)
202 {
Jose Pascoalca875e52014-11-24 12:34:59 +0000203 // obtain the cached app information
Tiago Costa4a8d6ab2015-01-12 16:19:07 +0000204 ApplicationRunInformation cachedApp = _appRunInfos.get(ApplicationRunInformation.serializeComponentName(appInfo.getComponentName()));
205 // if does not exist, create one
206 if (cachedApp == null)
207 {
208 _appRunInfos.put(ApplicationRunInformation.serializeComponentName(appInfo.getComponentName()), appInfo);
209
210 cachedApp = appInfo;
211
212 cachedApp.resetCount();
213 }
214
Tiago Costa4a8d6ab2015-01-12 16:19:07 +0000215 Log.d(TAG, "Logging application : " + cachedApp.getComponentName() + " : " + cachedApp.getCount());
Tiago Costa4a8d6ab2015-01-12 16:19:07 +0000216 cachedApp.setIsNewApp(false);
217 cachedApp.setIsUpdatedApp(true);
Jose Pascoalca875e52014-11-24 12:34:59 +0000218 }
Jose Pascoalca875e52014-11-24 12:34:59 +0000219
Jose Pascoal71794192015-01-15 12:47:08 +0000220 public ApplicationRunInformation getApplicationRunInformation(Context context, ComponentName componentName)
Tiago Costa4a8d6ab2015-01-12 16:19:07 +0000221 {
Jose Pascoal23699092015-01-13 19:55:32 +0000222 // obtain the cached app information
223 ApplicationRunInformation cachedApp = _appRunInfos.get(ApplicationRunInformation.serializeComponentName(componentName));
224 //update age
225 if (cachedApp != null)
226 {
Jose Pascoal71794192015-01-15 12:47:08 +0000227 updateAgeInfo(context, cachedApp);
Jose Pascoal23699092015-01-13 19:55:32 +0000228 }
229
230 return cachedApp;
231 }
232
Jose Pascoal8bdb3642015-02-13 13:15:11 +0000233 private static void updateAgeInfo(Context context, ApplicationRunInformation appRunInfo)
Jose Pascoal23699092015-01-13 19:55:32 +0000234 {
235 if(appRunInfo != null)
236 {
237 Date now = Calendar.getInstance().getTime();
238 long timePastSinceLastExec = now.getTime() - appRunInfo.getLastExecution().getTime();
239 boolean isPinned = appRunInfo.isPinnedApp();
240
Jose Pascoal71794192015-01-15 12:47:08 +0000241 if (timePastSinceLastExec < ApplicationRunInformation.getAgeLevelInMiliseconds(context, APP_AGE.FREQUENT_USE) || isPinned)
Jose Pascoal23699092015-01-13 19:55:32 +0000242 {
243 appRunInfo.setAge(APP_AGE.FREQUENT_USE);
244 }
245 else
246 {
247 appRunInfo.setAge(APP_AGE.RARE_USE);
248 }
249 }
Tiago Costa4a8d6ab2015-01-12 16:19:07 +0000250 }
Jose Pascoalca875e52014-11-24 12:34:59 +0000251
Tiago Costa4a8d6ab2015-01-12 16:19:07 +0000252 public void applicationRemoved(ComponentName component)
253 {
254 // remove data
255 ApplicationRunInformation appInfo = _appRunInfos.remove(ApplicationRunInformation.serializeComponentName(component));
Jose Pascoalca875e52014-11-24 12:34:59 +0000256
Tiago Costa4a8d6ab2015-01-12 16:19:07 +0000257 // if does not exist return
258 if (appInfo == null)
259 {
260 return;
261 }
Jose Pascoalca875e52014-11-24 12:34:59 +0000262
Tiago Costa4a8d6ab2015-01-12 16:19:07 +0000263 // if its being used in the lists refactor the lists
264 if (_updateLists)
265 {
266 if (_mostUsed.contains(appInfo) || _recentApps.contains(appInfo))
267 {
268 updateAppInformation();
269 }
270 }
271 }
272
273 private void updateAppInformation()
274 {
275 if (_updateLists)
276 {
277 _mostUsed.clear();
278 _recentApps.clear();
279
280 // most used
281 // calculate the most used
282 for (ApplicationRunInformation current : _appRunInfos.values())
283 {
284
285 if (current.getCount() >= MINIMAL_COUNT)
286 {
287 addByCount(current, _mostUsed, _mostUsedAppsLimit);
288 }
289 }
290
291 printMostUsedApps();
292
293 // calculate the most recent
294 for (ApplicationRunInformation current : _appRunInfos.values())
295 {
296 if (!_mostUsed.contains(current))
297 {
298 addByDate(current, _recentApps, _recentAppsLimit);
299 }
300 }
301
302 printRecentApps();
303 }
304 }
305
306 private void printRecentApps()
307 {
308 for (ApplicationRunInformation current : _recentApps)
309 {
310 Log.d(TAG, "Fairphone RecentApps - " + current);
311 }
312 }
313
314 private void printMostUsedApps()
315 {
316 for (ApplicationRunInformation current : _mostUsed)
317 {
318 Log.d(TAG, "Fairphone MostUsed - " + current);
319 }
320 }
321
322 private static void addByDate(ApplicationRunInformation info, LimitedQueue<ApplicationRunInformation> queue, int limit)
323 {
324 for (int insertIdx = 0; insertIdx < queue.size(); insertIdx++)
Jose Pascoalca875e52014-11-24 12:34:59 +0000325 {
326 if (queue.get(insertIdx).getLastExecution().before(info.getLastExecution()))
327 {
Tiago Costa4a8d6ab2015-01-12 16:19:07 +0000328 queue.add(insertIdx, info);
Jose Pascoalca875e52014-11-24 12:34:59 +0000329
330 return;
331 }
332 }
333
Tiago Costa4a8d6ab2015-01-12 16:19:07 +0000334 if (queue.size() < limit)
Jose Pascoalca875e52014-11-24 12:34:59 +0000335 {
Tiago Costa4a8d6ab2015-01-12 16:19:07 +0000336 queue.addLast(info);
Jose Pascoalca875e52014-11-24 12:34:59 +0000337 }
338 }
339
Tiago Costa4a8d6ab2015-01-12 16:19:07 +0000340 private static void addByCount(ApplicationRunInformation info, LimitedQueue<ApplicationRunInformation> queue, int limit)
341 {
342 for (int insertIdx = 0; insertIdx < queue.size(); insertIdx++)
343 {
344 Log.d(TAG, "Fairphone - Contacting ... " + queue.get(insertIdx));
345 if (info.getCount() > queue.get(insertIdx).getCount())
346 {
347 Log.d(TAG, "FairPhone - Qs : " + queue.size() + " : Most Used : Adding " + info.getComponentName() + " to position " + insertIdx);
348 queue.add(insertIdx, info);
Jose Pascoalca875e52014-11-24 12:34:59 +0000349
Tiago Costa4a8d6ab2015-01-12 16:19:07 +0000350 return;
351 }
352 }
353
354 Log.d(TAG, "Fairphone - Qs : " + queue.size() + " : Most Used : Adding " + info.getComponentName() + " to first position ");
355 if (queue.size() < limit)
356 {
357 queue.addLast(info);
358 }
359 }
360
361 private static class LimitedQueue<E> extends LinkedList<E>
362 {
363
364 /**
Jose Pascoalca875e52014-11-24 12:34:59 +0000365 *
366 */
Tiago Costa4a8d6ab2015-01-12 16:19:07 +0000367 private static final long serialVersionUID = 8174761694444365605L;
368 private final int limit;
Jose Pascoalca875e52014-11-24 12:34:59 +0000369
Tiago Costa4a8d6ab2015-01-12 16:19:07 +0000370 public LimitedQueue(int limit)
371 {
372 this.limit = limit;
373 }
Jose Pascoalca875e52014-11-24 12:34:59 +0000374
Tiago Costa4a8d6ab2015-01-12 16:19:07 +0000375 @Override
376 public void add(int idx, E o)
377 {
378 super.add(idx, o);
Jose Pascoalca875e52014-11-24 12:34:59 +0000379
Tiago Costa4a8d6ab2015-01-12 16:19:07 +0000380 while (size() > limit)
381 {
382 super.removeLast();
383 }
384 }
Jose Pascoalca875e52014-11-24 12:34:59 +0000385
Tiago Costa4a8d6ab2015-01-12 16:19:07 +0000386 @Override
387 public boolean add(E o)
388 {
389 super.addLast(o);
390 while (size() > limit)
391 {
392 super.removeLast();
393 }
394 return true;
395 }
396 }
Jose Pascoalca875e52014-11-24 12:34:59 +0000397
Tiago Costa4a8d6ab2015-01-12 16:19:07 +0000398 public List<ApplicationRunInformation> getRecentApps()
399 {
Jose Pascoalca875e52014-11-24 12:34:59 +0000400
Tiago Costa4a8d6ab2015-01-12 16:19:07 +0000401 Log.d(TAG, "Fairphone - Getting recent apps... " + _recentApps.size());
402 return _recentApps;
403 }
404
405 public List<ApplicationRunInformation> getMostUsedApps()
406 {
407 Log.d(TAG, "Fairphone - Getting most Used apps... " + _mostUsed.size());
408
409 return _mostUsed;
410 }
411
412 public int getMostUsedAppsLimit()
413 {
414 return _mostUsedAppsLimit;
415 }
416
417 public int getRecentAppsLimit()
418 {
419 return _recentAppsLimit;
420 }
421
422 public List<ApplicationRunInformation> getAllAppRunInfo()
423 {
424 return new ArrayList<ApplicationRunInformation>(_appRunInfos.values());
425 }
426
427 public void setAllRunInfo(List<ApplicationRunInformation> allApps)
428 {
Filiped63c86b2015-07-31 12:29:22 +0000429 if (_updateLists) {
430 resetState();
431 }
Tiago Costa4a8d6ab2015-01-12 16:19:07 +0000432
433 for (ApplicationRunInformation app : allApps)
434 {
435 _appRunInfos.put(ApplicationRunInformation.serializeComponentName(app.getComponentName()), app);
436 }
437
438 updateAppInformation();
439 }
Jose Pascoalca875e52014-11-24 12:34:59 +0000440
441}