Home | History | Annotate | Download | only in launcher3
      1 /*
      2  * Copyright (C) 2008 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;
     18 
     19 import android.annotation.TargetApi;
     20 import android.content.ComponentName;
     21 import android.content.ContentValues;
     22 import android.content.Context;
     23 import android.content.Intent;
     24 import android.graphics.Bitmap;
     25 import android.graphics.drawable.Drawable;
     26 import android.os.Build;
     27 import android.text.TextUtils;
     28 
     29 import com.android.launcher3.LauncherSettings.Favorites;
     30 import com.android.launcher3.compat.LauncherActivityInfoCompat;
     31 import com.android.launcher3.compat.UserHandleCompat;
     32 import com.android.launcher3.compat.UserManagerCompat;
     33 import com.android.launcher3.folder.FolderIcon;
     34 import com.android.launcher3.shortcuts.ShortcutInfoCompat;
     35 
     36 /**
     37  * Represents a launchable icon on the workspaces and in folders.
     38  */
     39 public class ShortcutInfo extends ItemInfo {
     40 
     41     public static final int DEFAULT = 0;
     42 
     43     /**
     44      * The shortcut was restored from a backup and it not ready to be used. This is automatically
     45      * set during backup/restore
     46      */
     47     public static final int FLAG_RESTORED_ICON = 1;
     48 
     49     /**
     50      * The icon was added as an auto-install app, and is not ready to be used. This flag can't
     51      * be present along with {@link #FLAG_RESTORED_ICON}, and is set during default layout
     52      * parsing.
     53      */
     54     public static final int FLAG_AUTOINTALL_ICON = 2; //0B10;
     55 
     56     /**
     57      * The icon is being installed. If {@link #FLAG_RESTORED_ICON} or {@link #FLAG_AUTOINTALL_ICON}
     58      * is set, then the icon is either being installed or is in a broken state.
     59      */
     60     public static final int FLAG_INSTALL_SESSION_ACTIVE = 4; // 0B100;
     61 
     62     /**
     63      * Indicates that the widget restore has started.
     64      */
     65     public static final int FLAG_RESTORE_STARTED = 8; //0B1000;
     66 
     67     /**
     68      * Indicates if it represents a common type mentioned in {@link CommonAppTypeParser}.
     69      * Upto 15 different types supported.
     70      */
     71     public static final int FLAG_RESTORED_APP_TYPE = 0B0011110000;
     72 
     73     /**
     74      * The intent used to start the application.
     75      */
     76     public Intent intent;
     77 
     78     /**
     79      * Indicates whether we're using the default fallback icon instead of something from the
     80      * app.
     81      */
     82     boolean usingFallbackIcon;
     83 
     84     /**
     85      * Indicates whether we're using a low res icon
     86      */
     87     boolean usingLowResIcon;
     88 
     89     /**
     90      * If isShortcut=true and customIcon=false, this contains a reference to the
     91      * shortcut icon as an application's resource.
     92      */
     93     public Intent.ShortcutIconResource iconResource;
     94 
     95     /**
     96      * The application icon.
     97      */
     98     private Bitmap mIcon;
     99 
    100     /**
    101      * Indicates that the icon is disabled due to safe mode restrictions.
    102      */
    103     public static final int FLAG_DISABLED_SAFEMODE = 1 << 0;
    104 
    105     /**
    106      * Indicates that the icon is disabled as the app is not available.
    107      */
    108     public static final int FLAG_DISABLED_NOT_AVAILABLE = 1 << 1;
    109 
    110     /**
    111      * Indicates that the icon is disabled as the app is suspended
    112      */
    113     public static final int FLAG_DISABLED_SUSPENDED = 1 << 2;
    114 
    115     /**
    116      * Indicates that the icon is disabled as the user is in quiet mode.
    117      */
    118     public static final int FLAG_DISABLED_QUIET_USER = 1 << 3;
    119 
    120     /**
    121      * Indicates that the icon is disabled as the publisher has disabled the actual shortcut.
    122      */
    123     public static final int FLAG_DISABLED_BY_PUBLISHER = 1 << 4;
    124 
    125     /**
    126      * Indicates that the icon is disabled as the user partition is currently locked.
    127      */
    128     public static final int FLAG_DISABLED_LOCKED_USER = 1 << 5;
    129 
    130     /**
    131      * Could be disabled, if the the app is installed but unavailable (eg. in safe mode or when
    132      * sd-card is not available).
    133      */
    134     int isDisabled = DEFAULT;
    135 
    136     /**
    137      * A message to display when the user tries to start a disabled shortcut.
    138      * This is currently only used for deep shortcuts.
    139      */
    140     CharSequence disabledMessage;
    141 
    142     int status;
    143 
    144     /**
    145      * The installation progress [0-100] of the package that this shortcut represents.
    146      */
    147     private int mInstallProgress;
    148 
    149     /**
    150      * TODO move this to {@link #status}
    151      */
    152     int flags = 0;
    153 
    154     /**
    155      * If this shortcut is a placeholder, then intent will be a market intent for the package, and
    156      * this will hold the original intent from the database.  Otherwise, null.
    157      * Refer {@link #FLAG_RESTORED_ICON}, {@link #FLAG_AUTOINTALL_ICON}
    158      */
    159     Intent promisedIntent;
    160 
    161     public ShortcutInfo() {
    162         itemType = LauncherSettings.BaseLauncherColumns.ITEM_TYPE_SHORTCUT;
    163     }
    164 
    165     @Override
    166     public Intent getIntent() {
    167         return intent;
    168     }
    169 
    170     /** Returns {@link #promisedIntent}, or {@link #intent} if promisedIntent is null. */
    171     public Intent getPromisedIntent() {
    172         return promisedIntent != null ? promisedIntent : intent;
    173     }
    174 
    175     ShortcutInfo(Intent intent, CharSequence title, CharSequence contentDescription,
    176             Bitmap icon, UserHandleCompat user) {
    177         this();
    178         this.intent = intent;
    179         this.title = Utilities.trim(title);
    180         this.contentDescription = contentDescription;
    181         mIcon = icon;
    182         this.user = user;
    183     }
    184 
    185     public ShortcutInfo(ShortcutInfo info) {
    186         super(info);
    187         title = info.title;
    188         intent = new Intent(info.intent);
    189         iconResource = info.iconResource;
    190         mIcon = info.mIcon; // TODO: should make a copy here.  maybe we don't need this ctor at all
    191         flags = info.flags;
    192         status = info.status;
    193         mInstallProgress = info.mInstallProgress;
    194         isDisabled = info.isDisabled;
    195         usingFallbackIcon = info.usingFallbackIcon;
    196     }
    197 
    198     /** TODO: Remove this.  It's only called by ApplicationInfo.makeShortcut. */
    199     public ShortcutInfo(AppInfo info) {
    200         super(info);
    201         title = Utilities.trim(info.title);
    202         intent = new Intent(info.intent);
    203         flags = info.flags;
    204         isDisabled = info.isDisabled;
    205     }
    206 
    207     public ShortcutInfo(LauncherActivityInfoCompat info, Context context) {
    208         user = info.getUser();
    209         title = Utilities.trim(info.getLabel());
    210         contentDescription = UserManagerCompat.getInstance(context)
    211                 .getBadgedLabelForUser(info.getLabel(), info.getUser());
    212         intent = AppInfo.makeLaunchIntent(context, info, info.getUser());
    213         itemType = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
    214         flags = AppInfo.initFlags(info);
    215     }
    216 
    217     /**
    218      * Creates a {@link ShortcutInfo} from a {@link ShortcutInfoCompat}.
    219      */
    220     @TargetApi(Build.VERSION_CODES.N)
    221     public ShortcutInfo(ShortcutInfoCompat shortcutInfo, Context context) {
    222         user = shortcutInfo.getUserHandle();
    223         itemType = LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT;
    224         flags = 0;
    225         updateFromDeepShortcutInfo(shortcutInfo, context);
    226     }
    227 
    228     public void setIcon(Bitmap b) {
    229         mIcon = b;
    230     }
    231 
    232     public Bitmap getIcon(IconCache iconCache) {
    233         if (mIcon == null) {
    234             updateIcon(iconCache);
    235         }
    236         return mIcon;
    237     }
    238 
    239     public void updateIcon(IconCache iconCache, boolean useLowRes) {
    240         if (itemType == Favorites.ITEM_TYPE_APPLICATION) {
    241             iconCache.getTitleAndIcon(this, promisedIntent != null ? promisedIntent : intent, user,
    242                     useLowRes);
    243         }
    244     }
    245 
    246     public void updateIcon(IconCache iconCache) {
    247         updateIcon(iconCache, shouldUseLowResIcon());
    248     }
    249 
    250     @Override
    251     void onAddToDatabase(Context context, ContentValues values) {
    252         super.onAddToDatabase(context, values);
    253 
    254         String titleStr = title != null ? title.toString() : null;
    255         values.put(LauncherSettings.BaseLauncherColumns.TITLE, titleStr);
    256 
    257         String uri = promisedIntent != null ? promisedIntent.toUri(0)
    258                 : (intent != null ? intent.toUri(0) : null);
    259         values.put(LauncherSettings.BaseLauncherColumns.INTENT, uri);
    260         values.put(LauncherSettings.Favorites.RESTORED, status);
    261 
    262         if (!usingFallbackIcon && !usingLowResIcon) {
    263             writeBitmap(values, mIcon);
    264         }
    265         if (iconResource != null) {
    266             values.put(LauncherSettings.BaseLauncherColumns.ICON_PACKAGE,
    267                     iconResource.packageName);
    268             values.put(LauncherSettings.BaseLauncherColumns.ICON_RESOURCE,
    269                     iconResource.resourceName);
    270         }
    271     }
    272 
    273     public ComponentName getTargetComponent() {
    274         return promisedIntent != null ? promisedIntent.getComponent() : intent.getComponent();
    275     }
    276 
    277     public boolean hasStatusFlag(int flag) {
    278         return (status & flag) != 0;
    279     }
    280 
    281 
    282     public final boolean isPromise() {
    283         return hasStatusFlag(FLAG_RESTORED_ICON | FLAG_AUTOINTALL_ICON);
    284     }
    285 
    286     public int getInstallProgress() {
    287         return mInstallProgress;
    288     }
    289 
    290     public void setInstallProgress(int progress) {
    291         mInstallProgress = progress;
    292         status |= FLAG_INSTALL_SESSION_ACTIVE;
    293     }
    294 
    295     public boolean shouldUseLowResIcon() {
    296         return usingLowResIcon && container >= 0 && rank >= FolderIcon.NUM_ITEMS_IN_PREVIEW;
    297     }
    298 
    299     public void updateFromDeepShortcutInfo(ShortcutInfoCompat shortcutInfo, Context context) {
    300         // {@link ShortcutInfoCompat#getActivity} can change during an update. Recreate the intent
    301         intent = shortcutInfo.makeIntent(context);
    302         title = shortcutInfo.getShortLabel();
    303 
    304         CharSequence label = shortcutInfo.getLongLabel();
    305         if (TextUtils.isEmpty(label)) {
    306             label = shortcutInfo.getShortLabel();
    307         }
    308         contentDescription = UserManagerCompat.getInstance(context)
    309                 .getBadgedLabelForUser(label, user);
    310         if (shortcutInfo.isEnabled()) {
    311             isDisabled &= ~FLAG_DISABLED_BY_PUBLISHER;
    312         } else {
    313             isDisabled |= FLAG_DISABLED_BY_PUBLISHER;
    314         }
    315         disabledMessage = shortcutInfo.getDisabledMessage();
    316 
    317         // TODO: Use cache for this
    318         LauncherAppState launcherAppState = LauncherAppState.getInstance();
    319         Drawable unbadgedDrawable = launcherAppState.getShortcutManager()
    320                 .getShortcutIconDrawable(shortcutInfo,
    321                         launcherAppState.getInvariantDeviceProfile().fillResIconDpi);
    322 
    323         IconCache cache = launcherAppState.getIconCache();
    324         Bitmap unbadgedBitmap = unbadgedDrawable == null
    325                 ? cache.getDefaultIcon(UserHandleCompat.myUserHandle())
    326                 : Utilities.createScaledBitmapWithoutShadow(unbadgedDrawable, context);
    327         setIcon(getBadgedIcon(unbadgedBitmap, shortcutInfo, cache, context));
    328     }
    329 
    330     protected Bitmap getBadgedIcon(Bitmap unbadgedBitmap, ShortcutInfoCompat shortcutInfo,
    331             IconCache cache, Context context) {
    332         unbadgedBitmap = Utilities.addShadowToIcon(unbadgedBitmap);
    333         // Get the app info for the source activity.
    334         AppInfo appInfo = new AppInfo();
    335         appInfo.user = user;
    336         appInfo.componentName = shortcutInfo.getActivity();
    337         try {
    338             cache.getTitleAndIcon(appInfo, shortcutInfo.getActivityInfo(context), false);
    339         } catch (NullPointerException e) {
    340             // This may happen when we fail to load the activity info. Worst case ignore badging.
    341             return Utilities.badgeIconForUser(unbadgedBitmap, user, context);
    342         }
    343         return Utilities.badgeWithBitmap(unbadgedBitmap, appInfo.iconBitmap, context);
    344     }
    345 
    346     /** Returns the ShortcutInfo id associated with the deep shortcut. */
    347     public String getDeepShortcutId() {
    348         return itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT ?
    349                 getPromisedIntent().getStringExtra(ShortcutInfoCompat.EXTRA_SHORTCUT_ID) : null;
    350     }
    351 
    352     @Override
    353     public boolean isDisabled() {
    354         return isDisabled != 0;
    355     }
    356 }
    357