1 /* 2 * Copyright (C) 2009 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.model.data; 18 19 import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_ALL_APPS; 20 import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_BOTTOM_WIDGETS_TRAY; 21 import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_PIN_WIDGETS; 22 import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_WIDGETS_PREDICTION; 23 import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_WIDGETS_TRAY; 24 import static com.android.launcher3.Utilities.ATLEAST_S; 25 26 import android.appwidget.AppWidgetHostView; 27 import android.content.ComponentName; 28 import android.content.Intent; 29 import android.content.res.Resources; 30 import android.os.Process; 31 32 import androidx.annotation.NonNull; 33 import androidx.annotation.Nullable; 34 35 import com.android.launcher3.LauncherSettings; 36 import com.android.launcher3.logger.LauncherAtom; 37 import com.android.launcher3.util.ContentWriter; 38 import com.android.launcher3.widget.LauncherAppWidgetHostView; 39 import com.android.launcher3.widget.LauncherAppWidgetProviderInfo; 40 41 /** 42 * Represents a widget (either instantiated or about to be) in the Launcher. 43 */ 44 public class LauncherAppWidgetInfo extends ItemInfo { 45 46 public static final int OPTION_SEARCH_WIDGET = 1; 47 48 49 public static final int RESTORE_COMPLETED = 0; 50 51 /** 52 * This is set during the package backup creation. 53 */ 54 public static final int FLAG_ID_NOT_VALID = 1; 55 56 /** 57 * Indicates that the provider is not available yet. 58 */ 59 public static final int FLAG_PROVIDER_NOT_READY = 2; 60 61 /** 62 * Indicates that the widget UI is not yet ready, and user needs to set it up again. 63 */ 64 public static final int FLAG_UI_NOT_READY = 4; 65 66 /** 67 * Indicates that the widget restore has started. 68 */ 69 public static final int FLAG_RESTORE_STARTED = 8; 70 71 /** 72 * Indicates that the widget has been allocated an Id. The id is still not valid, as it has 73 * not been bound yet. 74 */ 75 public static final int FLAG_ID_ALLOCATED = 16; 76 77 /** 78 * Indicates that the widget does not need to show config activity, even if it has a 79 * configuration screen. It can also optionally have some extras which are sent during bind. 80 */ 81 public static final int FLAG_DIRECT_CONFIG = 32; 82 83 /** 84 * Indicates that the widget hasn't been instantiated yet. 85 */ 86 public static final int NO_ID = -1; 87 88 /** 89 * Indicates that this is a locally defined widget and hence has no system allocated id. 90 */ 91 public static final int CUSTOM_WIDGET_ID = -100; 92 93 /** 94 * Flags for recording all the features that a widget has enabled. 95 * @see widgetFeatures 96 */ 97 public static final int FEATURE_RECONFIGURABLE = 1; 98 public static final int FEATURE_OPTIONAL_CONFIGURATION = 1 << 1; 99 public static final int FEATURE_PREVIEW_LAYOUT = 1 << 2; 100 public static final int FEATURE_TARGET_CELL_SIZE = 1 << 3; 101 public static final int FEATURE_MIN_SIZE = 1 << 4; 102 public static final int FEATURE_MAX_SIZE = 1 << 5; 103 public static final int FEATURE_ROUNDED_CORNERS = 1 << 6; 104 105 /** 106 * Identifier for this widget when talking with 107 * {@link android.appwidget.AppWidgetManager} for updates. 108 */ 109 public int appWidgetId = NO_ID; 110 111 public ComponentName providerName; 112 113 /** 114 * Indicates the restore status of the widget. 115 */ 116 public int restoreStatus; 117 118 /** 119 * Indicates the installation progress of the widget provider 120 */ 121 public int installProgress = -1; 122 123 /** 124 * Optional extras sent during widget bind. See {@link #FLAG_DIRECT_CONFIG}. 125 */ 126 public Intent bindOptions; 127 128 /** 129 * Widget options 130 */ 131 public int options; 132 133 /** 134 * Nonnull for pending widgets. We use this to get the icon and title for the widget. 135 */ 136 public PackageItemInfo pendingItemInfo; 137 138 /** 139 * Contains a binary representation indicating which widget features are enabled. This value is 140 * -1 if widget features could not be identified. 141 */ 142 private int widgetFeatures; 143 144 /** 145 * The container from which this widget was added (e.g. widgets tray, pin widget, search) 146 */ 147 public int sourceContainer = LauncherSettings.Favorites.CONTAINER_UNKNOWN; 148 LauncherAppWidgetInfo(int appWidgetId, ComponentName providerName)149 public LauncherAppWidgetInfo(int appWidgetId, ComponentName providerName) { 150 this.appWidgetId = appWidgetId; 151 this.providerName = providerName; 152 153 if (isCustomWidget()) { 154 itemType = LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET; 155 } else { 156 itemType = LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET; 157 } 158 159 // Since the widget isn't instantiated yet, we don't know these values. Set them to -1 160 // to indicate that they should be calculated based on the layout and minWidth/minHeight 161 spanX = -1; 162 spanY = -1; 163 widgetFeatures = -1; 164 // We only support app widgets on current user. 165 user = Process.myUserHandle(); 166 restoreStatus = RESTORE_COMPLETED; 167 } 168 LauncherAppWidgetInfo(int appWidgetId, ComponentName providerName, LauncherAppWidgetProviderInfo providerInfo, AppWidgetHostView hostView)169 public LauncherAppWidgetInfo(int appWidgetId, ComponentName providerName, 170 LauncherAppWidgetProviderInfo providerInfo, AppWidgetHostView hostView) { 171 this(appWidgetId, providerName); 172 widgetFeatures = computeWidgetFeatures(providerInfo, hostView); 173 } 174 175 /** Used for testing **/ LauncherAppWidgetInfo()176 public LauncherAppWidgetInfo() { 177 itemType = LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET; 178 } 179 isCustomWidget()180 public boolean isCustomWidget() { 181 return appWidgetId <= CUSTOM_WIDGET_ID; 182 } 183 184 @Nullable 185 @Override getTargetComponent()186 public ComponentName getTargetComponent() { 187 return providerName; 188 } 189 190 @Override onAddToDatabase(@onNull ContentWriter writer)191 public void onAddToDatabase(@NonNull ContentWriter writer) { 192 super.onAddToDatabase(writer); 193 writer.put(LauncherSettings.Favorites.APPWIDGET_ID, appWidgetId) 194 .put(LauncherSettings.Favorites.APPWIDGET_PROVIDER, providerName.flattenToString()) 195 .put(LauncherSettings.Favorites.RESTORED, restoreStatus) 196 .put(LauncherSettings.Favorites.OPTIONS, options) 197 .put(LauncherSettings.Favorites.INTENT, bindOptions) 198 .put(LauncherSettings.Favorites.APPWIDGET_SOURCE, sourceContainer); 199 } 200 201 @Override dumpProperties()202 protected String dumpProperties() { 203 return super.dumpProperties() 204 + " providerName=" + providerName 205 + " appWidgetId=" + appWidgetId; 206 } 207 isWidgetIdAllocated()208 public final boolean isWidgetIdAllocated() { 209 return (restoreStatus & FLAG_ID_NOT_VALID) == 0 210 || (restoreStatus & FLAG_ID_ALLOCATED) == FLAG_ID_ALLOCATED; 211 } 212 hasRestoreFlag(int flag)213 public final boolean hasRestoreFlag(int flag) { 214 return (restoreStatus & flag) == flag; 215 } 216 217 /** 218 * returns if widget options include an option or not 219 * @param option 220 * @return 221 */ hasOptionFlag(int option)222 public final boolean hasOptionFlag(int option) { 223 return (options & option) != 0; 224 } 225 226 @SuppressWarnings("NewApi") computeWidgetFeatures( LauncherAppWidgetProviderInfo providerInfo, AppWidgetHostView hostView)227 private static int computeWidgetFeatures( 228 LauncherAppWidgetProviderInfo providerInfo, AppWidgetHostView hostView) { 229 int widgetFeatures = 0; 230 if (providerInfo.isReconfigurable()) { 231 widgetFeatures |= FEATURE_RECONFIGURABLE; 232 } 233 if (providerInfo.isConfigurationOptional()) { 234 widgetFeatures |= FEATURE_OPTIONAL_CONFIGURATION; 235 } 236 if (ATLEAST_S && providerInfo.previewLayout != Resources.ID_NULL) { 237 widgetFeatures |= FEATURE_PREVIEW_LAYOUT; 238 } 239 if (ATLEAST_S && providerInfo.targetCellWidth > 0 || providerInfo.targetCellHeight > 0) { 240 widgetFeatures |= FEATURE_TARGET_CELL_SIZE; 241 } 242 if (providerInfo.minResizeWidth > 0 || providerInfo.minResizeHeight > 0) { 243 widgetFeatures |= FEATURE_MIN_SIZE; 244 } 245 if (ATLEAST_S && providerInfo.maxResizeWidth > 0 || providerInfo.maxResizeHeight > 0) { 246 widgetFeatures |= FEATURE_MAX_SIZE; 247 } 248 if (hostView instanceof LauncherAppWidgetHostView && 249 ((LauncherAppWidgetHostView) hostView).hasEnforcedCornerRadius()) { 250 widgetFeatures |= FEATURE_ROUNDED_CORNERS; 251 } 252 return widgetFeatures; 253 } 254 getAttribute(int container)255 public static LauncherAtom.Attribute getAttribute(int container) { 256 switch (container) { 257 case CONTAINER_WIDGETS_TRAY: 258 return LauncherAtom.Attribute.WIDGETS; 259 case CONTAINER_BOTTOM_WIDGETS_TRAY: 260 return LauncherAtom.Attribute.WIDGETS_BOTTOM_TRAY; 261 case CONTAINER_PIN_WIDGETS: 262 return LauncherAtom.Attribute.PINITEM; 263 case CONTAINER_WIDGETS_PREDICTION: 264 return LauncherAtom.Attribute.WIDGETS_TRAY_PREDICTION; 265 case CONTAINER_ALL_APPS: 266 return LauncherAtom.Attribute.ALL_APPS_SEARCH_RESULT_WIDGETS; 267 default: 268 return LauncherAtom.Attribute.UNKNOWN; 269 } 270 } 271 272 @NonNull 273 @Override buildProto(@ullable CollectionInfo collectionInfo)274 public LauncherAtom.ItemInfo buildProto(@Nullable CollectionInfo collectionInfo) { 275 LauncherAtom.ItemInfo info = super.buildProto(collectionInfo); 276 return info.toBuilder() 277 .setWidget(info.getWidget().toBuilder().setWidgetFeatures(widgetFeatures)) 278 .addItemAttributes(getAttribute(sourceContainer)) 279 .build(); 280 } 281 } 282