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