1 /* 2 * Copyright (C) 2017 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 package com.android.documentsui; 17 18 import android.annotation.DrawableRes; 19 import android.content.Context; 20 import android.content.Intent; 21 import android.content.pm.ShortcutInfo; 22 import android.content.pm.ShortcutManager; 23 import android.graphics.drawable.Icon; 24 25 import com.android.documentsui.R; 26 import com.android.documentsui.base.Providers; 27 import com.android.documentsui.base.RootInfo; 28 import com.android.documentsui.files.FilesActivity; 29 import com.android.documentsui.prefs.ScopedPreferences; 30 31 import java.util.ArrayList; 32 import java.util.Collection; 33 import java.util.HashMap; 34 import java.util.List; 35 import java.util.Map; 36 37 /** 38 * Manages dynamic shortcuts. 39 */ 40 public final class ShortcutsUpdater { 41 42 private final ScopedPreferences mPrefs; 43 private final Context mContext; 44 ShortcutsUpdater(Context context, ScopedPreferences prefs)45 public ShortcutsUpdater(Context context, ScopedPreferences prefs) { 46 mContext = context; 47 mPrefs = prefs; 48 } 49 update(Collection<RootInfo> roots)50 public void update(Collection<RootInfo> roots) { 51 ShortcutManager mgr = mContext.getSystemService(ShortcutManager.class); 52 53 Map<String, ShortcutInfo> existing = getPinnedShortcuts(mgr); 54 List<ShortcutInfo> devices = getDeviceShortcuts(roots); 55 List<String> deviceIds = new ArrayList<>(); 56 for (ShortcutInfo s : devices) { 57 deviceIds.add(s.getId()); 58 } 59 60 mgr.setDynamicShortcuts(devices.subList(0, getNumDynSlots(mgr, devices.size()))); 61 62 // Mark any shortcut that doesn't correspond to a current root as disabled. 63 List<String> disabled = new ArrayList<>(); 64 for (String id : existing.keySet()) { 65 // If it isn't in candidates, it isn't a live target, so we disable it. 66 if (!deviceIds.contains(id)) { 67 disabled.add(id); 68 } 69 } 70 71 mgr.enableShortcuts(deviceIds); 72 mgr.disableShortcuts(disabled); 73 } 74 75 /** 76 * Return at most four awesome devices/roots to include as dynamic shortcuts. 77 */ getDeviceShortcuts(Collection<RootInfo> roots)78 private List<ShortcutInfo> getDeviceShortcuts(Collection<RootInfo> roots) { 79 List<ShortcutInfo> devices = new ArrayList<>(); 80 for (RootInfo root : roots) { 81 String id = root.getUri().toString(); 82 // TODO: Hook up third party providers. For now, there may be dupes when 83 // user has multiple accounts installed, and the plain title doesn't 84 // disambiguate for the user. So, we don't add them. 85 // if (!Providers.isSystemProvider(root.authority)) { 86 // // add third party providers at the beginning of the list. 87 // devices.add(createShortcut(root, R.drawable.ic_folder_shortcut)); 88 // } else 89 if (root.isAdvanced() && root.authority.equals(Providers.AUTHORITY_STORAGE)) { 90 // internal storage 91 if (mPrefs.getShowDeviceRoot()) { 92 devices.add(0, createShortcut(root, R.drawable.ic_advanced_shortcut)); 93 } 94 } else if (root.isAdvanced()) { 95 // probably just bugreports provider 96 devices.add(0, createShortcut(root, R.drawable.ic_folder_shortcut)); 97 } 98 // TODO: Hook up USB and MTP devices. In order to do this we need 99 // to fire up a broadcast to listen for ACTION_MEDIA_MOUNTED 100 // and ACTION_MEDIA_REMOVED. But doing so now would require a good 101 // bit of refactoring, rendering out of scope for now. <sadface>. 102 // else if (root.isUsb() || root.isMtp()) { 103 // // probably just bugreports provider 104 // devices.add(0, createShortcut(root, R.drawable.ic_usb_shortcut)); 105 // } 106 } 107 108 return devices; 109 } 110 getPinnedShortcuts(ShortcutManager mgr)111 private Map<String, ShortcutInfo> getPinnedShortcuts(ShortcutManager mgr) { 112 Map<String, ShortcutInfo> pinned = new HashMap<>(); 113 for (ShortcutInfo s : mgr.getDynamicShortcuts()) { 114 pinned.put(s.getId(), s); 115 } 116 return pinned; 117 } 118 getNumDynSlots(ShortcutManager mgr, int numDevices)119 private int getNumDynSlots(ShortcutManager mgr, int numDevices) { 120 int slots = mgr.getMaxShortcutCountForActivity() - mgr.getManifestShortcuts().size(); 121 return numDevices >= slots ? slots : numDevices; 122 } 123 createShortcut(RootInfo root, @DrawableRes int resId)124 private ShortcutInfo createShortcut(RootInfo root, @DrawableRes int resId) { 125 Intent intent = new Intent(mContext, FilesActivity.class); 126 intent.setAction(Intent.ACTION_VIEW); 127 intent.setData(root.getUri()); 128 129 return new ShortcutInfo.Builder(mContext, root.getUri().toString()) 130 .setShortLabel(root.title) 131 .setIcon(Icon.createWithResource(mContext, resId)) 132 .setIntent(intent) 133 .build(); 134 } 135 } 136