Home | History | Annotate | Download | only in shortcuts
      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 
     17 package com.android.launcher3.shortcuts;
     18 
     19 import android.annotation.TargetApi;
     20 import android.content.ComponentName;
     21 import android.content.Context;
     22 import android.content.pm.LauncherApps;
     23 import android.content.pm.LauncherApps.ShortcutQuery;
     24 import android.content.pm.ShortcutInfo;
     25 import android.graphics.Rect;
     26 import android.graphics.drawable.Drawable;
     27 import android.os.Bundle;
     28 import android.os.UserHandle;
     29 import android.util.Log;
     30 
     31 import com.android.launcher3.ItemInfo;
     32 import com.android.launcher3.LauncherSettings;
     33 import com.android.launcher3.Utilities;
     34 
     35 import java.util.ArrayList;
     36 import java.util.Collections;
     37 import java.util.List;
     38 
     39 /**
     40  * Performs operations related to deep shortcuts, such as querying for them, pinning them, etc.
     41  */
     42 public class DeepShortcutManager {
     43     private static final String TAG = "DeepShortcutManager";
     44 
     45     private static final int FLAG_GET_ALL = ShortcutQuery.FLAG_MATCH_DYNAMIC
     46             | ShortcutQuery.FLAG_MATCH_MANIFEST | ShortcutQuery.FLAG_MATCH_PINNED;
     47 
     48     private static DeepShortcutManager sInstance;
     49     private static final Object sInstanceLock = new Object();
     50 
     51     public static DeepShortcutManager getInstance(Context context) {
     52         synchronized (sInstanceLock) {
     53             if (sInstance == null) {
     54                 sInstance = new DeepShortcutManager(context.getApplicationContext());
     55             }
     56             return sInstance;
     57         }
     58     }
     59 
     60     private final LauncherApps mLauncherApps;
     61     private boolean mWasLastCallSuccess;
     62 
     63     private DeepShortcutManager(Context context) {
     64         mLauncherApps = (LauncherApps) context.getSystemService(Context.LAUNCHER_APPS_SERVICE);
     65     }
     66 
     67     public static boolean supportsShortcuts(ItemInfo info) {
     68         boolean isItemPromise = info instanceof com.android.launcher3.ShortcutInfo
     69                 && ((com.android.launcher3.ShortcutInfo) info).hasPromiseIconUi();
     70         return info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION
     71                 && !info.isDisabled() && !isItemPromise;
     72     }
     73 
     74     public boolean wasLastCallSuccess() {
     75         return mWasLastCallSuccess;
     76     }
     77 
     78     public void onShortcutsChanged(List<ShortcutInfoCompat> shortcuts) {
     79         // mShortcutCache.removeShortcuts(shortcuts);
     80     }
     81 
     82     /**
     83      * Queries for the shortcuts with the package name and provided ids.
     84      *
     85      * This method is intended to get the full details for shortcuts when they are added or updated,
     86      * because we only get "key" fields in onShortcutsChanged().
     87      */
     88     public List<ShortcutInfoCompat> queryForFullDetails(String packageName,
     89             List<String> shortcutIds, UserHandle user) {
     90         return query(FLAG_GET_ALL, packageName, null, shortcutIds, user);
     91     }
     92 
     93     /**
     94      * Gets all the manifest and dynamic shortcuts associated with the given package and user,
     95      * to be displayed in the shortcuts container on long press.
     96      */
     97     public List<ShortcutInfoCompat> queryForShortcutsContainer(ComponentName activity,
     98             List<String> ids, UserHandle user) {
     99         return query(ShortcutQuery.FLAG_MATCH_MANIFEST | ShortcutQuery.FLAG_MATCH_DYNAMIC,
    100                 activity.getPackageName(), activity, ids, user);
    101     }
    102 
    103     /**
    104      * Removes the given shortcut from the current list of pinned shortcuts.
    105      * (Runs on background thread)
    106      */
    107     @TargetApi(25)
    108     public void unpinShortcut(final ShortcutKey key) {
    109         if (Utilities.ATLEAST_NOUGAT_MR1) {
    110             String packageName = key.componentName.getPackageName();
    111             String id = key.getId();
    112             UserHandle user = key.user;
    113             List<String> pinnedIds = extractIds(queryForPinnedShortcuts(packageName, user));
    114             pinnedIds.remove(id);
    115             try {
    116                 mLauncherApps.pinShortcuts(packageName, pinnedIds, user);
    117                 mWasLastCallSuccess = true;
    118             } catch (SecurityException|IllegalStateException e) {
    119                 Log.w(TAG, "Failed to unpin shortcut", e);
    120                 mWasLastCallSuccess = false;
    121             }
    122         }
    123     }
    124 
    125     /**
    126      * Adds the given shortcut to the current list of pinned shortcuts.
    127      * (Runs on background thread)
    128      */
    129     @TargetApi(25)
    130     public void pinShortcut(final ShortcutKey key) {
    131         if (Utilities.ATLEAST_NOUGAT_MR1) {
    132             String packageName = key.componentName.getPackageName();
    133             String id = key.getId();
    134             UserHandle user = key.user;
    135             List<String> pinnedIds = extractIds(queryForPinnedShortcuts(packageName, user));
    136             pinnedIds.add(id);
    137             try {
    138                 mLauncherApps.pinShortcuts(packageName, pinnedIds, user);
    139                 mWasLastCallSuccess = true;
    140             } catch (SecurityException|IllegalStateException e) {
    141                 Log.w(TAG, "Failed to pin shortcut", e);
    142                 mWasLastCallSuccess = false;
    143             }
    144         }
    145     }
    146 
    147     @TargetApi(25)
    148     public void startShortcut(String packageName, String id, Rect sourceBounds,
    149           Bundle startActivityOptions, UserHandle user) {
    150         if (Utilities.ATLEAST_NOUGAT_MR1) {
    151             try {
    152                 mLauncherApps.startShortcut(packageName, id, sourceBounds,
    153                         startActivityOptions, user);
    154                 mWasLastCallSuccess = true;
    155             } catch (SecurityException|IllegalStateException e) {
    156                 Log.e(TAG, "Failed to start shortcut", e);
    157                 mWasLastCallSuccess = false;
    158             }
    159         }
    160     }
    161 
    162     @TargetApi(25)
    163     public Drawable getShortcutIconDrawable(ShortcutInfoCompat shortcutInfo, int density) {
    164         if (Utilities.ATLEAST_NOUGAT_MR1) {
    165             try {
    166                 Drawable icon = mLauncherApps.getShortcutIconDrawable(
    167                         shortcutInfo.getShortcutInfo(), density);
    168                 mWasLastCallSuccess = true;
    169                 return icon;
    170             } catch (SecurityException|IllegalStateException e) {
    171                 Log.e(TAG, "Failed to get shortcut icon", e);
    172                 mWasLastCallSuccess = false;
    173             }
    174         }
    175         return null;
    176     }
    177 
    178     /**
    179      * Returns the id's of pinned shortcuts associated with the given package and user.
    180      *
    181      * If packageName is null, returns all pinned shortcuts regardless of package.
    182      */
    183     public List<ShortcutInfoCompat> queryForPinnedShortcuts(String packageName, UserHandle user) {
    184         return query(ShortcutQuery.FLAG_MATCH_PINNED, packageName, null, null, user);
    185     }
    186 
    187     public List<ShortcutInfoCompat> queryForAllShortcuts(UserHandle user) {
    188         return query(FLAG_GET_ALL, null, null, null, user);
    189     }
    190 
    191     private List<String> extractIds(List<ShortcutInfoCompat> shortcuts) {
    192         List<String> shortcutIds = new ArrayList<>(shortcuts.size());
    193         for (ShortcutInfoCompat shortcut : shortcuts) {
    194             shortcutIds.add(shortcut.getId());
    195         }
    196         return shortcutIds;
    197     }
    198 
    199     /**
    200      * Query the system server for all the shortcuts matching the given parameters.
    201      * If packageName == null, we query for all shortcuts with the passed flags, regardless of app.
    202      *
    203      * TODO: Use the cache to optimize this so we don't make an RPC every time.
    204      */
    205     @TargetApi(25)
    206     private List<ShortcutInfoCompat> query(int flags, String packageName,
    207             ComponentName activity, List<String> shortcutIds, UserHandle user) {
    208         if (Utilities.ATLEAST_NOUGAT_MR1) {
    209             ShortcutQuery q = new ShortcutQuery();
    210             q.setQueryFlags(flags);
    211             if (packageName != null) {
    212                 q.setPackage(packageName);
    213                 q.setActivity(activity);
    214                 q.setShortcutIds(shortcutIds);
    215             }
    216             List<ShortcutInfo> shortcutInfos = null;
    217             try {
    218                 shortcutInfos = mLauncherApps.getShortcuts(q, user);
    219                 mWasLastCallSuccess = true;
    220             } catch (SecurityException|IllegalStateException e) {
    221                 Log.e(TAG, "Failed to query for shortcuts", e);
    222                 mWasLastCallSuccess = false;
    223             }
    224             if (shortcutInfos == null) {
    225                 return Collections.EMPTY_LIST;
    226             }
    227             List<ShortcutInfoCompat> shortcutInfoCompats = new ArrayList<>(shortcutInfos.size());
    228             for (ShortcutInfo shortcutInfo : shortcutInfos) {
    229                 shortcutInfoCompats.add(new ShortcutInfoCompat(shortcutInfo));
    230             }
    231             return shortcutInfoCompats;
    232         } else {
    233             return Collections.EMPTY_LIST;
    234         }
    235     }
    236 
    237     @TargetApi(25)
    238     public boolean hasHostPermission() {
    239         if (Utilities.ATLEAST_NOUGAT_MR1) {
    240             try {
    241                 return mLauncherApps.hasShortcutHostPermission();
    242             } catch (SecurityException|IllegalStateException e) {
    243                 Log.e(TAG, "Failed to make shortcut manager call", e);
    244             }
    245         }
    246         return false;
    247     }
    248 }
    249