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