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.content.Context; 19 import android.content.Intent; 20 import android.content.pm.ShortcutInfo; 21 import android.content.pm.ShortcutManager; 22 import android.graphics.drawable.Icon; 23 24 import androidx.annotation.DrawableRes; 25 26 import com.android.documentsui.base.Providers; 27 import com.android.documentsui.base.RootInfo; 28 import com.android.documentsui.base.Shared; 29 import com.android.documentsui.files.FilesActivity; 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 Context mContext; 43 ShortcutsUpdater(Context context)44 public ShortcutsUpdater(Context context) { 45 mContext = context; 46 } 47 update(Collection<RootInfo> roots)48 public void update(Collection<RootInfo> roots) { 49 if (!Shared.isLauncherEnabled(mContext)) { 50 return; 51 } 52 53 ShortcutManager mgr = mContext.getSystemService(ShortcutManager.class); 54 55 Map<String, ShortcutInfo> existing = getPinnedShortcuts(mgr); 56 List<ShortcutInfo> devices = getDeviceShortcuts(roots); 57 List<String> deviceIds = new ArrayList<>(); 58 for (ShortcutInfo s : devices) { 59 deviceIds.add(s.getId()); 60 } 61 62 mgr.setDynamicShortcuts(devices.subList(0, getNumDynSlots(mgr, devices.size()))); 63 64 // Mark any shortcut that doesn't correspond to a current root as disabled. 65 List<String> disabled = new ArrayList<>(); 66 for (String id : existing.keySet()) { 67 // If it isn't in candidates, it isn't a live target, so we disable it. 68 if (!deviceIds.contains(id)) { 69 disabled.add(id); 70 } 71 } 72 73 mgr.enableShortcuts(deviceIds); 74 mgr.disableShortcuts(disabled); 75 } 76 77 /** 78 * Return at most four awesome devices/roots to include as dynamic shortcuts. 79 */ getDeviceShortcuts(Collection<RootInfo> roots)80 private List<ShortcutInfo> getDeviceShortcuts(Collection<RootInfo> roots) { 81 List<ShortcutInfo> devices = new ArrayList<>(); 82 for (RootInfo root : roots) { 83 String id = root.getUri().toString(); 84 // TODO: Hook up third party providers. For now, there may be dupes when 85 // user has multiple accounts installed, and the plain title doesn't 86 // disambiguate for the user. So, we don't add them. 87 // if (!Providers.isSystemProvider(root.authority)) { 88 // // add third party providers at the beginning of the list. 89 // devices.add(createShortcut(root, R.drawable.ic_folder_shortcut)); 90 // } else 91 if (root.isAdvanced() && root.authority.equals(Providers.AUTHORITY_STORAGE)) { 92 // internal storage 93 devices.add(0, createShortcut(root, R.drawable.ic_advanced_shortcut)); 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.getMaxShortcutCountPerActivity() - 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