1/* 2 * Copyright (C) 2016 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 17package com.android.launcher3.shortcuts; 18 19import android.support.annotation.VisibleForTesting; 20 21import java.util.ArrayList; 22import java.util.Collections; 23import java.util.Comparator; 24import java.util.List; 25 26/** 27 * Sorts and filters shortcuts. 28 */ 29public class ShortcutFilter { 30 31 public static final int MAX_SHORTCUTS = 4; 32 @VisibleForTesting static final int NUM_DYNAMIC = 2; 33 34 /** 35 * Sorts shortcuts in rank order, with manifest shortcuts coming before dynamic shortcuts. 36 */ 37 private static final Comparator<ShortcutInfoCompat> RANK_COMPARATOR 38 = new Comparator<ShortcutInfoCompat>() { 39 @Override 40 public int compare(ShortcutInfoCompat a, ShortcutInfoCompat b) { 41 if (a.isDeclaredInManifest() && !b.isDeclaredInManifest()) { 42 return -1; 43 } 44 if (!a.isDeclaredInManifest() && b.isDeclaredInManifest()) { 45 return 1; 46 } 47 return Integer.compare(a.getRank(), b.getRank()); 48 } 49 }; 50 51 /** 52 * Filters the shortcuts so that only MAX_SHORTCUTS or fewer shortcuts are retained. 53 * We want the filter to include both static and dynamic shortcuts, so we always 54 * include NUM_DYNAMIC dynamic shortcuts, if at least that many are present. 55 * 56 * @return a subset of shortcuts, in sorted order, with size <= MAX_SHORTCUTS. 57 */ 58 public static List<ShortcutInfoCompat> sortAndFilterShortcuts( 59 List<ShortcutInfoCompat> shortcuts) { 60 Collections.sort(shortcuts, RANK_COMPARATOR); 61 if (shortcuts.size() <= MAX_SHORTCUTS) { 62 return shortcuts; 63 } 64 65 // The list of shortcuts is now sorted with static shortcuts followed by dynamic 66 // shortcuts. We want to preserve this order, but only keep MAX_SHORTCUTS. 67 List<ShortcutInfoCompat> filteredShortcuts = new ArrayList<>(MAX_SHORTCUTS); 68 int numDynamic = 0; 69 int size = shortcuts.size(); 70 for (int i = 0; i < size; i++) { 71 ShortcutInfoCompat shortcut = shortcuts.get(i); 72 int filteredSize = filteredShortcuts.size(); 73 if (filteredSize < MAX_SHORTCUTS) { 74 // Always add the first MAX_SHORTCUTS to the filtered list. 75 filteredShortcuts.add(shortcut); 76 if (shortcut.isDynamic()) { 77 numDynamic++; 78 } 79 continue; 80 } 81 // At this point, we have MAX_SHORTCUTS already, but they may all be static. 82 // If there are dynamic shortcuts, remove static shortcuts to add them. 83 if (shortcut.isDynamic() && numDynamic < NUM_DYNAMIC) { 84 numDynamic++; 85 int lastStaticIndex = filteredSize - numDynamic; 86 filteredShortcuts.remove(lastStaticIndex); 87 filteredShortcuts.add(shortcut); 88 } 89 } 90 return filteredShortcuts; 91 } 92} 93