| /* |
| * 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(); |
| } |
| |
| } |