blob: 7f4a6b1ba085f7296d95de5888c44323d7132c56 [file] [log] [blame]
/*
* Copyright (C) 2013 Fairphone Project
*
* 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.fairphone.fplauncher3.widgets.appswitcher;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import android.content.ComponentName;
import android.content.Context;
import android.util.Log;
import com.fairphone.fplauncher3.widgets.appswitcher.ApplicationRunInformation.APP_AGE;
/**
* This class processes the count for the most used apps and the most recent.
*
* @author Tiago Costa
*
*/
public class ApplicationRunInfoManager
{
public static final int RECENT_APP_MAX_COUNT_LIMIT = 5;
public static final int MOST_APP_MAX_COUNT_LIMIT = 5;
public static final int MINIMAL_COUNT = 2;
private static final String TAG = ApplicationRunInfoManager.class.getSimpleName();
private LimitedQueue<ApplicationRunInformation> _mostUsed;
private LimitedQueue<ApplicationRunInformation> _recentApps;
private Map<String, ApplicationRunInformation> _appRunInfos;
private int _mostUsedAppsLimit;
private int _recentAppsLimit;
private final boolean _updateLists;
public ApplicationRunInfoManager(boolean updateLists)
{
this._updateLists = updateLists;
_appRunInfos = new HashMap<String, ApplicationRunInformation>();
if (_updateLists)
{
setUpLimits(MOST_APP_MAX_COUNT_LIMIT, RECENT_APP_MAX_COUNT_LIMIT);
}
}
public static ApplicationRunInformation generateApplicationRunInfo(ComponentName component, boolean isFreshInstall, boolean isUpdated)
{
ApplicationRunInformation appInfo = new ApplicationRunInformation(component);
appInfo.incrementCount();
appInfo.setLastExecution(Calendar.getInstance().getTime());
appInfo.setIsNewApp(isFreshInstall);
appInfo.setIsPinnedApp(false);
appInfo.setIsUpdatedApp(isUpdated);
return appInfo;
}
public static ApplicationRunInformation generateApplicationRunInfo(ComponentName component, boolean isFreshInstall)
{
return generateApplicationRunInfo(component, isFreshInstall, false);
}
public void setUpLimits(int maxMostUsed, int maxRecentApps)
{
_mostUsedAppsLimit = maxMostUsed;
_recentAppsLimit = maxRecentApps;
// refactor the limits
setUpNewLimits();
}
private void setUpNewLimits()
{
_mostUsed = new LimitedQueue<ApplicationRunInformation>(_mostUsedAppsLimit);
_recentApps = new LimitedQueue<ApplicationRunInformation>(_recentAppsLimit);
// update the information
if (_appRunInfos != null)
{
updateAppInformation();
}
}
public void loadNewRunInformation(List<ApplicationRunInformation> allApps)
{
// clear the current state
resetState();
// add application to the bag
for (ApplicationRunInformation appInfo : allApps)
{
_appRunInfos.put(ApplicationRunInformation.serializeComponentName(appInfo.getComponentName()), appInfo);
}
// update the information
updateAppInformation();
}
public void resetState()
{
if (_updateLists)
{
_mostUsed.clear();
_recentApps.clear();
}
_appRunInfos.clear();
}
public void applicationStarted(ApplicationRunInformation appInfo)
{
// obtain the cached app information
ApplicationRunInformation cachedApp = _appRunInfos.get(ApplicationRunInformation.serializeComponentName(appInfo.getComponentName()));
// if does not exist, create one
if (cachedApp == null)
{
Log.d(TAG, "No entry yet");
_appRunInfos.put(ApplicationRunInformation.serializeComponentName(appInfo.getComponentName()), appInfo);
cachedApp = appInfo;
cachedApp.resetCount();
}
// increment count
cachedApp.incrementCount();
Log.d(TAG, "Logging application : " + cachedApp.getComponentName() + " : " + cachedApp.getCount());
// set the current time for the last execution
cachedApp.setLastExecution(appInfo.getLastExecution());
cachedApp.setIsNewApp(false);
cachedApp.setIsUpdatedApp(false);
cachedApp.setIsPinnedApp(appInfo.isPinnedApp());
// update the informations
updateAppInformation();
}
public boolean applicationPinned(ApplicationRunInformation appInfo)
{
// obtain the cached app information
ApplicationRunInformation cachedApp = _appRunInfos.get(ApplicationRunInformation.serializeComponentName(appInfo.getComponentName()));
// if does not exist, create one
if (cachedApp == null)
{
_appRunInfos.put(ApplicationRunInformation.serializeComponentName(appInfo.getComponentName()), appInfo);
cachedApp = appInfo;
cachedApp.setIsPinnedApp(false);
cachedApp.setIsNewApp(false);
cachedApp.setIsUpdatedApp(false);
cachedApp.resetCount();
}
cachedApp.setIsPinnedApp(!cachedApp.isPinnedApp());
return cachedApp.isPinnedApp();
}
public void applicationInstalled(ApplicationRunInformation appInfo)
{
// obtain the cached app information
ApplicationRunInformation cachedApp = _appRunInfos.get(ApplicationRunInformation.serializeComponentName(appInfo.getComponentName()));
// if does not exist, create one
if (cachedApp == null)
{
_appRunInfos.put(ApplicationRunInformation.serializeComponentName(appInfo.getComponentName()), appInfo);
cachedApp = appInfo;
cachedApp.resetCount();
}
Log.d(TAG, "Logging application : " + cachedApp.getComponentName() + " : " + cachedApp.getCount());
// set the current time for the last execution
cachedApp.setLastExecution(appInfo.getLastExecution());
cachedApp.setIsNewApp(true);
cachedApp.setIsUpdatedApp(false);
cachedApp.setIsPinnedApp(false);
}
public void applicationUpdated(ApplicationRunInformation appInfo)
{
// obtain the cached app information
ApplicationRunInformation cachedApp = _appRunInfos.get(ApplicationRunInformation.serializeComponentName(appInfo.getComponentName()));
// if does not exist, create one
if (cachedApp == null)
{
_appRunInfos.put(ApplicationRunInformation.serializeComponentName(appInfo.getComponentName()), appInfo);
cachedApp = appInfo;
cachedApp.resetCount();
}
Log.d(TAG, "Logging application : " + cachedApp.getComponentName() + " : " + cachedApp.getCount());
cachedApp.setIsNewApp(false);
cachedApp.setIsUpdatedApp(true);
}
public ApplicationRunInformation getApplicationRunInformation(Context context, ComponentName componentName)
{
// obtain the cached app information
ApplicationRunInformation cachedApp = _appRunInfos.get(ApplicationRunInformation.serializeComponentName(componentName));
//update age
if (cachedApp != null)
{
updateAgeInfo(context, cachedApp);
}
return cachedApp;
}
private static void updateAgeInfo(Context context, ApplicationRunInformation appRunInfo)
{
if(appRunInfo != null)
{
Date now = Calendar.getInstance().getTime();
long timePastSinceLastExec = now.getTime() - appRunInfo.getLastExecution().getTime();
boolean isPinned = appRunInfo.isPinnedApp();
if (timePastSinceLastExec < ApplicationRunInformation.getAgeLevelInMiliseconds(context, APP_AGE.FREQUENT_USE) || isPinned)
{
appRunInfo.setAge(APP_AGE.FREQUENT_USE);
}
else
{
appRunInfo.setAge(APP_AGE.RARE_USE);
}
}
}
public void applicationRemoved(ComponentName component)
{
// remove data
ApplicationRunInformation appInfo = _appRunInfos.remove(ApplicationRunInformation.serializeComponentName(component));
// if does not exist return
if (appInfo == null)
{
return;
}
// if its being used in the lists refactor the lists
if (_updateLists)
{
if (_mostUsed.contains(appInfo) || _recentApps.contains(appInfo))
{
updateAppInformation();
}
}
}
private void updateAppInformation()
{
if (_updateLists)
{
_mostUsed.clear();
_recentApps.clear();
// most used
// calculate the most used
for (ApplicationRunInformation current : _appRunInfos.values())
{
if (current.getCount() >= MINIMAL_COUNT)
{
addByCount(current, _mostUsed, _mostUsedAppsLimit);
}
}
printMostUsedApps();
// calculate the most recent
for (ApplicationRunInformation current : _appRunInfos.values())
{
if (!_mostUsed.contains(current))
{
addByDate(current, _recentApps, _recentAppsLimit);
}
}
printRecentApps();
}
}
private void printRecentApps()
{
for (ApplicationRunInformation current : _recentApps)
{
Log.d(TAG, "Fairphone RecentApps - " + current);
}
}
private void printMostUsedApps()
{
for (ApplicationRunInformation current : _mostUsed)
{
Log.d(TAG, "Fairphone MostUsed - " + current);
}
}
private static void addByDate(ApplicationRunInformation info, LimitedQueue<ApplicationRunInformation> queue, int limit)
{
for (int insertIdx = 0; insertIdx < queue.size(); insertIdx++)
{
if (queue.get(insertIdx).getLastExecution().before(info.getLastExecution()))
{
queue.add(insertIdx, info);
return;
}
}
if (queue.size() < limit)
{
queue.addLast(info);
}
}
private static void addByCount(ApplicationRunInformation info, LimitedQueue<ApplicationRunInformation> queue, int limit)
{
for (int insertIdx = 0; insertIdx < queue.size(); insertIdx++)
{
Log.d(TAG, "Fairphone - Contacting ... " + queue.get(insertIdx));
if (info.getCount() > queue.get(insertIdx).getCount())
{
Log.d(TAG, "FairPhone - Qs : " + queue.size() + " : Most Used : Adding " + info.getComponentName() + " to position " + insertIdx);
queue.add(insertIdx, info);
return;
}
}
Log.d(TAG, "Fairphone - Qs : " + queue.size() + " : Most Used : Adding " + info.getComponentName() + " to first position ");
if (queue.size() < limit)
{
queue.addLast(info);
}
}
private static class LimitedQueue<E> extends LinkedList<E>
{
/**
*
*/
private static final long serialVersionUID = 8174761694444365605L;
private final int limit;
public LimitedQueue(int limit)
{
this.limit = limit;
}
@Override
public void add(int idx, E o)
{
super.add(idx, o);
while (size() > limit)
{
super.removeLast();
}
}
@Override
public boolean add(E o)
{
super.addLast(o);
while (size() > limit)
{
super.removeLast();
}
return true;
}
}
public List<ApplicationRunInformation> getRecentApps()
{
Log.d(TAG, "Fairphone - Getting recent apps... " + _recentApps.size());
return _recentApps;
}
public List<ApplicationRunInformation> getMostUsedApps()
{
Log.d(TAG, "Fairphone - Getting most Used apps... " + _mostUsed.size());
return _mostUsed;
}
public int getMostUsedAppsLimit()
{
return _mostUsedAppsLimit;
}
public int getRecentAppsLimit()
{
return _recentAppsLimit;
}
public List<ApplicationRunInformation> getAllAppRunInfo()
{
return new ArrayList<ApplicationRunInformation>(_appRunInfos.values());
}
public void setAllRunInfo(List<ApplicationRunInformation> allApps)
{
if (_updateLists) {
resetState();
}
for (ApplicationRunInformation app : allApps)
{
_appRunInfos.put(ApplicationRunInformation.serializeComponentName(app.getComponentName()), app);
}
updateAppInformation();
}
}