Merge "Fix widget tray clipping due to wrong padding" into ub-launcher3-calgary
diff --git a/src/com/android/launcher3/IconCache.java b/src/com/android/launcher3/IconCache.java
index f5fcf47..e1c52b2 100644
--- a/src/com/android/launcher3/IconCache.java
+++ b/src/com/android/launcher3/IconCache.java
@@ -800,7 +800,7 @@
}
private static final class IconDB extends SQLiteCacheHelper {
- private final static int DB_VERSION = 7;
+ private final static int DB_VERSION = 8;
private final static int RELEASE_VERSION = DB_VERSION +
(FeatureFlags.LAUNCHER3_DISABLE_ICON_NORMALIZATION ? 0 : 1);
@@ -859,6 +859,7 @@
Bitmap lowResIcon = Bitmap.createBitmap(icon.getWidth() / LOW_RES_SCALE_FACTOR,
icon.getHeight() / LOW_RES_SCALE_FACTOR, Bitmap.Config.RGB_565);
synchronized (this) {
+ mLowResCanvas.setBitmap(lowResIcon);
mLowResCanvas.drawColor(lowResBackgroundColor);
mLowResCanvas.drawBitmap(icon, new Rect(0, 0, icon.getWidth(), icon.getHeight()),
new Rect(0, 0, lowResIcon.getWidth(), lowResIcon.getHeight()),
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index fc828da..c8eb9cc 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -82,7 +82,6 @@
import android.view.View.OnClickListener;
import android.view.View.OnLongClickListener;
import android.view.ViewGroup;
-import android.view.ViewStub;
import android.view.ViewTreeObserver;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityEvent;
@@ -109,8 +108,10 @@
import com.android.launcher3.dragndrop.DragView;
import com.android.launcher3.folder.Folder;
import com.android.launcher3.folder.FolderIcon;
+import com.android.launcher3.logging.UserEventLogger;
import com.android.launcher3.model.WidgetsModel;
-import com.android.launcher3.userevent.Logger;
+import com.android.launcher3.logging.LoggerUtils;
+import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.LongArrayMap;
import com.android.launcher3.util.TestingUtils;
@@ -131,6 +132,7 @@
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
+import java.util.Locale;
/**
* Default launcher application.
@@ -366,7 +368,7 @@
}
private Stats mStats;
- private Logger mUserEventLogger;
+ private UserEventLogger mUserEventLogger;
public FocusIndicatorView mFocusHandler;
private boolean mRotationEnabled = false;
@@ -425,8 +427,8 @@
mDragController = new DragController(this);
mStateTransitionAnimation = new LauncherStateTransitionAnimation(this);
- mUserEventLogger = new Logger(this);
mStats = new Stats(this);
+ initLogger();
mAppWidgetManager = AppWidgetManagerCompat.getInstance(this);
@@ -536,7 +538,7 @@
private boolean mWorkspaceImportanceStored = false;
private boolean mHotseatImportanceStored = false;
private int mWorkspaceImportanceForAccessibility =
- View.IMPORTANT_FOR_ACCESSIBILITY_AUTO;
+ View.IMPORTANT_FOR_ACCESSIBILITY_AUTO;
private int mHotseatImportanceForAccessibility = View.IMPORTANT_FOR_ACCESSIBILITY_AUTO;
@Override
@@ -632,7 +634,35 @@
public Stats getStats() {
return mStats;
}
- public Logger getLogger() {return mUserEventLogger; }
+
+ /**
+ * Logger object is a singleton and does not have to be coupled with the foreground activity.
+ * Since most user event logging is done on the UI, the object is retrieved from the
+ * callback for convenience.
+ */
+ private void initLogger() {
+ if (mLauncherCallbacks != null) {
+ mUserEventLogger = mLauncherCallbacks.getLogger();
+ }
+ if (mUserEventLogger == null) {
+ mUserEventLogger = new UserEventLogger() {
+ @Override
+ public void processEvent(LauncherLogProto.LauncherEvent ev) {
+ if (ev.action.touch == LauncherLogProto.Action.TAP && ev.srcTarget.itemType == LauncherLogProto.APP_ICON) {
+ Log.d(TAG, String.format(Locale.US, "action:%s target:%s\n\telapsed container %d ms session %d ms",
+ LoggerUtils.getActionStr(ev.action),
+ LoggerUtils.getTargetStr(ev.srcTarget),
+ ev.elapsedContainerMillis,
+ ev.elapsedSessionMillis));
+ }
+ }
+ };
+ }
+ }
+
+ public UserEventLogger getLogger() {
+ return mUserEventLogger;
+ }
public boolean isDraggingEnabled() {
// We prevent dragging when we are loading the workspace as it is possible to pick up a view
@@ -1530,8 +1560,7 @@
ItemInfo info = mPendingAddInfo;
if (appWidgetInfo == null) {
- appWidgetInfo = LauncherAppWidgetProviderInfo.fromProviderInfo(this,
- mAppWidgetManager.getAppWidgetInfo(appWidgetId));
+ appWidgetInfo = mAppWidgetManager.getLauncherAppWidgetInfo(appWidgetId);
}
if (appWidgetInfo.isCustomWidget) {
@@ -2528,10 +2557,10 @@
final LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) v.getTag();
if (v.isReadyForClickSetup()) {
int widgetId = info.appWidgetId;
- AppWidgetProviderInfo appWidgetInfo = mAppWidgetManager.getAppWidgetInfo(widgetId);
+ LauncherAppWidgetProviderInfo appWidgetInfo =
+ mAppWidgetManager.getLauncherAppWidgetInfo(widgetId);
if (appWidgetInfo != null) {
- mPendingAddWidgetInfo = LauncherAppWidgetProviderInfo.fromProviderInfo(
- this, appWidgetInfo);
+ mPendingAddWidgetInfo = appWidgetInfo;
mPendingAddInfo.copyFrom(info);
mPendingAddWidgetId = widgetId;
@@ -3302,7 +3331,6 @@
getWindow().getDecorView()
.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
}
- mUserEventLogger.resetElapsedContainerMillis();
return changed;
}
@@ -3509,10 +3537,6 @@
// TODO
}
- protected void disableVoiceButtonProxy(boolean disable) {
- // NO-OP
- }
-
public boolean launcherCallbacksProvidesSearch() {
return (mLauncherCallbacks != null && mLauncherCallbacks.providesSearch());
}
@@ -3926,6 +3950,16 @@
sFolders = folders.clone();
}
+ private void bindSafeModeWidget(LauncherAppWidgetInfo item) {
+ PendingAppWidgetHostView view = new PendingAppWidgetHostView(this, item, true);
+ view.updateIcon(mIconCache);
+ item.hostView = view;
+ item.hostView.updateAppWidget(null);
+ item.hostView.setOnClickListener(this);
+ addAppWidgetToWorkspace(item, null, false);
+ mWorkspace.requestLayout();
+ }
+
/**
* Add the views for a widget to the workspace.
*
@@ -3941,19 +3975,31 @@
return;
}
+ if (mIsSafeModeEnabled) {
+ bindSafeModeWidget(item);
+ return;
+ }
+
final long start = DEBUG_WIDGETS ? SystemClock.uptimeMillis() : 0;
if (DEBUG_WIDGETS) {
Log.d(TAG, "bindAppWidget: " + item);
}
- final Workspace workspace = mWorkspace;
- LauncherAppWidgetProviderInfo appWidgetInfo =
- LauncherModel.getProviderInfo(this, item.providerName, item.user);
+ final LauncherAppWidgetProviderInfo appWidgetInfo;
- if (!mIsSafeModeEnabled
- && ((item.restoreStatus & LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY) == 0)
- && (item.restoreStatus != LauncherAppWidgetInfo.RESTORE_COMPLETED)) {
+ if (item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY)) {
+ // If the provider is not ready, bind as a pending widget.
+ appWidgetInfo = null;
+ } else if (item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_ID_NOT_VALID)) {
+ // The widget id is not valid. Try to find the widget based on the provider info.
+ appWidgetInfo = mAppWidgetManager.findProvider(item.providerName, item.user);
+ } else {
+ appWidgetInfo = mAppWidgetManager.getLauncherAppWidgetInfo(item.appWidgetId);
+ }
+ // If the provider is ready, but the width is not yet restored, try to restore it.
+ if (!item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY) &&
+ (item.restoreStatus != LauncherAppWidgetInfo.RESTORE_COMPLETED)) {
if (appWidgetInfo == null) {
if (DEBUG_WIDGETS) {
Log.d(TAG, "Removing restored widget: id=" + item.appWidgetId
@@ -3965,7 +4011,7 @@
}
// If we do not have a valid id, try to bind an id.
- if ((item.restoreStatus & LauncherAppWidgetInfo.FLAG_ID_NOT_VALID) != 0) {
+ if (item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_ID_NOT_VALID)) {
// Note: This assumes that the id remap broadcast is received before this step.
// If that is not the case, the id remap will be ignored and user may see the
// click to setup view.
@@ -4001,46 +4047,42 @@
: LauncherAppWidgetInfo.FLAG_UI_NOT_READY;
LauncherModel.updateItemInDatabase(this, item);
- } else if (((item.restoreStatus & LauncherAppWidgetInfo.FLAG_UI_NOT_READY) != 0)
+ } else if (item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_UI_NOT_READY)
&& (appWidgetInfo.configure == null)) {
- // If the ID is already valid, verify if we need to configure or not.
+ // The widget was marked as UI not ready, but there is no configure activity to
+ // update the UI.
item.restoreStatus = LauncherAppWidgetInfo.RESTORE_COMPLETED;
LauncherModel.updateItemInDatabase(this, item);
}
}
- if (!mIsSafeModeEnabled && item.restoreStatus == LauncherAppWidgetInfo.RESTORE_COMPLETED) {
- final int appWidgetId = item.appWidgetId;
+ if (item.restoreStatus == LauncherAppWidgetInfo.RESTORE_COMPLETED) {
if (DEBUG_WIDGETS) {
Log.d(TAG, "bindAppWidget: id=" + item.appWidgetId + " belongs to component "
+ appWidgetInfo.provider);
}
// Verify that we own the widget
- AppWidgetProviderInfo info = mAppWidgetManager.getAppWidgetInfo(appWidgetId);
- if (info == null || appWidgetInfo == null ||
- !info.provider.equals(appWidgetInfo.provider)) {
- Log.e(TAG, "Removing invalid widget: id=" + item.appWidgetId + " info=" + info
- + " appWidgetInfo=" + appWidgetInfo);
+ if (appWidgetInfo == null) {
+ Log.e(TAG, "Removing invalid widget: id=" + item.appWidgetId);
deleteWidgetInfo(item);
return;
}
- item.hostView = mAppWidgetHost.createView(this, appWidgetId, appWidgetInfo);
+ item.hostView = mAppWidgetHost.createView(this, item.appWidgetId, appWidgetInfo);
item.minSpanX = appWidgetInfo.minSpanX;
item.minSpanY = appWidgetInfo.minSpanY;
+ addAppWidgetToWorkspace(item, appWidgetInfo, false);
} else {
- appWidgetInfo = null;
PendingAppWidgetHostView view = new PendingAppWidgetHostView(this, item,
mIsSafeModeEnabled);
view.updateIcon(mIconCache);
item.hostView = view;
item.hostView.updateAppWidget(null);
item.hostView.setOnClickListener(this);
+ addAppWidgetToWorkspace(item, null, false);
}
-
- addAppWidgetToWorkspace(item, appWidgetInfo, false);
- workspace.requestLayout();
+ mWorkspace.requestLayout();
if (DEBUG_WIDGETS) {
Log.d(TAG, "bound widget id="+item.appWidgetId+" in "
@@ -4378,15 +4420,15 @@
}
}
- private Runnable mBindPackagesUpdatedRunnable = new Runnable() {
+ private Runnable mBindWidgetModelRunnable = new Runnable() {
public void run() {
- bindAllPackages(mWidgetsModel);
+ bindWidgetsModel(mWidgetsModel);
}
};
@Override
- public void bindAllPackages(final WidgetsModel model) {
- if (waitUntilResume(mBindPackagesUpdatedRunnable, true)) {
+ public void bindWidgetsModel(WidgetsModel model) {
+ if (waitUntilResume(mBindWidgetModelRunnable, true)) {
mWidgetsModel = model;
return;
}
@@ -4397,6 +4439,13 @@
}
}
+ @Override
+ public void notifyWidgetProvidersChanged() {
+ if (mWorkspace.getState().shouldUpdateWidget) {
+ mModel.refreshAndBindWidgetsAndShortcuts(this, mWidgetsView.isEmpty());
+ }
+ }
+
private int mapConfigurationOriActivityInfoOri(int configOri) {
final Display d = getWindowManager().getDefaultDisplay();
int naturalOri = Configuration.ORIENTATION_LANDSCAPE;
diff --git a/src/com/android/launcher3/LauncherAppWidgetHost.java b/src/com/android/launcher3/LauncherAppWidgetHost.java
index b07ccc3..8c23ff3 100644
--- a/src/com/android/launcher3/LauncherAppWidgetHost.java
+++ b/src/com/android/launcher3/LauncherAppWidgetHost.java
@@ -102,6 +102,10 @@
callback.run();
}
}
+
+ if (Utilities.ATLEAST_MARSHMALLOW) {
+ mLauncher.notifyWidgetProvidersChanged();
+ }
}
public AppWidgetHostView createView(Context context, int appWidgetId,
diff --git a/src/com/android/launcher3/LauncherBackupHelper.java b/src/com/android/launcher3/LauncherBackupHelper.java
index 05d729e..cad0f2c 100644
--- a/src/com/android/launcher3/LauncherBackupHelper.java
+++ b/src/com/android/launcher3/LauncherBackupHelper.java
@@ -50,6 +50,7 @@
import com.android.launcher3.backup.nano.BackupProtos.Resource;
import com.android.launcher3.backup.nano.BackupProtos.Screen;
import com.android.launcher3.backup.nano.BackupProtos.Widget;
+import com.android.launcher3.compat.AppWidgetManagerCompat;
import com.android.launcher3.compat.UserHandleCompat;
import com.android.launcher3.compat.UserManagerCompat;
import com.android.launcher3.model.GridSizeMigrationTask;
@@ -660,12 +661,14 @@
+ getUserSelectionArg();
Cursor cursor = cr.query(Favorites.CONTENT_URI, FAVORITE_PROJECTION,
where, null, null);
+ AppWidgetManagerCompat widgetManager = AppWidgetManagerCompat.getInstance(mContext);
try {
cursor.moveToPosition(-1);
while(cursor.moveToNext()) {
final long id = cursor.getLong(ID_INDEX);
final String providerName = cursor.getString(APPWIDGET_PROVIDER_INDEX);
final ComponentName provider = ComponentName.unflattenFromString(providerName);
+
Key key = null;
String backupKey = null;
if (provider != null) {
@@ -684,11 +687,14 @@
} else if (backupKey != null) {
if (DEBUG) Log.d(TAG, "I can count this high: " + backupWidgetCount);
if (backupWidgetCount < MAX_WIDGETS_PER_PASS) {
- if (DEBUG) Log.d(TAG, "saving widget " + backupKey);
- UserHandleCompat user = UserHandleCompat.myUserHandle();
- writeRowToBackup(key, packWidget(dpi, provider, user), data);
- mKeys.add(key);
- backupWidgetCount ++;
+ LauncherAppWidgetProviderInfo widgetInfo = widgetManager
+ .getLauncherAppWidgetInfo(cursor.getInt(APPWIDGET_ID_INDEX));
+ if (widgetInfo != null) {
+ if (DEBUG) Log.d(TAG, "saving widget " + backupKey);
+ writeRowToBackup(key, packWidget(dpi, widgetInfo), data);
+ mKeys.add(key);
+ backupWidgetCount ++;
+ }
} else {
if (VERBOSE) Log.v(TAG, "deferring widget backup " + backupKey);
// too many widgets for this pass, request another.
@@ -1004,16 +1010,14 @@
}
/** Serialize a widget for persistence, including a checksum wrapper. */
- private Widget packWidget(int dpi, ComponentName provider, UserHandleCompat user) {
- final LauncherAppWidgetProviderInfo info =
- LauncherModel.getProviderInfo(mContext, provider, user);
+ private Widget packWidget(int dpi, LauncherAppWidgetProviderInfo info) {
Widget widget = new Widget();
- widget.provider = provider.flattenToShortString();
+ widget.provider = info.provider.flattenToShortString();
widget.label = info.label;
widget.configure = info.configure != null;
if (info.icon != 0) {
widget.icon = new Resource();
- Drawable fullResIcon = mIconCache.getFullResIcon(provider.getPackageName(), info.icon);
+ Drawable fullResIcon = mIconCache.getFullResIcon(info.provider.getPackageName(), info.icon);
Bitmap icon = Utilities.createIconBitmap(fullResIcon, mContext);
widget.icon.data = Utilities.flattenBitmap(icon);
widget.icon.dpi = dpi;
@@ -1022,7 +1026,6 @@
Point spans = info.getMinSpans(mIdp, mContext);
widget.minSpanX = spans.x;
widget.minSpanY = spans.y;
-
return widget;
}
diff --git a/src/com/android/launcher3/LauncherCallbacks.java b/src/com/android/launcher3/LauncherCallbacks.java
index 0be45c3..fc7ff70 100644
--- a/src/com/android/launcher3/LauncherCallbacks.java
+++ b/src/com/android/launcher3/LauncherCallbacks.java
@@ -8,6 +8,7 @@
import android.view.View;
import android.view.ViewGroup;
import com.android.launcher3.allapps.AllAppsSearchBarController;
+import com.android.launcher3.logging.UserEventLogger;
import com.android.launcher3.util.ComponentKey;
import java.io.FileDescriptor;
@@ -97,6 +98,7 @@
/*
* Extensions points for adding / replacing some other aspects of the Launcher experience.
*/
+ public UserEventLogger getLogger();
public Intent getFirstRunActivity();
public boolean hasFirstRunActivity();
public boolean hasDismissableIntroScreen();
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index f707ec5..3877b94 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -17,7 +17,6 @@
package com.android.launcher3;
import android.app.SearchManager;
-import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProviderInfo;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -34,7 +33,6 @@
import android.database.Cursor;
import android.graphics.Bitmap;
import android.net.Uri;
-import android.os.DeadObjectException;
import android.os.Environment;
import android.os.Handler;
import android.os.HandlerThread;
@@ -42,7 +40,6 @@
import android.os.Parcelable;
import android.os.Process;
import android.os.SystemClock;
-import android.os.TransactionTooLargeException;
import android.provider.BaseColumns;
import android.text.TextUtils;
import android.util.Log;
@@ -73,7 +70,6 @@
import java.security.InvalidParameterException;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
@@ -137,11 +133,9 @@
@Thunk WeakReference<Callbacks> mCallbacks;
// < only access in worker thread >
- AllAppsList mBgAllAppsList;
+ private final AllAppsList mBgAllAppsList;
// Entire list of widgets.
- WidgetsModel mBgWidgetsModel;
- // Keep a clone of widgets that can be accessed from non-worker thread.
- WidgetsModel mFgWidgetsModel;
+ private final WidgetsModel mBgWidgetsModel;
// The lock that must be acquired before referencing any static bg data structures. Unlike
// other locks, this one can generally be held long-term because we never expect any of these
@@ -168,12 +162,6 @@
// sBgWorkspaceScreens is the ordered set of workspace screens.
static final ArrayList<Long> sBgWorkspaceScreens = new ArrayList<Long>();
- // sBgWidgetProviders is the set of widget providers including custom internal widgets
- public static HashMap<ComponentKey, LauncherAppWidgetProviderInfo> sBgWidgetProviders;
-
- // sBgShortcutProviders is the set of custom shortcut providers
- public static List<ResolveInfo> sBgShortcutProviders;
-
// sPendingPackages is a set of packages which could be on sdcard and are not available yet
static final HashMap<UserHandleCompat, HashSet<String>> sPendingPackages =
new HashMap<UserHandleCompat, HashSet<String>>();
@@ -209,7 +197,8 @@
public void bindRestoreItemsChange(HashSet<ItemInfo> updates);
public void bindComponentsRemoved(ArrayList<String> packageNames,
ArrayList<AppInfo> appInfos, UserHandleCompat user, int reason);
- public void bindAllPackages(WidgetsModel model);
+ public void notifyWidgetProvidersChanged();
+ public void bindWidgetsModel(WidgetsModel model);
public void bindSearchProviderChanged();
public boolean isAllAppsButtonRank(int rank);
public void onPageBoundSynchronously(int page);
@@ -245,7 +234,6 @@
mApp = app;
mBgAllAppsList = new AllAppsList(iconCache, appFilter);
mBgWidgetsModel = new WidgetsModel(context, iconCache, appFilter);
- mFgWidgetsModel = mBgWidgetsModel.clone();
mIconCache = iconCache;
mLauncherApps = LauncherAppsCompat.getInstance(context);
@@ -1701,8 +1689,8 @@
.getInstance(mContext).updateAndGetActiveSessionCache();
sBgWorkspaceScreens.addAll(loadWorkspaceScreensDb(mContext));
- final ArrayList<Long> itemsToRemove = new ArrayList<Long>();
- final ArrayList<Long> restoredRows = new ArrayList<Long>();
+ final ArrayList<Long> itemsToRemove = new ArrayList<>();
+ final ArrayList<Long> restoredRows = new ArrayList<>();
final Uri contentUri = LauncherSettings.Favorites.CONTENT_URI;
if (DEBUG_LOADERS) Log.d(TAG, "loading model from " + contentUri);
final Cursor c = contentResolver.query(contentUri, null, null, null, null);
@@ -1711,6 +1699,7 @@
// Load workspace in reverse order to ensure that latest items are loaded first (and
// before any earlier duplicates)
final LongArrayMap<ItemInfo[][]> occupied = new LongArrayMap<>();
+ HashMap<ComponentKey, AppWidgetProviderInfo> widgetProvidersMap = null;
try {
final int idIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites._ID);
@@ -2070,10 +2059,14 @@
final boolean wasProviderReady = (restoreStatus &
LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY) == 0;
- final LauncherAppWidgetProviderInfo provider =
- LauncherModel.getProviderInfo(context,
+ if (widgetProvidersMap == null) {
+ widgetProvidersMap = AppWidgetManagerCompat
+ .getInstance(mContext).getAllProvidersMap();
+ }
+ final AppWidgetProviderInfo provider = widgetProvidersMap.get(
+ new ComponentKey(
ComponentName.unflattenFromString(savedProvider),
- user);
+ user));
final boolean isProviderReady = isValidProvider(provider);
if (!isSafeMode && !customWidget &&
@@ -2695,7 +2688,6 @@
final Callbacks callbacks = tryGetCallbacks(oldCallbacks);
if (callbacks != null) {
callbacks.bindAllApplications(list);
- callbacks.bindAllPackages(mFgWidgetsModel);
}
if (DEBUG_LOADERS) {
Log.d(TAG, "bound all " + list.size() + " apps from cache in "
@@ -2787,7 +2779,7 @@
callbacks.bindAllApplications(added);
if (DEBUG_LOADERS) {
Log.d(TAG, "bound " + added.size() + " apps in "
- + (SystemClock.uptimeMillis() - bindTime) + "ms");
+ + (SystemClock.uptimeMillis() - bindTime) + "ms");
}
} else {
Log.i(TAG, "not binding apps: no Launcher activity");
@@ -2796,8 +2788,6 @@
});
// Cleanup any data stored for a deleted user.
ManagedProfileHeuristic.processAllUsers(profiles, mContext);
-
- loadAndBindWidgetsAndShortcuts(tryGetCallbacks(oldCallbacks), true /* refresh */);
if (DEBUG_LOADERS) {
Log.d(TAG, "Icons processed in "
+ (SystemClock.uptimeMillis() - loadTime) + "ms");
@@ -2864,9 +2854,6 @@
}
});
}
-
- // Reload widget list. No need to refresh, as we only want to update the icons and labels.
- loadAndBindWidgetsAndShortcuts(callbacks, false);
}
void enqueuePackageUpdated(PackageUpdatedTask task) {
@@ -3230,167 +3217,49 @@
});
}
- // Update widgets
- if (mOp == OP_ADD || mOp == OP_REMOVE || mOp == OP_UPDATE) {
- // Always refresh for a package event on secondary user
- boolean needToRefresh = !mUser.equals(UserHandleCompat.myUserHandle());
-
- // Refresh widget list, if the package already had a widget.
- synchronized (sBgLock) {
- if (sBgWidgetProviders != null) {
- HashSet<String> pkgSet = new HashSet<>();
- Collections.addAll(pkgSet, mPackages);
-
- for (ComponentKey key : sBgWidgetProviders.keySet()) {
- needToRefresh |= key.user.equals(mUser) &&
- pkgSet.contains(key.componentName.getPackageName());
- }
- }
- }
-
- if (!needToRefresh && mOp != OP_REMOVE) {
- // Refresh widget list, if there is any newly added widget
- PackageManager pm = context.getPackageManager();
- for (String pkg : mPackages) {
- try {
- List<ResolveInfo> widgets = pm.queryBroadcastReceivers(
- new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE)
- .setPackage(pkg), 0);
- needToRefresh |= widgets != null && !widgets.isEmpty();
- } catch (RuntimeException e) {
- if (ProviderConfig.IS_DOGFOOD_BUILD) {
- throw e;
- }
- // Ignore the crash. We can live with a state widget list.
- Log.e(TAG, "PM call failed for " + pkg, e);
- }
- }
- }
-
- loadAndBindWidgetsAndShortcuts(callbacks, needToRefresh);
- }
- }
- }
-
- public static List<LauncherAppWidgetProviderInfo> getWidgetProviders(Context context,
- boolean refresh) {
- ArrayList<LauncherAppWidgetProviderInfo> results =
- new ArrayList<LauncherAppWidgetProviderInfo>();
- try {
- synchronized (sBgLock) {
- if (sBgWidgetProviders == null || refresh) {
- HashMap<ComponentKey, LauncherAppWidgetProviderInfo> tmpWidgetProviders
- = new HashMap<>();
- AppWidgetManagerCompat wm = AppWidgetManagerCompat.getInstance(context);
- LauncherAppWidgetProviderInfo info;
-
- List<AppWidgetProviderInfo> widgets = wm.getAllProviders();
- for (AppWidgetProviderInfo pInfo : widgets) {
- info = LauncherAppWidgetProviderInfo.fromProviderInfo(context, pInfo);
- UserHandleCompat user = wm.getUser(info);
- tmpWidgetProviders.put(new ComponentKey(info.provider, user), info);
- }
-
- Collection<CustomAppWidget> customWidgets = Launcher.getCustomAppWidgets().values();
- for (CustomAppWidget widget : customWidgets) {
- info = new LauncherAppWidgetProviderInfo(context, widget);
- UserHandleCompat user = wm.getUser(info);
- tmpWidgetProviders.put(new ComponentKey(info.provider, user), info);
- }
- // Replace the global list at the very end, so that if there is an exception,
- // previously loaded provider list is used.
- sBgWidgetProviders = tmpWidgetProviders;
- }
- results.addAll(sBgWidgetProviders.values());
- return results;
- }
- } catch (Exception e) {
- if (!ProviderConfig.IS_DOGFOOD_BUILD &&
- (e.getCause() instanceof TransactionTooLargeException ||
- e.getCause() instanceof DeadObjectException)) {
- // 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.
- synchronized (sBgLock) {
- if (sBgWidgetProviders != null) {
- results.addAll(sBgWidgetProviders.values());
- }
- return results;
- }
- } else {
- throw e;
- }
- }
- }
-
- public static LauncherAppWidgetProviderInfo getProviderInfo(Context ctx, ComponentName name,
- UserHandleCompat user) {
- synchronized (sBgLock) {
- if (sBgWidgetProviders == null) {
- getWidgetProviders(ctx, false /* refresh */);
- }
- return sBgWidgetProviders.get(new ComponentKey(name, user));
- }
- }
-
- public void loadAndBindWidgetsAndShortcuts(final Callbacks callbacks, final boolean refresh) {
-
- runOnWorkerThread(new Runnable() {
- @Override
- public void run() {
- updateWidgetsModel(refresh);
+ // Notify launcher of widget update. From marshmallow onwards we use AppWidgetHost to
+ // get widget update signals.
+ if (!Utilities.ATLEAST_MARSHMALLOW &&
+ (mOp == OP_ADD || mOp == OP_REMOVE || mOp == OP_UPDATE)) {
mHandler.post(new Runnable() {
- @Override
public void run() {
Callbacks cb = getCallback();
if (callbacks == cb && cb != null) {
- callbacks.bindAllPackages(mFgWidgetsModel);
+ callbacks.notifyWidgetProvidersChanged();
}
}
});
- // update the Widget entries inside DB on the worker thread.
- LauncherAppState.getInstance().getWidgetCache().removeObsoletePreviews(
- mFgWidgetsModel.getRawList());
+ }
+ }
+ }
+
+ private void bindWidgetsModel(final Callbacks callbacks, final WidgetsModel model) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ Callbacks cb = getCallback();
+ if (callbacks == cb && cb != null) {
+ callbacks.bindWidgetsModel(model);
+ }
}
});
}
- /**
- * Returns a list of ResolveInfos/AppWidgetInfos.
- *
- * @see #loadAndBindWidgetsAndShortcuts
- */
- @Thunk void updateWidgetsModel(boolean refresh) {
- Utilities.assertWorkerThread();
- PackageManager packageManager = mApp.getContext().getPackageManager();
- final ArrayList<Object> widgetsAndShortcuts = new ArrayList<Object>();
- widgetsAndShortcuts.addAll(getWidgetProviders(mApp.getContext(), refresh));
-
- // Update shortcut providers
- synchronized (sBgLock) {
- try {
- Intent shortcutsIntent = new Intent(Intent.ACTION_CREATE_SHORTCUT);
- List<ResolveInfo> providers = packageManager.queryIntentActivities(shortcutsIntent, 0);
- sBgShortcutProviders = providers;
- } catch (RuntimeException e) {
- if (!ProviderConfig.IS_DOGFOOD_BUILD &&
- (e.getCause() instanceof TransactionTooLargeException ||
- e.getCause() instanceof DeadObjectException)) {
- /**
- * Ignore exception and use the cached list if available.
- * Refer to {@link #getWidgetProviders(Context, boolean}} for more info.
- */
- } else {
- throw e;
+ public void refreshAndBindWidgetsAndShortcuts(
+ final Callbacks callbacks, final boolean bindFirst) {
+ runOnWorkerThread(new Runnable() {
+ @Override
+ public void run() {
+ if (bindFirst && !mBgWidgetsModel.isEmpty()) {
+ bindWidgetsModel(callbacks, mBgWidgetsModel.clone());
}
+ final WidgetsModel model = mBgWidgetsModel.updateAndClone(mApp.getContext());
+ bindWidgetsModel(callbacks, model);
+ // update the Widget entries inside DB on the worker thread.
+ LauncherAppState.getInstance().getWidgetCache().removeObsoletePreviews(
+ model.getRawList());
}
- if (sBgShortcutProviders != null) {
- widgetsAndShortcuts.addAll(sBgShortcutProviders);
- }
- }
- mBgWidgetsModel.setWidgetsAndShortcuts(widgetsAndShortcuts);
- mFgWidgetsModel = mBgWidgetsModel.clone();
+ });
}
@Thunk static boolean isPackageDisabled(Context context, String packageName,
diff --git a/src/com/android/launcher3/LauncherStateTransitionAnimation.java b/src/com/android/launcher3/LauncherStateTransitionAnimation.java
index 54945be..8855cf0 100644
--- a/src/com/android/launcher3/LauncherStateTransitionAnimation.java
+++ b/src/com/android/launcher3/LauncherStateTransitionAnimation.java
@@ -148,6 +148,7 @@
}
@Override
void onTransitionComplete() {
+ mLauncher.getLogger().resetElapsedContainerMillis();
if (startSearchAfterTransition) {
toView.startAppsSearch();
}
@@ -167,7 +168,12 @@
final View buttonView = mLauncher.getWidgetsButton();
mCurrentAnimation = startAnimationToOverlay(fromWorkspaceState,
Workspace.State.OVERVIEW_HIDDEN, buttonView, toView, animated,
- new PrivateTransitionCallbacks(FINAL_REVEAL_ALPHA_FOR_WIDGETS));
+ new PrivateTransitionCallbacks(FINAL_REVEAL_ALPHA_FOR_WIDGETS){
+ @Override
+ void onTransitionComplete() {
+ mLauncher.getLogger().resetElapsedContainerMillis();
+ }
+ });
}
/**
@@ -397,7 +403,7 @@
// Animate the search bar
final SearchDropTargetBar.State toSearchBarState =
- toWorkspaceState.getSearchDropTargetBarState();
+ toWorkspaceState.searchDropTargetBarState;
mLauncher.getSearchDropTargetBar().animateToState(toSearchBarState,
animated ? revealDuration : 0, animation);
@@ -462,6 +468,10 @@
}
};
}
+ @Override
+ void onTransitionComplete() {
+ mLauncher.getLogger().resetElapsedContainerMillis();
+ }
};
// Only animate the search bar if animating to spring loaded mode from all apps
mCurrentAnimation = startAnimationToWorkspaceFromOverlay(fromWorkspaceState, toWorkspaceState,
@@ -488,6 +498,10 @@
}
};
}
+ @Override
+ void onTransitionComplete() {
+ mLauncher.getLogger().resetElapsedContainerMillis();
+ }
};
mCurrentAnimation = startAnimationToWorkspaceFromOverlay(
fromWorkspaceState, toWorkspaceState,
diff --git a/src/com/android/launcher3/Stats.java b/src/com/android/launcher3/Stats.java
index 2873828..10a26ad 100644
--- a/src/com/android/launcher3/Stats.java
+++ b/src/com/android/launcher3/Stats.java
@@ -26,7 +26,6 @@
import android.view.ViewParent;
import com.android.launcher3.config.ProviderConfig;
-import com.android.launcher3.userevent.Logger;
public class Stats {
@@ -146,6 +145,8 @@
LaunchSourceUtils.populateSourceDataFromAncestorProvider(v, sourceExtras);
broadcastIntent.putExtra(EXTRA_SOURCE, sourceExtras);
mLauncher.sendBroadcast(broadcastIntent, mLaunchBroadcastPermission);
- mLauncher.getLogger().logAppLaunch(intent.getComponent().getPackageName(), shortcut, sourceExtras);
+ if (intent.getComponent() != null) {
+ mLauncher.getLogger().logAppLaunch(intent.getComponent().getPackageName(), shortcut, sourceExtras);
+ }
}
}
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index a74fa0d..0b72ef7 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -52,11 +52,11 @@
import android.view.ViewDebug;
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityManager;
-import android.view.animation.AccelerateInterpolator;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
import android.widget.TextView;
+import com.android.launcher3.compat.AppWidgetManagerCompat;
import com.android.launcher3.folder.Folder;
import com.android.launcher3.folder.FolderIcon;
import com.android.launcher3.Launcher.CustomContentCallbacks;
@@ -179,22 +179,20 @@
// in all apps or customize mode)
enum State {
- NORMAL (SearchDropTargetBar.State.SEARCH_BAR),
- NORMAL_HIDDEN (SearchDropTargetBar.State.INVISIBLE_TRANSLATED),
- SPRING_LOADED (SearchDropTargetBar.State.DROP_TARGET),
- OVERVIEW (SearchDropTargetBar.State.INVISIBLE),
- OVERVIEW_HIDDEN (SearchDropTargetBar.State.INVISIBLE);
+ NORMAL (SearchDropTargetBar.State.SEARCH_BAR, false),
+ NORMAL_HIDDEN (SearchDropTargetBar.State.INVISIBLE_TRANSLATED, false),
+ SPRING_LOADED (SearchDropTargetBar.State.DROP_TARGET, false),
+ OVERVIEW (SearchDropTargetBar.State.INVISIBLE, true),
+ OVERVIEW_HIDDEN (SearchDropTargetBar.State.INVISIBLE, true);
- private final SearchDropTargetBar.State mBarState;
+ public final SearchDropTargetBar.State searchDropTargetBarState;
+ public final boolean shouldUpdateWidget;
- State(SearchDropTargetBar.State searchBarState) {
- mBarState = searchBarState;
+ State(SearchDropTargetBar.State searchBarState, boolean shouldUpdateWidget) {
+ searchDropTargetBarState = searchBarState;
+ this.shouldUpdateWidget = shouldUpdateWidget;
}
-
- public SearchDropTargetBar.State getSearchDropTargetBarState() {
- return mBarState;
- }
- };
+ }
@ViewDebug.ExportedProperty(category = "launcher")
private State mState = State.NORMAL;
@@ -1914,6 +1912,8 @@
Animator workspaceAnim = mStateTransitionAnimation.getAnimationToState(mState,
toState, animated, layerViews);
+ boolean shouldNotifyWidgetChange = !mState.shouldUpdateWidget
+ && toState.shouldUpdateWidget;
// Update the current state
mState = toState;
updateAccessibilityFlags();
@@ -1923,6 +1923,10 @@
invalidate(); // This will call dispatchDraw(), which calls getVisiblePages().
}
+ if (shouldNotifyWidgetChange) {
+ mLauncher.notifyWidgetProvidersChanged();
+ }
+
return workspaceAnim;
}
@@ -4148,13 +4152,22 @@
});
}
- void widgetsRestored(ArrayList<LauncherAppWidgetInfo> changedInfo) {
+ public void widgetsRestored(ArrayList<LauncherAppWidgetInfo> changedInfo) {
if (!changedInfo.isEmpty()) {
DeferredWidgetRefresh widgetRefresh = new DeferredWidgetRefresh(changedInfo,
mLauncher.getAppWidgetHost());
- if (LauncherModel.getProviderInfo(getContext(),
- changedInfo.get(0).providerName,
- changedInfo.get(0).user) != null) {
+
+ LauncherAppWidgetInfo item = changedInfo.get(0);
+ final AppWidgetProviderInfo widgetInfo;
+ if (item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_ID_NOT_VALID)) {
+ widgetInfo = AppWidgetManagerCompat
+ .getInstance(mLauncher).findProvider(item.providerName, item.user);
+ } else {
+ widgetInfo = AppWidgetManagerCompat.getInstance(mLauncher)
+ .getAppWidgetInfo(item.appWidgetId);
+ }
+
+ if (widgetInfo != null) {
// Re-inflate the widgets which have changed status
widgetRefresh.run();
} else {
diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java
index 07bbc46..9d5afb4 100644
--- a/src/com/android/launcher3/allapps/AllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java
@@ -47,7 +47,6 @@
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.Workspace;
-import com.android.launcher3.userevent.Logger;
import com.android.launcher3.util.ComponentKey;
import java.nio.charset.Charset;
@@ -313,7 +312,6 @@
icon.getMeasuredHeight());
updateBackgroundAndPaddings();
- mLauncher.getLogger().resetElapsedContainerMillis();
}
@Override
diff --git a/src/com/android/launcher3/compat/AppWidgetManagerCompat.java b/src/com/android/launcher3/compat/AppWidgetManagerCompat.java
index f0221bc..811cacf 100644
--- a/src/com/android/launcher3/compat/AppWidgetManagerCompat.java
+++ b/src/com/android/launcher3/compat/AppWidgetManagerCompat.java
@@ -20,6 +20,7 @@
import android.appwidget.AppWidgetHost;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProviderInfo;
+import android.content.ComponentName;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
@@ -28,7 +29,9 @@
import com.android.launcher3.IconCache;
import com.android.launcher3.LauncherAppWidgetProviderInfo;
import com.android.launcher3.Utilities;
+import com.android.launcher3.util.ComponentKey;
+import java.util.HashMap;
import java.util.List;
public abstract class AppWidgetManagerCompat {
@@ -62,6 +65,11 @@
return mAppWidgetManager.getAppWidgetInfo(appWidgetId);
}
+ public LauncherAppWidgetProviderInfo getLauncherAppWidgetInfo(int appWidgetId) {
+ AppWidgetProviderInfo info = getAppWidgetInfo(appWidgetId);
+ return info == null ? null : LauncherAppWidgetProviderInfo.fromProviderInfo(mContext, info);
+ }
+
public abstract List<AppWidgetProviderInfo> getAllProviders();
public abstract String loadLabel(LauncherAppWidgetProviderInfo info);
@@ -81,4 +89,8 @@
public abstract Bitmap getBadgeBitmap(LauncherAppWidgetProviderInfo info, Bitmap bitmap,
int imageWidth, int imageHeight);
+ public abstract LauncherAppWidgetProviderInfo findProvider(
+ ComponentName provider, UserHandleCompat user);
+
+ public abstract HashMap<ComponentKey, AppWidgetProviderInfo> getAllProvidersMap();
}
diff --git a/src/com/android/launcher3/compat/AppWidgetManagerCompatV16.java b/src/com/android/launcher3/compat/AppWidgetManagerCompatV16.java
index e9d2510..de9414e 100644
--- a/src/com/android/launcher3/compat/AppWidgetManagerCompatV16.java
+++ b/src/com/android/launcher3/compat/AppWidgetManagerCompatV16.java
@@ -21,6 +21,7 @@
import android.appwidget.AppWidgetHost;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProviderInfo;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
@@ -31,7 +32,9 @@
import com.android.launcher3.IconCache;
import com.android.launcher3.LauncherAppWidgetProviderInfo;
import com.android.launcher3.Utilities;
+import com.android.launcher3.util.ComponentKey;
+import java.util.HashMap;
import java.util.List;
class AppWidgetManagerCompatV16 extends AppWidgetManagerCompat {
@@ -91,4 +94,25 @@
int imageWidth, int imageHeight) {
return bitmap;
}
+
+ @Override
+ public LauncherAppWidgetProviderInfo findProvider(
+ ComponentName provider, UserHandleCompat user) {
+ for (AppWidgetProviderInfo info : mAppWidgetManager.getInstalledProviders()) {
+ if (info.provider.equals(provider)) {
+ return LauncherAppWidgetProviderInfo.fromProviderInfo(mContext, info);
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public HashMap<ComponentKey, AppWidgetProviderInfo> getAllProvidersMap() {
+ HashMap<ComponentKey, AppWidgetProviderInfo> result = new HashMap<>();
+ UserHandleCompat user = UserHandleCompat.myUserHandle();
+ for (AppWidgetProviderInfo info : mAppWidgetManager.getInstalledProviders()) {
+ result.put(new ComponentKey(info.provider, user), info);
+ }
+ return result;
+ }
}
diff --git a/src/com/android/launcher3/compat/AppWidgetManagerCompatVL.java b/src/com/android/launcher3/compat/AppWidgetManagerCompatVL.java
index 3bc3d0d..a1570e6 100644
--- a/src/com/android/launcher3/compat/AppWidgetManagerCompatVL.java
+++ b/src/com/android/launcher3/compat/AppWidgetManagerCompatVL.java
@@ -21,6 +21,7 @@
import android.appwidget.AppWidgetHost;
import android.appwidget.AppWidgetProviderInfo;
import android.content.ActivityNotFoundException;
+import android.content.ComponentName;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.res.Resources;
@@ -40,8 +41,10 @@
import com.android.launcher3.IconCache;
import com.android.launcher3.LauncherAppWidgetProviderInfo;
import com.android.launcher3.R;
+import com.android.launcher3.util.ComponentKey;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
@@ -145,4 +148,28 @@
c.setBitmap(null);
return bitmap;
}
+
+ @Override
+ public LauncherAppWidgetProviderInfo findProvider(ComponentName provider, UserHandleCompat user) {
+ for (AppWidgetProviderInfo info : mAppWidgetManager
+ .getInstalledProvidersForProfile(user.getUser())) {
+ if (info.provider.equals(provider)) {
+ return LauncherAppWidgetProviderInfo.fromProviderInfo(mContext, info);
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public HashMap<ComponentKey, AppWidgetProviderInfo> getAllProvidersMap() {
+ HashMap<ComponentKey, AppWidgetProviderInfo> result = new HashMap<>();
+ for (UserHandle user : mUserManager.getUserProfiles()) {
+ UserHandleCompat userHandle = UserHandleCompat.fromUser(user);
+ for (AppWidgetProviderInfo info :
+ mAppWidgetManager.getInstalledProvidersForProfile(user)) {
+ result.put(new ComponentKey(info.provider, userHandle), info);
+ }
+ }
+ return result;
+ }
}
diff --git a/src/com/android/launcher3/logging/LoggerUtils.java b/src/com/android/launcher3/logging/LoggerUtils.java
new file mode 100644
index 0000000..4b30384
--- /dev/null
+++ b/src/com/android/launcher3/logging/LoggerUtils.java
@@ -0,0 +1,117 @@
+package com.android.launcher3.logging;
+
+import android.os.Bundle;
+import android.util.Log;
+
+import com.android.launcher3.LauncherSettings;
+import com.android.launcher3.ShortcutInfo;
+import com.android.launcher3.Stats;
+import com.android.launcher3.userevent.nano.LauncherLogProto;
+import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
+import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
+
+
+/**
+ * Debugging helper methods.
+ * toString() cannot be overriden inside auto generated {@link LauncherLogProto}.
+ * Note: switch statement cannot be replaced with reflection as proguard strips the constants
+ */
+public class LoggerUtils {
+ private static final String TAG = "LoggerUtils";
+ private static final boolean DEBUG = false;
+
+ static int getContainerType(ShortcutInfo shortcut) {
+ switch ((int) shortcut.container) {
+ case LauncherSettings.Favorites.CONTAINER_DESKTOP: return LauncherLogProto.WORKSPACE;
+ case LauncherSettings.Favorites.CONTAINER_HOTSEAT: return LauncherLogProto.HOTSEAT;
+ default:
+ return (int) shortcut.container;
+ }
+ }
+
+ public static String getActionStr(LauncherLogProto.Action action) {
+ switch(action.touch) {
+ case Action.TAP: return "TAP";
+ case Action.LONGPRESS: return "LONGPRESS";
+ case Action.DRAGDROP: return "DRAGDROP";
+ case Action.PINCH: return "PINCH";
+ default: return "UNKNOWN";
+ }
+ }
+
+ public static String getTargetStr(Target t) {
+ String typeStr;
+ switch (t.type) {
+ case Target.ITEM:
+ return getItemStr(t);
+ case Target.CONTROL:
+ return getControlStr(t);
+ case Target.CONTAINER:
+ return getContainerStr(t);
+ default:
+ return "UNKNOWN TARGET TYPE";
+ }
+ }
+
+ private static String getItemStr(Target t) {
+ String typeStr = "";
+ switch(t.itemType){
+ case LauncherLogProto.APP_ICON: typeStr = "ICON"; break;
+ case LauncherLogProto.SHORTCUT: typeStr = "SHORTCUT"; break;
+ case LauncherLogProto.WIDGET: typeStr = "WIDGET"; break;
+ default: typeStr = "UNKNOWN";
+ }
+
+ return typeStr + " " + t.packageNameHash + " grid=(" + t.gridX + "," + t.gridY + ") "
+ + getContainerStr(t.parent);
+ }
+
+ private static String getControlStr(Target t) {
+ switch(t.controlType) {
+ case LauncherLogProto.ALL_APPS_BUTTON: return "ALL_APPS_BUTTON";
+ case LauncherLogProto.WIDGETS_BUTTON: return "WIDGETS_BUTTON";
+ case LauncherLogProto.WALLPAPER_BUTTON: return "WALLPAPER_BUTTON";
+ case LauncherLogProto.SETTINGS_BUTTON: return "SETTINGS_BUTTON";
+ case LauncherLogProto.REMOVE_TARGET: return "REMOVE_TARGET";
+ case LauncherLogProto.UNINSTALL_TARGET: return "UNINSTALL_TARGET";
+ case LauncherLogProto.APPINFO_TARGET: return "APPINFO_TARGET";
+ case LauncherLogProto.RESIZE_HANDLE: return "RESIZE_HANDLE";
+ case LauncherLogProto.FAST_SCROLL_HANDLE: return "FAST_SCROLL_HANDLE";
+ default: return "UNKNOWN";
+ }
+ }
+
+ private static String getContainerStr(LauncherLogProto.Target t) {
+ String str;
+ Log.d(TAG, "t.containerType" + t.containerType);
+ switch (t.containerType) {
+ case LauncherLogProto.WORKSPACE:
+ str = "WORKSPACE";
+ break;
+ case LauncherLogProto.HOTSEAT:
+ str = "HOTSEAT";
+ break;
+ case LauncherLogProto.FOLDER:
+ str = "FOLDER";
+ break;
+ case LauncherLogProto.ALLAPPS:
+ str = "ALLAPPS";
+ break;
+ case LauncherLogProto.WIDGETS:
+ str = "WIDGETS";
+ break;
+ case LauncherLogProto.OVERVIEW:
+ str = "OVERVIEW";
+ break;
+ case LauncherLogProto.PREDICTION:
+ str = "PREDICTION";
+ break;
+ case LauncherLogProto.SEARCHRESULT:
+ str = "SEARCHRESULT";
+ break;
+ default:
+ str = "UNKNOWN";
+ }
+ return str + " id=" + t.pageIndex;
+ }
+}
diff --git a/src/com/android/launcher3/logging/UserEventLogger.java b/src/com/android/launcher3/logging/UserEventLogger.java
index d05b683..4e5b2c1 100644
--- a/src/com/android/launcher3/logging/UserEventLogger.java
+++ b/src/com/android/launcher3/logging/UserEventLogger.java
@@ -1,4 +1,97 @@
package com.android.launcher3.logging;
+import android.os.Bundle;
+import android.util.Log;
+
+import com.android.launcher3.ShortcutInfo;
+import com.android.launcher3.Stats;
+import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.userevent.nano.LauncherLogProto;
+
+import java.util.Locale;
+
public abstract class UserEventLogger {
+
+ private String TAG = "UserEventLogger";
+ private boolean DEBUG = false;
+
+ private long mElapsedContainerMillis;
+ private long mElapsedSessionMillis;
+ private long mActionDurationMillis;
+
+
+ public final void logAppLaunch(String provider, ShortcutInfo shortcut, Bundle bundle) {
+ if (FeatureFlags.LAUNCHER3_LEGACY_LOGGING) return;
+
+ LauncherLogProto.LauncherEvent event = new LauncherLogProto.LauncherEvent();
+ event.action = new LauncherLogProto.Action();
+ event.action.type = LauncherLogProto.Action.TOUCH;
+ event.action.touch = LauncherLogProto.Action.TAP;
+
+ event.srcTarget = new LauncherLogProto.Target();
+ event.srcTarget.type = LauncherLogProto.Target.ITEM;
+ event.srcTarget.itemType = LauncherLogProto.APP_ICON;
+ // TODO: package hash name should be different per device.
+ event.srcTarget.packageNameHash = provider.hashCode();
+
+ event.srcTarget.parent = new LauncherLogProto.Target();
+ String subContainer = bundle.getString(Stats.SOURCE_EXTRA_SUB_CONTAINER);
+
+ if (shortcut != null) {
+ event.srcTarget.parent.containerType = LoggerUtils.getContainerType(shortcut);
+ event.srcTarget.pageIndex = (int) shortcut.screenId;
+ event.srcTarget.gridX = shortcut.cellX;
+ event.srcTarget.gridX = shortcut.cellY;
+ }
+ if (subContainer != null) {
+ event.srcTarget.parent.type = LauncherLogProto.Target.CONTAINER;
+ if (subContainer.equals(Stats.SUB_CONTAINER_FOLDER)) {
+ event.srcTarget.parent.containerType = LauncherLogProto.FOLDER;
+ } else if (subContainer.equals(Stats.SUB_CONTAINER_ALL_APPS_A_Z)) {
+ event.srcTarget.parent.containerType = LauncherLogProto.ALLAPPS;
+ } else if (subContainer.equals(Stats.CONTAINER_HOTSEAT)) {
+ event.srcTarget.parent.containerType = LauncherLogProto.HOTSEAT;
+ } else if (subContainer.equals(Stats.SUB_CONTAINER_ALL_APPS_PREDICTION)) {
+ event.srcTarget.parent.containerType = LauncherLogProto.PREDICTION;
+ }
+
+ if (DEBUG) {
+ Log.d(TAG, String.format("parent bundle: %s %s %s %s",
+ bundle.getString(Stats.SOURCE_EXTRA_CONTAINER),
+ bundle.getString(Stats.SOURCE_EXTRA_CONTAINER_PAGE),
+ bundle.getString(Stats.SOURCE_EXTRA_SUB_CONTAINER),
+ bundle.getString(Stats.SOURCE_EXTRA_SUB_CONTAINER_PAGE)));
+ }
+ }
+ event.elapsedContainerMillis = System.currentTimeMillis() - mElapsedContainerMillis;
+ event.elapsedSessionMillis = System.currentTimeMillis() - mElapsedSessionMillis;
+ processEvent(event);
+ }
+
+ /**
+ * Currently logs following containers: workspace, allapps, widget tray.
+ */
+ public final void resetElapsedContainerMillis() {
+ mElapsedContainerMillis = System.currentTimeMillis();
+ if(DEBUG) {
+ Log.d(TAG, "resetElapsedContainerMillis " + mElapsedContainerMillis);
+ }
+ }
+
+ public final void resetElapsedSessionMillis() {
+ mElapsedSessionMillis = System.currentTimeMillis();
+ mElapsedContainerMillis = System.currentTimeMillis();
+ if(DEBUG) {
+ Log.d(TAG, "resetElapsedSessionMillis " + mElapsedSessionMillis);
+ }
+ }
+
+ public final void resetActionDurationMillis() {
+ mActionDurationMillis = System.currentTimeMillis();
+ if(DEBUG) {
+ Log.d(TAG, "resetElapsedContainerMillis " + mElapsedContainerMillis);
+ }
+ }
+
+ public abstract void processEvent(LauncherLogProto.LauncherEvent ev);
}
\ No newline at end of file
diff --git a/src/com/android/launcher3/model/GridSizeMigrationTask.java b/src/com/android/launcher3/model/GridSizeMigrationTask.java
index 19ec3ed..931466c 100644
--- a/src/com/android/launcher3/model/GridSizeMigrationTask.java
+++ b/src/com/android/launcher3/model/GridSizeMigrationTask.java
@@ -23,8 +23,8 @@
import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.Utilities;
import com.android.launcher3.backup.nano.BackupProtos;
+import com.android.launcher3.compat.AppWidgetManagerCompat;
import com.android.launcher3.compat.PackageInstallerCompat;
-import com.android.launcher3.compat.UserHandleCompat;
import com.android.launcher3.util.LongArrayMap;
import java.util.ArrayList;
@@ -696,7 +696,8 @@
Favorites.SPANX, // 4
Favorites.SPANY, // 5
Favorites.INTENT, // 6
- Favorites.APPWIDGET_PROVIDER}, // 7
+ Favorites.APPWIDGET_PROVIDER, // 7
+ Favorites.APPWIDGET_ID}, // 8
Favorites.CONTAINER + " = " + Favorites.CONTAINER_DESKTOP
+ " AND " + Favorites.SCREEN + " = " + screen, null, null, null);
@@ -708,6 +709,7 @@
final int indexSpanY = c.getColumnIndexOrThrow(Favorites.SPANY);
final int indexIntent = c.getColumnIndexOrThrow(Favorites.INTENT);
final int indexAppWidgetProvider = c.getColumnIndexOrThrow(Favorites.APPWIDGET_PROVIDER);
+ final int indexAppWidgetId = c.getColumnIndexOrThrow(Favorites.APPWIDGET_ID);
ArrayList<DbEntry> entries = new ArrayList<>();
while (c.moveToNext()) {
@@ -737,9 +739,9 @@
entry.weight = Math.max(WT_WIDGET_MIN, WT_WIDGET_FACTOR
* entry.spanX * entry.spanY);
- // Migration happens for current user only.
- LauncherAppWidgetProviderInfo pInfo = LauncherModel.getProviderInfo(
- mContext, cn, UserHandleCompat.myUserHandle());
+ int widgetId = c.getInt(indexAppWidgetId);
+ LauncherAppWidgetProviderInfo pInfo = AppWidgetManagerCompat.getInstance(
+ mContext).getLauncherAppWidgetInfo(widgetId);
Point spans = pInfo == null ?
mWidgetMinSize.get(provider) : pInfo.getMinSpans(mIdp, mContext);
if (spans != null) {
diff --git a/src/com/android/launcher3/model/WidgetsModel.java b/src/com/android/launcher3/model/WidgetsModel.java
index 99a53ff..e043c94 100644
--- a/src/com/android/launcher3/model/WidgetsModel.java
+++ b/src/com/android/launcher3/model/WidgetsModel.java
@@ -1,9 +1,13 @@
package com.android.launcher3.model;
+import android.appwidget.AppWidgetProviderInfo;
import android.content.ComponentName;
import android.content.Context;
+import android.content.Intent;
import android.content.pm.ResolveInfo;
+import android.os.DeadObjectException;
+import android.os.TransactionTooLargeException;
import android.util.Log;
import com.android.launcher3.AppFilter;
@@ -16,6 +20,7 @@
import com.android.launcher3.compat.AlphabeticIndexCompat;
import com.android.launcher3.compat.AppWidgetManagerCompat;
import com.android.launcher3.compat.UserHandleCompat;
+import com.android.launcher3.config.ProviderConfig;
import java.util.ArrayList;
import java.util.Collections;
@@ -95,8 +100,41 @@
return mRawList;
}
- public void setWidgetsAndShortcuts(ArrayList<Object> rawWidgetsShortcuts) {
+ public boolean isEmpty() {
+ return mRawList.isEmpty();
+ }
+
+ public WidgetsModel updateAndClone(Context context) {
Utilities.assertWorkerThread();
+
+ try {
+ final ArrayList<Object> widgetsAndShortcuts = new ArrayList<>();
+ // Widgets
+ for (AppWidgetProviderInfo widgetInfo :
+ AppWidgetManagerCompat.getInstance(context).getAllProviders()) {
+ widgetsAndShortcuts.add(LauncherAppWidgetProviderInfo
+ .fromProviderInfo(context, widgetInfo));
+ }
+ // Shortcuts
+ widgetsAndShortcuts.addAll(context.getPackageManager().queryIntentActivities(
+ new Intent(Intent.ACTION_CREATE_SHORTCUT), 0));
+ setWidgetsAndShortcuts(widgetsAndShortcuts);
+ } catch (Exception e) {
+ if (!ProviderConfig.IS_DOGFOOD_BUILD &&
+ (e.getCause() instanceof TransactionTooLargeException ||
+ e.getCause() instanceof DeadObjectException)) {
+ // 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;
+ }
+ }
+ return clone();
+ }
+
+ private void setWidgetsAndShortcuts(ArrayList<Object> rawWidgetsShortcuts) {
mRawList = rawWidgetsShortcuts;
if (DEBUG) {
Log.d(TAG, "addWidgetsAndShortcuts, widgetsShortcuts#=" + rawWidgetsShortcuts.size());
diff --git a/src/com/android/launcher3/testing/LauncherExtension.java b/src/com/android/launcher3/testing/LauncherExtension.java
index 475762f..d5a340d 100644
--- a/src/com/android/launcher3/testing/LauncherExtension.java
+++ b/src/com/android/launcher3/testing/LauncherExtension.java
@@ -11,6 +11,7 @@
import com.android.launcher3.AppInfo;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherCallbacks;
+import com.android.launcher3.logging.UserEventLogger;
import com.android.launcher3.allapps.AllAppsSearchBarController;
import com.android.launcher3.util.ComponentKey;
@@ -225,6 +226,9 @@
}
@Override
+ public UserEventLogger getLogger() { return null; }
+
+ @Override
public View getQsbBar() {
return null;
}
diff --git a/src/com/android/launcher3/userevent/Logger.java b/src/com/android/launcher3/userevent/Logger.java
deleted file mode 100644
index ae9041a..0000000
--- a/src/com/android/launcher3/userevent/Logger.java
+++ /dev/null
@@ -1,208 +0,0 @@
-package com.android.launcher3.userevent;
-
-import com.android.launcher3.ShortcutInfo;
-import com.android.launcher3.LauncherSettings;
-import com.android.launcher3.Stats;
-import com.android.launcher3.config.FeatureFlags;
-import com.android.launcher3.userevent.nano.LauncherLogProto;
-import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
-import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
-import com.android.launcher3.userevent.nano.LauncherLogProto.LauncherEvent;
-
-import android.content.Context;
-import android.os.Bundle;
-import android.util.Log;
-
-import java.util.Locale;
-
-/**
- * Creates {@LauncherLogProto} nano protobuf object that can be used for user event
- * metrics analysis.
- */
-public class Logger {
-
- private static final String TAG = "UserEventLogger";
- private static final boolean DEBUG = false;
-
- private long mActionDurationMillis;
- private long mElapsedContainerMillis;
- private long mElapsedSessionMillis;
-
- private Context mContext;
-
- public Logger(Context context) {
- mContext = context;
- }
-
- public void logAppLaunch(String provider, ShortcutInfo shortcut, Bundle bundle) {
- LauncherEvent event = new LauncherEvent();
- event.action = new Action();
- event.action.type = Action.TOUCH;
- event.action.touch = Action.TAP;
-
- event.srcTarget = new Target();
- event.srcTarget.type = Target.ITEM;
- event.srcTarget.itemType = LauncherLogProto.APP_ICON;
- // TODO: package hash name should be different per device.
- event.srcTarget.packageNameHash = provider.hashCode();
-
- event.srcTarget.parent = new Target();
- String subContainer = bundle.getString(Stats.SOURCE_EXTRA_SUB_CONTAINER);
-
- if (shortcut != null) {
- event.srcTarget.parent.containerType = getContainerType(shortcut);
- event.srcTarget.pageIndex = (int) shortcut.screenId;
- event.srcTarget.gridX = shortcut.cellX;
- event.srcTarget.gridX = shortcut.cellY;
- }
- if (subContainer != null) {
- event.srcTarget.parent.type = Target.CONTAINER;
- if (subContainer.equals(Stats.SUB_CONTAINER_FOLDER)) {
- event.srcTarget.parent.containerType = LauncherLogProto.FOLDER;
- } else if (subContainer.equals(Stats.SUB_CONTAINER_ALL_APPS_A_Z)) {
- event.srcTarget.parent.containerType = LauncherLogProto.ALLAPPS;
- } else if (subContainer.equals(Stats.CONTAINER_HOTSEAT)) {
- event.srcTarget.parent.containerType = LauncherLogProto.HOTSEAT;
- } else if (subContainer.equals(Stats.SUB_CONTAINER_ALL_APPS_PREDICTION)) {
- event.srcTarget.parent.containerType = LauncherLogProto.PREDICTION;
- }
-
- if (DEBUG) {
- Log.d(TAG, String.format("parent bundle: %s %s %s %s",
- bundle.getString(Stats.SOURCE_EXTRA_CONTAINER),
- bundle.getString(Stats.SOURCE_EXTRA_CONTAINER_PAGE),
- bundle.getString(Stats.SOURCE_EXTRA_SUB_CONTAINER),
- bundle.getString(Stats.SOURCE_EXTRA_SUB_CONTAINER_PAGE)));
- }
- }
-
-
- // Assign timeToAction
- event.elapsedContainerMillis = System.currentTimeMillis() - mElapsedContainerMillis;
- event.elapsedSessionMillis = System.currentTimeMillis() - mElapsedSessionMillis;
-
- // Debug
- processLauncherEvent(event);
- }
-
- public void resetElapsedContainerMillis() {
- mElapsedContainerMillis = System.currentTimeMillis();
- }
-
- public void resetElapsedSessionMillis() {
- mElapsedSessionMillis = System.currentTimeMillis();
- }
-
- //
- // Debugging helper methods.
- // toString() cannot be overriden inside auto generated {@link LauncherLogProto}.
- // Note: switch statement cannot be replaced with reflection as proguard strips the constants
-
- private static void processLauncherEvent(LauncherEvent ev) {
- if (DEBUG) {
- if (ev.action.touch == Action.TAP && ev.srcTarget.itemType == LauncherLogProto.APP_ICON) {
- Log.d(TAG, String.format(Locale.US, "action:%s target:%s\n\telapsed container %d ms session %d ms",
- getActionStr(ev.action),
- getTargetStr(ev.srcTarget),
- ev.elapsedContainerMillis,
- ev.elapsedSessionMillis));
- }
- }
- }
-
- private static int getContainerType(ShortcutInfo shortcut) {
- switch ((int) shortcut.container) {
- case LauncherSettings.Favorites.CONTAINER_DESKTOP: return LauncherLogProto.WORKSPACE;
- case LauncherSettings.Favorites.CONTAINER_HOTSEAT: return LauncherLogProto.HOTSEAT;
- default:
- return (int) shortcut.container;
- }
- }
-
- private static String getActionStr(Action action) {
- switch(action.touch) {
- case Action.TAP: return "TAP";
- case Action.LONGPRESS: return "LONGPRESS";
- case Action.DRAGDROP: return "DRAGDROP";
- case Action.PINCH: return "PINCH";
- default: return "UNKNOWN";
- }
- }
-
- private static String getTargetStr(Target t) {
- String typeStr;
- switch (t.type) {
- case LauncherLogProto.Target.ITEM:
- return getItemStr(t);
- case LauncherLogProto.Target.CONTROL:
- return getControlStr(t);
- case LauncherLogProto.Target.CONTAINER:
- return getContainerStr(t);
- default:
- return "UNKNOWN TARGET TYPE";
- }
- }
-
- private static String getItemStr(Target t) {
- String typeStr = "";
- switch(t.itemType){
- case LauncherLogProto.APP_ICON: typeStr = "ICON"; break;
- case LauncherLogProto.SHORTCUT: typeStr = "SHORTCUT"; break;
- case LauncherLogProto.WIDGET: typeStr = "WIDGET"; break;
- default: typeStr = "UNKNOWN";
- }
-
- return typeStr + " " + t.packageNameHash + " grid=(" + t.gridX + "," + t.gridY + ") "
- + getContainerStr(t.parent);
- }
-
- private static String getControlStr(Target t) {
- switch(t.controlType) {
- case LauncherLogProto.ALL_APPS_BUTTON: return "ALL_APPS_BUTTON";
- case LauncherLogProto.WIDGETS_BUTTON: return "WIDGETS_BUTTON";
- case LauncherLogProto.WALLPAPER_BUTTON: return "WALLPAPER_BUTTON";
- case LauncherLogProto.SETTINGS_BUTTON: return "SETTINGS_BUTTON";
- case LauncherLogProto.REMOVE_TARGET: return "REMOVE_TARGET";
- case LauncherLogProto.UNINSTALL_TARGET: return "UNINSTALL_TARGET";
- case LauncherLogProto.APPINFO_TARGET: return "APPINFO_TARGET";
- case LauncherLogProto.RESIZE_HANDLE: return "RESIZE_HANDLE";
- case LauncherLogProto.FAST_SCROLL_HANDLE: return "FAST_SCROLL_HANDLE";
- default: return "UNKNOWN";
- }
- }
-
- private static String getContainerStr(Target t) {
- String str;
- Log.d(TAG, "t.containerType" + t.containerType);
- switch (t.containerType) {
- case LauncherLogProto.WORKSPACE:
- str = "WORKSPACE";
- break;
- case LauncherLogProto.HOTSEAT:
- str = "HOTSEAT";
- break;
- case LauncherLogProto.FOLDER:
- str = "FOLDER";
- break;
- case LauncherLogProto.ALLAPPS:
- str = "ALLAPPS";
- break;
- case LauncherLogProto.WIDGETS:
- str = "WIDGETS";
- break;
- case LauncherLogProto.OVERVIEW:
- str = "OVERVIEW";
- break;
- case LauncherLogProto.PREDICTION:
- str = "PREDICTION";
- break;
- case LauncherLogProto.SEARCHRESULT:
- str = "SEARCHRESULT";
- break;
- default:
- str = "UNKNOWN";
- }
- return str + " id=" + t.pageIndex;
- }
-}
-
diff --git a/src/com/android/launcher3/widget/WidgetsContainerView.java b/src/com/android/launcher3/widget/WidgetsContainerView.java
index fc2e0be..5d6f475 100644
--- a/src/com/android/launcher3/widget/WidgetsContainerView.java
+++ b/src/com/android/launcher3/widget/WidgetsContainerView.java
@@ -335,6 +335,10 @@
mAdapter.notifyDataSetChanged();
}
+ public boolean isEmpty() {
+ return mAdapter.getItemCount() == 0;
+ }
+
private WidgetPreviewLoader getWidgetPreviewLoader() {
if (mWidgetPreviewLoader == null) {
mWidgetPreviewLoader = LauncherAppState.getInstance().getWidgetCache();