1 /* 2 * Copyright (C) 2024 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.util 18 19 import android.appwidget.AppWidgetHostView 20 import android.content.Context 21 import android.view.LayoutInflater 22 import android.view.View 23 import android.view.View.OnClickListener 24 import android.view.View.OnFocusChangeListener 25 import android.view.ViewGroup 26 import com.android.launcher3.BubbleTextView 27 import com.android.launcher3.LauncherAppState 28 import com.android.launcher3.LauncherSettings.Favorites 29 import com.android.launcher3.R 30 import com.android.launcher3.apppairs.AppPairIcon 31 import com.android.launcher3.folder.FolderIcon 32 import com.android.launcher3.model.ModelWriter 33 import com.android.launcher3.model.data.AppPairInfo 34 import com.android.launcher3.model.data.FolderInfo 35 import com.android.launcher3.model.data.ItemInfo 36 import com.android.launcher3.model.data.LauncherAppWidgetInfo 37 import com.android.launcher3.model.data.WorkspaceItemFactory 38 import com.android.launcher3.model.data.WorkspaceItemInfo 39 import com.android.launcher3.views.ActivityContext 40 import com.android.launcher3.widget.LauncherWidgetHolder 41 import com.android.launcher3.widget.PendingAppWidgetHostView 42 import com.android.launcher3.widget.WidgetInflater 43 44 /** Utility class to inflate View for a model item */ 45 class ItemInflater<T>( 46 private val context: T, 47 private val widgetHolder: LauncherWidgetHolder, 48 private val clickListener: OnClickListener, 49 private val focusListener: OnFocusChangeListener, 50 private val defaultParent: ViewGroup, 51 ) where T : Context, T : ActivityContext { 52 53 private val widgetInflater = 54 WidgetInflater(context, LauncherAppState.getInstance(context).isSafeModeEnabled) 55 56 @JvmOverloads inflateItemnull57 fun inflateItem(item: ItemInfo, writer: ModelWriter, nullableParent: ViewGroup? = null): View? { 58 val parent = nullableParent ?: defaultParent 59 when (item.itemType) { 60 Favorites.ITEM_TYPE_APPLICATION, 61 Favorites.ITEM_TYPE_DEEP_SHORTCUT, 62 Favorites.ITEM_TYPE_SEARCH_ACTION -> { 63 var info = 64 if (item is WorkspaceItemFactory) { 65 (item as WorkspaceItemFactory).makeWorkspaceItem(context) 66 } else { 67 item as WorkspaceItemInfo 68 } 69 if (info.container == Favorites.CONTAINER_PREDICTION) { 70 // Came from all apps prediction row -- make a copy 71 info = WorkspaceItemInfo(info) 72 } 73 return createShortcut(info, parent) 74 } 75 Favorites.ITEM_TYPE_FOLDER -> 76 return FolderIcon.inflateFolderAndIcon( 77 R.layout.folder_icon, 78 context, 79 parent, 80 item as FolderInfo, 81 ) 82 Favorites.ITEM_TYPE_APP_PAIR -> 83 return AppPairIcon.inflateIcon( 84 R.layout.app_pair_icon, 85 context, 86 parent, 87 item as AppPairInfo, 88 BubbleTextView.DISPLAY_WORKSPACE, 89 ) 90 Favorites.ITEM_TYPE_APPWIDGET, 91 Favorites.ITEM_TYPE_CUSTOM_APPWIDGET -> 92 return inflateAppWidget(item as LauncherAppWidgetInfo, writer) 93 else -> throw RuntimeException("Invalid Item Type") 94 } 95 } 96 97 /** 98 * Creates a view representing a shortcut inflated from the specified resource. 99 * 100 * @param parent The group the shortcut belongs to. This is not necessarily the group where the 101 * shortcut should be added. 102 * @param info The data structure describing the shortcut. 103 * @return A View inflated from layoutResId. 104 */ createShortcutnull105 private fun createShortcut(info: WorkspaceItemInfo, parent: ViewGroup): View { 106 val favorite = 107 LayoutInflater.from(parent.context).inflate(R.layout.app_icon, parent, false) 108 as BubbleTextView 109 favorite.applyFromWorkspaceItem(info) 110 favorite.setOnClickListener(clickListener) 111 favorite.onFocusChangeListener = focusListener 112 return favorite 113 } 114 inflateAppWidgetnull115 private fun inflateAppWidget(item: LauncherAppWidgetInfo, writer: ModelWriter): View? { 116 TraceHelper.INSTANCE.beginSection("BIND_WIDGET_id=" + item.appWidgetId) 117 try { 118 val (type, reason, _, isUpdate, widgetInfo) = widgetInflater.inflateAppWidget(item) 119 if (type == WidgetInflater.TYPE_DELETE) { 120 writer.deleteItemFromDatabase(item, reason) 121 return null 122 } 123 if (isUpdate) { 124 writer.updateItemInDatabase(item) 125 } 126 val view = 127 if (type == WidgetInflater.TYPE_PENDING || widgetInfo == null) 128 PendingAppWidgetHostView(context, widgetHolder, item, widgetInfo) 129 else widgetHolder.createView(item.appWidgetId, widgetInfo) 130 prepareAppWidget(view, item) 131 return view 132 } finally { 133 TraceHelper.INSTANCE.endSection() 134 } 135 } 136 prepareAppWidgetnull137 fun prepareAppWidget(hostView: AppWidgetHostView, item: LauncherAppWidgetInfo) { 138 hostView.tag = item 139 hostView.isFocusable = true 140 hostView.onFocusChangeListener = focusListener 141 } 142 } 143