android10_Launcher3_original

This commit is contained in:
bryan.xiang
2020-02-29 10:01:57 +08:00
parent 7fd766734d
commit 6591b1156b
1146 changed files with 147198 additions and 0 deletions

View File

@@ -0,0 +1,54 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.launcher3.model;
import com.android.launcher3.AllAppsList;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherModel.Callbacks;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.widget.WidgetListRowEntry;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.HashMap;
/**
* Helper class to handle results of {@link com.android.launcher3.model.LoaderTask}.
*/
public class LoaderResults extends BaseLoaderResults {
public LoaderResults(LauncherAppState app, BgDataModel dataModel,
AllAppsList allAppsList, int pageToBindFirst, WeakReference<Callbacks> callbacks) {
super(app, dataModel, allAppsList, pageToBindFirst, callbacks);
}
@Override
public void bindDeepShortcuts() {
final HashMap<ComponentKey, Integer> shortcutMapCopy;
synchronized (mBgDataModel) {
shortcutMapCopy = new HashMap<>(mBgDataModel.deepShortcutMap);
}
executeCallbacksTask(c -> c.bindDeepShortcutMap(shortcutMapCopy), mUiExecutor);
}
@Override
public void bindWidgets() {
final ArrayList<WidgetListRowEntry> widgets =
mBgDataModel.widgetsModel.getWidgetsList(mApp.getContext());
executeCallbacksTask(c -> c.bindAllWidgets(widgets), mUiExecutor);
}
}

View File

@@ -0,0 +1,241 @@
package com.android.launcher3.model;
import static android.appwidget.AppWidgetProviderInfo.WIDGET_FEATURE_HIDE_FROM_PICKER;
import android.appwidget.AppWidgetProviderInfo;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Process;
import android.os.UserHandle;
import android.util.Log;
import com.android.launcher3.AppFilter;
import com.android.launcher3.icons.ComponentWithLabel;
import com.android.launcher3.icons.IconCache;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherAppWidgetProviderInfo;
import com.android.launcher3.Utilities;
import com.android.launcher3.compat.AlphabeticIndexCompat;
import com.android.launcher3.compat.AppWidgetManagerCompat;
import com.android.launcher3.compat.LauncherAppsCompat;
import com.android.launcher3.compat.ShortcutConfigActivityInfo;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.util.MultiHashMap;
import com.android.launcher3.util.PackageUserKey;
import com.android.launcher3.util.Preconditions;
import com.android.launcher3.widget.WidgetItemComparator;
import com.android.launcher3.widget.WidgetListRowEntry;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import androidx.annotation.Nullable;
/**
* Widgets data model that is used by the adapters of the widget views and controllers.
*
* <p> The widgets and shortcuts are organized using package name as its index.
*/
public class WidgetsModel {
private static final String TAG = "WidgetsModel";
private static final boolean DEBUG = false;
/* Map of widgets and shortcuts that are tracked per package. */
private final MultiHashMap<PackageItemInfo, WidgetItem> mWidgetsList = new MultiHashMap<>();
private AppFilter mAppFilter;
/**
* Returns a list of {@link WidgetListRowEntry}. All {@link WidgetItem} in a single row
* are sorted (based on label and user), but the overall list of {@link WidgetListRowEntry}s
* is not sorted. This list is sorted at the UI when using
* {@link com.android.launcher3.widget.WidgetsDiffReporter}
*
* @see com.android.launcher3.widget.WidgetsListAdapter#setWidgets(ArrayList)
*/
public synchronized ArrayList<WidgetListRowEntry> getWidgetsList(Context context) {
ArrayList<WidgetListRowEntry> result = new ArrayList<>();
AlphabeticIndexCompat indexer = new AlphabeticIndexCompat(context);
WidgetItemComparator widgetComparator = new WidgetItemComparator();
for (Map.Entry<PackageItemInfo, ArrayList<WidgetItem>> entry : mWidgetsList.entrySet()) {
WidgetListRowEntry row = new WidgetListRowEntry(entry.getKey(), entry.getValue());
row.titleSectionName = (row.pkgItem.title == null) ? "" :
indexer.computeSectionName(row.pkgItem.title);
Collections.sort(row.widgets, widgetComparator);
result.add(row);
}
return result;
}
/**
* @param packageUser If null, all widgets and shortcuts are updated and returned, otherwise
* only widgets and shortcuts associated with the package/user are.
*/
public List<ComponentWithLabel> update(LauncherAppState app, @Nullable PackageUserKey packageUser) {
Preconditions.assertWorkerThread();
Context context = app.getContext();
final ArrayList<WidgetItem> widgetsAndShortcuts = new ArrayList<>();
List<ComponentWithLabel> updatedItems = new ArrayList<>();
try {
InvariantDeviceProfile idp = app.getInvariantDeviceProfile();
PackageManager pm = app.getContext().getPackageManager();
// Widgets
AppWidgetManagerCompat widgetManager = AppWidgetManagerCompat.getInstance(context);
for (AppWidgetProviderInfo widgetInfo : widgetManager.getAllProviders(packageUser)) {
LauncherAppWidgetProviderInfo launcherWidgetInfo =
LauncherAppWidgetProviderInfo.fromProviderInfo(context, widgetInfo);
widgetsAndShortcuts.add(new WidgetItem(
launcherWidgetInfo, idp, app.getIconCache()));
updatedItems.add(launcherWidgetInfo);
}
// Shortcuts
for (ShortcutConfigActivityInfo info : LauncherAppsCompat.getInstance(context)
.getCustomShortcutActivityList(packageUser)) {
widgetsAndShortcuts.add(new WidgetItem(info, app.getIconCache(), pm));
updatedItems.add(info);
}
setWidgetsAndShortcuts(widgetsAndShortcuts, app, packageUser);
} catch (Exception e) {
if (!FeatureFlags.IS_DOGFOOD_BUILD && Utilities.isBinderSizeError(e)) {
// the returned value may be incomplete and will not be refreshed until the next
// time Launcher starts.
// TODO: after figuring out a repro step, introduce a dirty bit to check when
// onResume is called to refresh the widget provider list.
} else {
throw e;
}
}
app.getWidgetCache().removeObsoletePreviews(widgetsAndShortcuts, packageUser);
return updatedItems;
}
private synchronized void setWidgetsAndShortcuts(ArrayList<WidgetItem> rawWidgetsShortcuts,
LauncherAppState app, @Nullable PackageUserKey packageUser) {
if (DEBUG) {
Log.d(TAG, "addWidgetsAndShortcuts, widgetsShortcuts#=" + rawWidgetsShortcuts.size());
}
// Temporary list for {@link PackageItemInfos} to avoid having to go through
// {@link mPackageItemInfos} to locate the key to be used for {@link #mWidgetsList}
HashMap<String, PackageItemInfo> tmpPackageItemInfos = new HashMap<>();
// clear the lists.
if (packageUser == null) {
mWidgetsList.clear();
} else {
// Only clear the widgets for the given package/user.
PackageItemInfo packageItem = null;
for (PackageItemInfo item : mWidgetsList.keySet()) {
if (item.packageName.equals(packageUser.mPackageName)) {
packageItem = item;
break;
}
}
if (packageItem != null) {
// We want to preserve the user that was on the packageItem previously,
// so add it to tmpPackageItemInfos here to avoid creating a new entry.
tmpPackageItemInfos.put(packageItem.packageName, packageItem);
Iterator<WidgetItem> widgetItemIterator = mWidgetsList.get(packageItem).iterator();
while (widgetItemIterator.hasNext()) {
WidgetItem nextWidget = widgetItemIterator.next();
if (nextWidget.componentName.getPackageName().equals(packageUser.mPackageName)
&& nextWidget.user.equals(packageUser.mUser)) {
widgetItemIterator.remove();
}
}
}
}
InvariantDeviceProfile idp = app.getInvariantDeviceProfile();
UserHandle myUser = Process.myUserHandle();
// add and update.
for (WidgetItem item : rawWidgetsShortcuts) {
if (item.widgetInfo != null) {
if ((item.widgetInfo.getWidgetFeatures() & WIDGET_FEATURE_HIDE_FROM_PICKER) != 0) {
// Widget is hidden from picker
continue;
}
// Ensure that all widgets we show can be added on a workspace of this size
int minSpanX = Math.min(item.widgetInfo.spanX, item.widgetInfo.minSpanX);
int minSpanY = Math.min(item.widgetInfo.spanY, item.widgetInfo.minSpanY);
if (minSpanX > idp.numColumns || minSpanY > idp.numRows) {
if (DEBUG) {
Log.d(TAG, String.format(
"Widget %s : (%d X %d) can't fit on this device",
item.componentName, minSpanX, minSpanY));
}
continue;
}
}
if (mAppFilter == null) {
mAppFilter = AppFilter.newInstance(app.getContext());
}
if (!mAppFilter.shouldShowApp(item.componentName)) {
if (DEBUG) {
Log.d(TAG, String.format("%s is filtered and not added to the widget tray.",
item.componentName));
}
continue;
}
String packageName = item.componentName.getPackageName();
PackageItemInfo pInfo = tmpPackageItemInfos.get(packageName);
if (pInfo == null) {
pInfo = new PackageItemInfo(packageName);
pInfo.user = item.user;
tmpPackageItemInfos.put(packageName, pInfo);
} else if (!myUser.equals(pInfo.user)) {
// Keep updating the user, until we get the primary user.
pInfo.user = item.user;
}
mWidgetsList.addToList(pInfo, item);
}
// Update each package entry
IconCache iconCache = app.getIconCache();
for (PackageItemInfo p : tmpPackageItemInfos.values()) {
iconCache.getTitleAndIconForApp(p, true /* userLowResIcon */);
}
}
public void onPackageIconsUpdated(Set<String> packageNames, UserHandle user,
LauncherAppState app) {
for (Entry<PackageItemInfo, ArrayList<WidgetItem>> entry : mWidgetsList.entrySet()) {
if (packageNames.contains(entry.getKey().packageName)) {
ArrayList<WidgetItem> items = entry.getValue();
int count = items.size();
for (int i = 0; i < count; i++) {
WidgetItem item = items.get(i);
if (item.user.equals(user)) {
if (item.activityInfo != null) {
items.set(i, new WidgetItem(item.activityInfo, app.getIconCache(),
app.getContext().getPackageManager()));
} else {
items.set(i, new WidgetItem(item.widgetInfo,
app.getInvariantDeviceProfile(), app.getIconCache()));
}
}
}
}
}
}
}

View File

@@ -0,0 +1,223 @@
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.launcher3.shortcuts;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.LauncherApps;
import android.content.pm.LauncherApps.ShortcutQuery;
import android.content.pm.ShortcutInfo;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.UserHandle;
import android.util.Log;
import com.android.launcher3.ItemInfo;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.WorkspaceItemInfo;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* Performs operations related to deep shortcuts, such as querying for them, pinning them, etc.
*/
public class DeepShortcutManager {
private static final String TAG = "DeepShortcutManager";
private static final int FLAG_GET_ALL = ShortcutQuery.FLAG_MATCH_DYNAMIC
| ShortcutQuery.FLAG_MATCH_MANIFEST | ShortcutQuery.FLAG_MATCH_PINNED;
private static DeepShortcutManager sInstance;
private static final Object sInstanceLock = new Object();
public static DeepShortcutManager getInstance(Context context) {
synchronized (sInstanceLock) {
if (sInstance == null) {
sInstance = new DeepShortcutManager(context.getApplicationContext());
}
return sInstance;
}
}
private final LauncherApps mLauncherApps;
private boolean mWasLastCallSuccess;
private DeepShortcutManager(Context context) {
mLauncherApps = (LauncherApps) context.getSystemService(Context.LAUNCHER_APPS_SERVICE);
}
public static boolean supportsShortcuts(ItemInfo info) {
boolean isItemPromise = info instanceof WorkspaceItemInfo
&& ((WorkspaceItemInfo) info).hasPromiseIconUi();
return info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION
&& !info.isDisabled() && !isItemPromise;
}
public boolean wasLastCallSuccess() {
return mWasLastCallSuccess;
}
/**
* Queries for the shortcuts with the package name and provided ids.
*
* This method is intended to get the full details for shortcuts when they are added or updated,
* because we only get "key" fields in onShortcutsChanged().
*/
public List<ShortcutInfo> queryForFullDetails(String packageName,
List<String> shortcutIds, UserHandle user) {
return query(FLAG_GET_ALL, packageName, null, shortcutIds, user);
}
/**
* Gets all the manifest and dynamic shortcuts associated with the given package and user,
* to be displayed in the shortcuts container on long press.
*/
public List<ShortcutInfo> queryForShortcutsContainer(ComponentName activity,
UserHandle user) {
return query(ShortcutQuery.FLAG_MATCH_MANIFEST | ShortcutQuery.FLAG_MATCH_DYNAMIC,
activity.getPackageName(), activity, null, user);
}
/**
* Removes the given shortcut from the current list of pinned shortcuts.
* (Runs on background thread)
*/
public void unpinShortcut(final ShortcutKey key) {
String packageName = key.componentName.getPackageName();
String id = key.getId();
UserHandle user = key.user;
List<String> pinnedIds = extractIds(queryForPinnedShortcuts(packageName, user));
pinnedIds.remove(id);
try {
mLauncherApps.pinShortcuts(packageName, pinnedIds, user);
mWasLastCallSuccess = true;
} catch (SecurityException|IllegalStateException e) {
Log.w(TAG, "Failed to unpin shortcut", e);
mWasLastCallSuccess = false;
}
}
/**
* Adds the given shortcut to the current list of pinned shortcuts.
* (Runs on background thread)
*/
public void pinShortcut(final ShortcutKey key) {
String packageName = key.componentName.getPackageName();
String id = key.getId();
UserHandle user = key.user;
List<String> pinnedIds = extractIds(queryForPinnedShortcuts(packageName, user));
pinnedIds.add(id);
try {
mLauncherApps.pinShortcuts(packageName, pinnedIds, user);
mWasLastCallSuccess = true;
} catch (SecurityException|IllegalStateException e) {
Log.w(TAG, "Failed to pin shortcut", e);
mWasLastCallSuccess = false;
}
}
public void startShortcut(String packageName, String id, Rect sourceBounds,
Bundle startActivityOptions, UserHandle user) {
try {
mLauncherApps.startShortcut(packageName, id, sourceBounds,
startActivityOptions, user);
mWasLastCallSuccess = true;
} catch (SecurityException|IllegalStateException e) {
Log.e(TAG, "Failed to start shortcut", e);
mWasLastCallSuccess = false;
}
}
public Drawable getShortcutIconDrawable(ShortcutInfo shortcutInfo, int density) {
try {
Drawable icon = mLauncherApps.getShortcutIconDrawable(shortcutInfo, density);
mWasLastCallSuccess = true;
return icon;
} catch (SecurityException|IllegalStateException e) {
Log.e(TAG, "Failed to get shortcut icon", e);
mWasLastCallSuccess = false;
}
return null;
}
/**
* Returns the id's of pinned shortcuts associated with the given package and user.
*
* If packageName is null, returns all pinned shortcuts regardless of package.
*/
public List<ShortcutInfo> queryForPinnedShortcuts(String packageName, UserHandle user) {
return queryForPinnedShortcuts(packageName, null, user);
}
public List<ShortcutInfo> queryForPinnedShortcuts(String packageName,
List<String> shortcutIds, UserHandle user) {
return query(ShortcutQuery.FLAG_MATCH_PINNED, packageName, null, shortcutIds, user);
}
public List<ShortcutInfo> queryForAllShortcuts(UserHandle user) {
return query(FLAG_GET_ALL, null, null, null, user);
}
private List<String> extractIds(List<ShortcutInfo> shortcuts) {
List<String> shortcutIds = new ArrayList<>(shortcuts.size());
for (ShortcutInfo shortcut : shortcuts) {
shortcutIds.add(shortcut.getId());
}
return shortcutIds;
}
/**
* Query the system server for all the shortcuts matching the given parameters.
* If packageName == null, we query for all shortcuts with the passed flags, regardless of app.
*
* TODO: Use the cache to optimize this so we don't make an RPC every time.
*/
private List<ShortcutInfo> query(int flags, String packageName,
ComponentName activity, List<String> shortcutIds, UserHandle user) {
ShortcutQuery q = new ShortcutQuery();
q.setQueryFlags(flags);
if (packageName != null) {
q.setPackage(packageName);
q.setActivity(activity);
q.setShortcutIds(shortcutIds);
}
List<ShortcutInfo> shortcutInfos = null;
try {
shortcutInfos = mLauncherApps.getShortcuts(q, user);
mWasLastCallSuccess = true;
} catch (SecurityException|IllegalStateException e) {
Log.e(TAG, "Failed to query for shortcuts", e);
mWasLastCallSuccess = false;
}
if (shortcutInfos == null) {
return Collections.EMPTY_LIST;
}
return shortcutInfos;
}
public boolean hasHostPermission() {
try {
return mLauncherApps.hasShortcutHostPermission();
} catch (SecurityException|IllegalStateException e) {
Log.e(TAG, "Failed to make shortcut manager call", e);
}
return false;
}
}