Merge "Don't persist invalid previews to cache" into ub-launcher3-master
diff --git a/OWNERS b/OWNERS
index 6c1273f..538ca33 100644
--- a/OWNERS
+++ b/OWNERS
@@ -10,3 +10,6 @@
sunnygoyal@google.com
twickham@google.com
winsonc@google.com
+
+per-file FeatureFlags.java = sunnygoyal@google.com, adamcohen@google.com
+per-file BaseFlags.java = sunnygoyal@google.com, adamcohen@google.com
diff --git a/go/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java b/go/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
index d0cfcf9..212ce9b 100644
--- a/go/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
+++ b/go/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
@@ -32,6 +32,7 @@
import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_7;
import static com.android.launcher3.states.RotationHelper.REQUEST_ROTATE;
+import android.content.Context;
import android.view.View;
import com.android.launcher3.DeviceProfile;
@@ -115,10 +116,10 @@
}
public static float getDefaultSwipeHeight(Launcher launcher) {
- return getDefaultSwipeHeight(launcher.getDeviceProfile());
+ return getDefaultSwipeHeight(launcher, launcher.getDeviceProfile());
}
- public static float getDefaultSwipeHeight(DeviceProfile dp) {
+ public static float getDefaultSwipeHeight(Context context, DeviceProfile dp) {
return dp.allAppsCellHeightPx - dp.allAppsIconTextSizePx;
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewState.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewState.java
index 151ceb8..93d4de1 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewState.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewState.java
@@ -32,6 +32,7 @@
import static com.android.launcher3.logging.LoggerUtils.newContainerTarget;
import static com.android.launcher3.states.RotationHelper.REQUEST_ROTATE;
+import android.content.Context;
import android.graphics.Rect;
import android.view.View;
@@ -159,11 +160,15 @@
}
public static float getDefaultSwipeHeight(Launcher launcher) {
- return getDefaultSwipeHeight(launcher.getDeviceProfile());
+ return getDefaultSwipeHeight(launcher, launcher.getDeviceProfile());
}
- public static float getDefaultSwipeHeight(DeviceProfile dp) {
- return dp.allAppsCellHeightPx - dp.allAppsIconTextSizePx;
+ public static float getDefaultSwipeHeight(Context context, DeviceProfile dp) {
+ float swipeHeight = dp.allAppsCellHeightPx - dp.allAppsIconTextSizePx;
+ if (SysUINavigationMode.getMode(context) == SysUINavigationMode.Mode.NO_BUTTON) {
+ swipeHeight -= dp.getInsets().bottom;
+ }
+ return swipeHeight;
}
@Override
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java
index 295585e..4f97180 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java
@@ -40,7 +40,6 @@
import android.graphics.RectF;
import android.graphics.Region;
import android.os.UserHandle;
-import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.Interpolator;
@@ -58,7 +57,6 @@
import com.android.launcher3.allapps.DiscoveryBounce;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.AnimatorSetBuilder;
-import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.uioverrides.states.OverviewState;
import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.launcher3.views.FloatingIconView;
@@ -174,6 +172,8 @@
AnimatorSetBuilder builder = new AnimatorSetBuilder();
// setRecentsAttachedToAppWindow() will animate recents out.
builder.addFlag(AnimatorSetBuilder.FLAG_DONT_ANIMATE_OVERVIEW);
+ // We want to keep all apps content as GONE to avoid relayout during home animation.
+ builder.addFlag(AnimatorSetBuilder.FLAG_DONT_UPDATE_ALL_APPS_VISIBILITY);
stateManager.createAtomicAnimation(BACKGROUND_APP, NORMAL, builder, ANIM_ALL, 0);
builder.build().start();
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepTestInformationHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepTestInformationHandler.java
index 61b57e2..72a14b5 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepTestInformationHandler.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepTestInformationHandler.java
@@ -25,7 +25,7 @@
switch (method) {
case TestProtocol.REQUEST_HOME_TO_OVERVIEW_SWIPE_HEIGHT: {
final float swipeHeight =
- OverviewState.getDefaultSwipeHeight(mDeviceProfile);
+ OverviewState.getDefaultSwipeHeight(mContext, mDeviceProfile);
response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD, (int) swipeHeight);
return response;
}
diff --git a/quickstep/src/com/android/quickstep/views/ShelfScrimView.java b/quickstep/src/com/android/quickstep/views/ShelfScrimView.java
index 3747f9a..dc6b56e 100644
--- a/quickstep/src/com/android/quickstep/views/ShelfScrimView.java
+++ b/quickstep/src/com/android/quickstep/views/ShelfScrimView.java
@@ -156,12 +156,14 @@
mDragHandleProgress = 1;
mMidAlpha = 0;
} else {
- mMidAlpha = Themes.getAttrInteger(getContext(), R.attr.allAppsInterimScrimAlpha);
+ Context context = getContext();
+ mMidAlpha = Themes.getAttrInteger(context, R.attr.allAppsInterimScrimAlpha);
mMidProgress = OVERVIEW.getVerticalProgress(mLauncher);
Rect hotseatPadding = dp.getHotseatLayoutPadding();
int hotseatSize = dp.hotseatBarSizePx + dp.getInsets().bottom
- hotseatPadding.bottom - hotseatPadding.top;
- float dragHandleTop = Math.min(hotseatSize, OverviewState.getDefaultSwipeHeight(dp));
+ float dragHandleTop =
+ Math.min(hotseatSize, OverviewState.getDefaultSwipeHeight(context, dp));
mDragHandleProgress = 1 - (dragHandleTop / mShiftRange);
}
mTopOffset = dp.getInsets().top - mShelfOffset;
diff --git a/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java b/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java
index edd5011..e295527 100644
--- a/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java
+++ b/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java
@@ -118,7 +118,6 @@
assertTrue("Couldn't set overlay",
setActiveOverlay(prevOverlayPkg, originalMode));
}
- mLauncher.disableDebugTracing();
}
private void evaluateWithThreeButtons() throws Throwable {
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
index be8506d..885fdbf 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
@@ -97,7 +97,6 @@
@Test
@PortraitLandscape
public void testOverview() throws Exception {
- mLauncher.enableDebugTracing();
startTestApps();
Overview overview = mLauncher.pressHome().switchToOverview();
assertTrue("Launcher internal state didn't switch to Overview",
@@ -177,7 +176,6 @@
executeOnLauncher(
launcher -> assertEquals("Still have tasks after dismissing all",
0, getTaskCount(launcher)));
- mLauncher.disableDebugTracing();
}
private int getCurrentOverviewPage(Launcher launcher) {
diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml
index 071b71e..e0d2c74 100644
--- a/res/values-pt-rPT/strings.xml
+++ b/res/values-pt-rPT/strings.xml
@@ -20,7 +20,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="649227358658669779">"Launcher3"</string>
- <string name="folder_name" msgid="7371454440695724752"></string>
<string name="work_folder_name" msgid="3753320833950115786">"Trabalho"</string>
<string name="activity_not_found" msgid="8071924732094499514">"A aplicação não está instalada."</string>
<string name="activity_not_available" msgid="7456344436509528827">"A aplicação não está disponível"</string>
diff --git a/res/values-sq/strings.xml b/res/values-sq/strings.xml
index 48ae26e..7f2567c 100644
--- a/res/values-sq/strings.xml
+++ b/res/values-sq/strings.xml
@@ -20,7 +20,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="649227358658669779">"Nisësi3"</string>
- <string name="folder_name" msgid="7371454440695724752"></string>
<string name="work_folder_name" msgid="3753320833950115786">"Puna"</string>
<string name="activity_not_found" msgid="8071924732094499514">"Aplikacioni nuk është i instaluar."</string>
<string name="activity_not_available" msgid="7456344436509528827">"Aplikacioni nuk mundësohet"</string>
@@ -41,8 +40,8 @@
<string name="all_apps_search_market_message" msgid="1366263386197059176">"Kërko për më shumë aplikacione"</string>
<string name="label_application" msgid="8531721983832654978">"Aplikacioni"</string>
<string name="notifications_header" msgid="1404149926117359025">"Njoftimet"</string>
- <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"Prek dhe mbaj prekur për të zgjedhur një shkurtore."</string>
- <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"Prek dy herë dhe mbaj prekur për të zgjedhur një shkurtore ose për të përdorur veprimet e personalizuara."</string>
+ <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"Prek dhe mbaj të shtypur për të zgjedhur një shkurtore."</string>
+ <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"Prek dy herë dhe mbaj të shtypur për të zgjedhur një shkurtore ose për të përdorur veprimet e personalizuara."</string>
<string name="out_of_space" msgid="4691004494942118364">"Nuk ka më hapësirë në këtë ekran bazë."</string>
<string name="hotseat_out_of_space" msgid="7448809638125333693">"Nuk ka më hapësirë në tabakanë \"Të preferuarat\""</string>
<string name="all_apps_button_label" msgid="8130441508702294465">"Lista e aplikacioneve"</string>
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index 69b8c8a..2b265fa 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -152,21 +152,6 @@
<attr name="canThumbDetach" format="boolean" />
</declare-styleable>
- <declare-styleable name="CustomAppWidgetProviderInfo">
- <attr name="providerId" format="integer" />
-
- <attr name="android:label" />
- <attr name="android:initialLayout" />
- <attr name="android:icon" />
- <attr name="android:previewImage" />
- <attr name="android:resizeMode" />
-
- <attr name="numRows" />
- <attr name="numColumns" />
- <attr name="numMinRows" format="integer" />
- <attr name="numMinColumns" format="integer" />
- </declare-styleable>
-
<declare-styleable name="PreviewFragment">
<attr name="android:name" />
<attr name="android:id" />
diff --git a/res/xml/custom_widgets.xml b/res/xml/custom_widgets.xml
deleted file mode 100644
index 4b54386..0000000
--- a/res/xml/custom_widgets.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- 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.
--->
-
-<widgets>
- <!-- Sample widget definition
- <widget
- android:label="My custom widget"
- android:initialLayout="@layout/sample_widget_layout"
- android:icon="@drawable/ic_launcher_home"
- android:resizeMode="horizontal|vertical"
- launcher:numRows="2"
- launcher:numColumns="3"
- launcher:numMinRows="1"
- launcher:numMinColumns="2"
- launcher:providerId="1" />
- -->
-</widgets>
\ No newline at end of file
diff --git a/src/com/android/launcher3/InstallShortcutReceiver.java b/src/com/android/launcher3/InstallShortcutReceiver.java
index 9f05795..fb80537 100644
--- a/src/com/android/launcher3/InstallShortcutReceiver.java
+++ b/src/com/android/launcher3/InstallShortcutReceiver.java
@@ -137,7 +137,15 @@
if (DBG) {
Log.d(TAG, "Ignoring shortcut for absent package: " + info.launchIntent);
}
+ continue;
}
+
+ // Generate a shortcut info to add into the model
+ installQueue.add(info.getItemInfo());
+ }
+ prefs.edit().remove(APPS_PENDING_INSTALL).apply();
+ if (!installQueue.isEmpty()) {
+ model.addAndBindAddedWorkspaceItems(installQueue);
}
}
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index aa02441..ea58687 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -147,7 +147,7 @@
import com.android.launcher3.widget.WidgetHostViewLoader;
import com.android.launcher3.widget.WidgetListRowEntry;
import com.android.launcher3.widget.WidgetsFullSheet;
-import com.android.launcher3.widget.custom.CustomWidgetParser;
+import com.android.launcher3.widget.custom.CustomWidgetManager;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -1657,10 +1657,9 @@
} else {
// In this case, we either need to start an activity to get permission to bind
// the widget, or we need to start an activity to configure the widget, or both.
- if (FeatureFlags.ENABLE_CUSTOM_WIDGETS &&
- info.itemType == LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET) {
- appWidgetId = CustomWidgetParser.getWidgetIdForCustomProvider(
- this, info.componentName);
+ if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET) {
+ appWidgetId = CustomWidgetManager.INSTANCE.get(this).getWidgetIdForCustomProvider(
+ info.componentName);
} else {
appWidgetId = getAppWidgetHost().allocateAppWidgetId();
}
diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java
index 2a801d6..82b1ea7 100644
--- a/src/com/android/launcher3/LauncherAppState.java
+++ b/src/com/android/launcher3/LauncherAppState.java
@@ -37,6 +37,7 @@
import com.android.launcher3.util.MainThreadInitializedObject;
import com.android.launcher3.util.Preconditions;
import com.android.launcher3.util.SecureSettingsObserver;
+import com.android.launcher3.widget.custom.CustomWidgetManager;
public class LauncherAppState {
@@ -148,6 +149,8 @@
LauncherModel setLauncher(Launcher launcher) {
getLocalProvider(mContext).setLauncherProviderChangeListener(launcher);
mModel.initialize(launcher);
+ CustomWidgetManager.INSTANCE.get(launcher)
+ .setWidgetRefreshCallback(mModel::refreshAndBindWidgetsAndShortcuts);
return mModel;
}
diff --git a/src/com/android/launcher3/LauncherAppWidgetHost.java b/src/com/android/launcher3/LauncherAppWidgetHost.java
index 7f5ac52..1139f29 100644
--- a/src/com/android/launcher3/LauncherAppWidgetHost.java
+++ b/src/com/android/launcher3/LauncherAppWidgetHost.java
@@ -27,12 +27,12 @@
import android.content.Intent;
import android.os.Handler;
import android.util.SparseArray;
-import android.view.LayoutInflater;
import android.widget.Toast;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.widget.DeferredAppWidgetHostView;
import com.android.launcher3.widget.LauncherAppWidgetHostView;
+import com.android.launcher3.widget.custom.CustomWidgetManager;
import java.util.ArrayList;
@@ -180,10 +180,8 @@
LauncherAppWidgetProviderInfo appWidget) {
if (appWidget.isCustomWidget()) {
LauncherAppWidgetHostView lahv = new LauncherAppWidgetHostView(context);
- LayoutInflater inflater = (LayoutInflater)
- context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- inflater.inflate(appWidget.initialLayout, lahv);
lahv.setAppWidget(0, appWidget);
+ CustomWidgetManager.INSTANCE.get(context).onViewCreated(lahv);
return lahv;
} else if ((mFlags & FLAG_LISTENING) == 0) {
DeferredAppWidgetHostView view = new DeferredAppWidgetHostView(context);
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index da9617a..8433a91 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -523,5 +523,4 @@
public Callbacks getCallback() {
return mCallbacks != null ? mCallbacks.get() : null;
}
-
}
diff --git a/src/com/android/launcher3/LauncherStateManager.java b/src/com/android/launcher3/LauncherStateManager.java
index e1ea3be..63914b0 100644
--- a/src/com/android/launcher3/LauncherStateManager.java
+++ b/src/com/android/launcher3/LauncherStateManager.java
@@ -228,8 +228,9 @@
private void goToState(LauncherState state, boolean animated, long delay,
final Runnable onCompleteRunnable) {
if (TestProtocol.sDebugTracing) {
- Log.d(TestProtocol.ALL_APPS_UPON_RECENTS, "goToState: " + state + " @ " +
- Log.getStackTraceString(new Throwable()));
+ Log.d(TestProtocol.ALL_APPS_UPON_RECENTS, "goToState: " +
+ state.getClass().getSimpleName() +
+ " @ " + Log.getStackTraceString(new Throwable()));
}
animated &= Utilities.areAnimationsEnabled(mLauncher);
if (mLauncher.isInState(state)) {
@@ -411,6 +412,11 @@
mState.onStateDisabled(mLauncher);
}
mState = state;
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.STABLE_STATE_MISMATCH, "onStateTransitionStart: " +
+ state.getClass().getSimpleName() +
+ " @ " + Log.getStackTraceString(new Throwable()));
+ }
mState.onStateEnabled(mLauncher);
mLauncher.onStateSet(mState);
@@ -431,7 +437,9 @@
mLastStableState = state.getHistoryForState(mCurrentStableState);
mCurrentStableState = state;
if (TestProtocol.sDebugTracing) {
- Log.d(TestProtocol.ALL_APPS_UPON_RECENTS, "onStateTransitionEnd: " + state);
+ Log.d(TestProtocol.ALL_APPS_UPON_RECENTS, "onStateTransitionEnd: " +
+ state.getClass().getSimpleName() +
+ " @ " + Log.getStackTraceString(new Throwable()));
}
}
diff --git a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
index a0e9dc5..1399302 100644
--- a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
@@ -26,13 +26,14 @@
import android.view.MotionEvent;
import android.view.View;
+import androidx.recyclerview.widget.RecyclerView;
+
import com.android.launcher3.BaseRecyclerView;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.ItemInfo;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
import com.android.launcher3.compat.AccessibilityManagerCompat;
import com.android.launcher3.logging.StatsLogUtils.LogContainerProvider;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
@@ -41,8 +42,6 @@
import java.util.List;
-import androidx.recyclerview.widget.RecyclerView;
-
/**
* A RecyclerView with custom fast scroll support for the all apps view.
*/
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index 5b3beec..dfddc61 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -1,5 +1,7 @@
package com.android.launcher3.allapps;
+import static android.view.View.ALPHA;
+
import static com.android.launcher3.LauncherState.ALL_APPS_CONTENT;
import static com.android.launcher3.LauncherState.ALL_APPS_HEADER_EXTRA;
import static com.android.launcher3.LauncherState.BACKGROUND_APP;
@@ -10,6 +12,7 @@
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_ALL_APPS_HEADER_FADE;
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_SCALE;
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_VERTICAL_PROGRESS;
+import static com.android.launcher3.anim.AnimatorSetBuilder.FLAG_DONT_UPDATE_ALL_APPS_VISIBILITY;
import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.anim.PropertySetter.NO_ANIM_PROPERTY_SETTER;
@@ -18,7 +21,7 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.util.FloatProperty;
-import android.util.Log;
+import android.view.View;
import android.view.animation.Interpolator;
import com.android.launcher3.DeviceProfile;
@@ -32,7 +35,6 @@
import com.android.launcher3.anim.AnimatorSetBuilder;
import com.android.launcher3.anim.PropertySetter;
import com.android.launcher3.anim.SpringObjectAnimator;
-import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.util.Themes;
import com.android.launcher3.views.ScrimView;
@@ -213,7 +215,12 @@
Interpolator allAppsFade = builder.getInterpolator(ANIM_ALL_APPS_FADE, LINEAR);
Interpolator headerFade = builder.getInterpolator(ANIM_ALL_APPS_HEADER_FADE, allAppsFade);
- setter.setViewAlpha(mAppsView.getContentView(), hasAllAppsContent ? 1 : 0, allAppsFade);
+ View allAppsContent = mAppsView.getContentView();
+ if (!hasAllAppsContent && builder.hasFlag(FLAG_DONT_UPDATE_ALL_APPS_VISIBILITY)) {
+ setter.setFloat(allAppsContent, ALPHA, 0, allAppsFade);
+ } else {
+ setter.setViewAlpha(allAppsContent, hasAllAppsContent ? 1 : 0, allAppsFade);
+ }
setter.setViewAlpha(mAppsView.getScrollBar(), hasAllAppsContent ? 1 : 0, allAppsFade);
mAppsView.getFloatingHeaderView().setContentVisibility(hasHeaderExtra, hasAllAppsContent,
setter, headerFade, allAppsFade);
diff --git a/src/com/android/launcher3/anim/AnimatorSetBuilder.java b/src/com/android/launcher3/anim/AnimatorSetBuilder.java
index cd30dea..07e7553 100644
--- a/src/com/android/launcher3/anim/AnimatorSetBuilder.java
+++ b/src/com/android/launcher3/anim/AnimatorSetBuilder.java
@@ -43,6 +43,7 @@
public static final int ANIM_ALL_APPS_HEADER_FADE = 12; // e.g. predictions
public static final int FLAG_DONT_ANIMATE_OVERVIEW = 1 << 0;
+ public static final int FLAG_DONT_UPDATE_ALL_APPS_VISIBILITY = 1 << 1;
protected final ArrayList<Animator> mAnims = new ArrayList<>();
diff --git a/src/com/android/launcher3/compat/AppWidgetManagerCompat.java b/src/com/android/launcher3/compat/AppWidgetManagerCompat.java
index 3243256..fc5d11c 100644
--- a/src/com/android/launcher3/compat/AppWidgetManagerCompat.java
+++ b/src/com/android/launcher3/compat/AppWidgetManagerCompat.java
@@ -23,19 +23,18 @@
import android.os.Bundle;
import android.os.UserHandle;
+import androidx.annotation.Nullable;
+
import com.android.launcher3.LauncherAppWidgetInfo;
import com.android.launcher3.LauncherAppWidgetProviderInfo;
import com.android.launcher3.Utilities;
-import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.PackageUserKey;
-import com.android.launcher3.widget.custom.CustomWidgetParser;
+import com.android.launcher3.widget.custom.CustomWidgetManager;
import java.util.HashMap;
import java.util.List;
-import androidx.annotation.Nullable;
-
public abstract class AppWidgetManagerCompat {
private static final Object sInstanceLock = new Object();
@@ -63,11 +62,9 @@
}
public LauncherAppWidgetProviderInfo getLauncherAppWidgetInfo(int appWidgetId) {
- if (FeatureFlags.ENABLE_CUSTOM_WIDGETS
- && appWidgetId <= LauncherAppWidgetInfo.CUSTOM_WIDGET_ID) {
- return CustomWidgetParser.getWidgetProvider(mContext, appWidgetId);
+ if (appWidgetId <= LauncherAppWidgetInfo.CUSTOM_WIDGET_ID) {
+ return CustomWidgetManager.INSTANCE.get(mContext).getWidgetProvider(appWidgetId);
}
-
AppWidgetProviderInfo info = mAppWidgetManager.getAppWidgetInfo(appWidgetId);
return info == null ? null : LauncherAppWidgetProviderInfo.fromProviderInfo(mContext, info);
}
diff --git a/src/com/android/launcher3/compat/AppWidgetManagerCompatVL.java b/src/com/android/launcher3/compat/AppWidgetManagerCompatVL.java
index 1065748..c8b1f67 100644
--- a/src/com/android/launcher3/compat/AppWidgetManagerCompatVL.java
+++ b/src/com/android/launcher3/compat/AppWidgetManagerCompatVL.java
@@ -24,12 +24,15 @@
import android.os.UserHandle;
import android.os.UserManager;
+import androidx.annotation.Nullable;
+
import com.android.launcher3.LauncherAppWidgetInfo;
import com.android.launcher3.LauncherAppWidgetProviderInfo;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.PackageUserKey;
-import com.android.launcher3.widget.custom.CustomWidgetParser;
+import com.android.launcher3.widget.custom.CustomAppWidgetProviderInfo;
+import com.android.launcher3.widget.custom.CustomWidgetManager;
import java.util.ArrayList;
import java.util.Collections;
@@ -37,8 +40,6 @@
import java.util.Iterator;
import java.util.List;
-import androidx.annotation.Nullable;
-
class AppWidgetManagerCompatVL extends AppWidgetManagerCompat {
private final UserManager mUserManager;
@@ -54,14 +55,11 @@
return Collections.emptyList();
}
if (packageUser == null) {
- ArrayList<AppWidgetProviderInfo> providers = new ArrayList<AppWidgetProviderInfo>();
+ ArrayList<AppWidgetProviderInfo> providers = new ArrayList<>();
for (UserHandle user : mUserManager.getUserProfiles()) {
providers.addAll(mAppWidgetManager.getInstalledProvidersForProfile(user));
}
-
- if (FeatureFlags.ENABLE_CUSTOM_WIDGETS) {
- providers.addAll(CustomWidgetParser.getCustomWidgets(mContext));
- }
+ providers.addAll(getCustomWidgets());
return providers;
}
// Only get providers for the given package/user.
@@ -74,9 +72,9 @@
}
}
- if (FeatureFlags.ENABLE_CUSTOM_WIDGETS && Process.myUserHandle().equals(packageUser.mUser)
+ if (Process.myUserHandle().equals(packageUser.mUser)
&& mContext.getPackageName().equals(packageUser.mPackageName)) {
- providers.addAll(CustomWidgetParser.getCustomWidgets(mContext));
+ providers.addAll(getCustomWidgets());
}
return providers;
}
@@ -87,9 +85,7 @@
if (FeatureFlags.GO_DISABLE_WIDGETS) {
return false;
}
-
- if (FeatureFlags.ENABLE_CUSTOM_WIDGETS
- && appWidgetId <= LauncherAppWidgetInfo.CUSTOM_WIDGET_ID) {
+ if (appWidgetId <= LauncherAppWidgetInfo.CUSTOM_WIDGET_ID) {
return true;
}
return mAppWidgetManager.bindAppWidgetIdIfAllowed(
@@ -108,9 +104,8 @@
}
}
- if (FeatureFlags.ENABLE_CUSTOM_WIDGETS && Process.myUserHandle().equals(user)) {
- for (LauncherAppWidgetProviderInfo info :
- CustomWidgetParser.getCustomWidgets(mContext)) {
+ if (Process.myUserHandle().equals(user)) {
+ for (LauncherAppWidgetProviderInfo info : getCustomWidgets()) {
if (info.provider.equals(provider)) {
return info;
}
@@ -131,13 +126,13 @@
result.put(new ComponentKey(info.provider, user), info);
}
}
-
- if (FeatureFlags.ENABLE_CUSTOM_WIDGETS) {
- for (LauncherAppWidgetProviderInfo info :
- CustomWidgetParser.getCustomWidgets(mContext)) {
- result.put(new ComponentKey(info.provider, info.getProfile()), info);
- }
+ for (LauncherAppWidgetProviderInfo info : getCustomWidgets()) {
+ result.put(new ComponentKey(info.provider, info.getProfile()), info);
}
return result;
}
+
+ List<CustomAppWidgetProviderInfo> getCustomWidgets() {
+ return CustomWidgetManager.INSTANCE.get(mContext).getCustomWidgets();
+ }
}
diff --git a/src/com/android/launcher3/compat/AppWidgetManagerCompatVO.java b/src/com/android/launcher3/compat/AppWidgetManagerCompatVO.java
index b7b0563..11ec333 100644
--- a/src/com/android/launcher3/compat/AppWidgetManagerCompatVO.java
+++ b/src/com/android/launcher3/compat/AppWidgetManagerCompatVO.java
@@ -19,14 +19,14 @@
import android.appwidget.AppWidgetProviderInfo;
import android.content.Context;
+import androidx.annotation.Nullable;
+
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.util.PackageUserKey;
import java.util.Collections;
import java.util.List;
-import androidx.annotation.Nullable;
-
class AppWidgetManagerCompatVO extends AppWidgetManagerCompatVL {
AppWidgetManagerCompatVO(Context context) {
diff --git a/src/com/android/launcher3/compat/PackageInstallerCompatVL.java b/src/com/android/launcher3/compat/PackageInstallerCompatVL.java
index 607be5b..c423d13 100644
--- a/src/com/android/launcher3/compat/PackageInstallerCompatVL.java
+++ b/src/com/android/launcher3/compat/PackageInstallerCompatVL.java
@@ -135,6 +135,25 @@
}
}
+ /**
+ * Add a promise app icon to the workspace iff:
+ * - The settings for it are enabled
+ * - The user installed the app
+ * - There is a provided app icon (For apps with no launching activity, no icon is provided).
+ */
+ private void tryQueuePromiseAppIcon(SessionInfo sessionInfo) {
+ if (Utilities.ATLEAST_OREO && FeatureFlags.PROMISE_APPS_NEW_INSTALLS.get()
+ && SessionCommitReceiver.isEnabled(mAppContext)
+ && sessionInfo != null
+ && sessionInfo.getInstallReason() == PackageManager.INSTALL_REASON_USER
+ && sessionInfo.getAppIcon() != null
+ && !mPromiseIconIds.contains(sessionInfo.getSessionId())) {
+ SessionCommitReceiver.queuePromiseAppIconAddition(mAppContext, sessionInfo);
+ mPromiseIconIds.add(sessionInfo.getSessionId());
+ updatePromiseIconPrefs();
+ }
+ }
+
private final SessionCallback mCallback = new SessionCallback() {
@Override
@@ -148,16 +167,7 @@
}
}
- if (Utilities.ATLEAST_OREO && FeatureFlags.PROMISE_APPS_NEW_INSTALLS.get()
- && SessionCommitReceiver.isEnabled(mAppContext)
- && sessionInfo != null
- && sessionInfo.getInstallReason() == PackageManager.INSTALL_REASON_USER) {
- SessionCommitReceiver.queuePromiseAppIconAddition(mAppContext, sessionInfo);
- if (!mPromiseIconIds.contains(sessionInfo.getSessionId())) {
- mPromiseIconIds.add(sessionInfo.getSessionId());
- updatePromiseIconPrefs();
- }
- }
+ tryQueuePromiseAppIcon(sessionInfo);
}
@Override
@@ -195,7 +205,10 @@
@Override
public void onBadgingChanged(int sessionId) {
- pushSessionDisplayToLauncher(sessionId);
+ SessionInfo sessionInfo = pushSessionDisplayToLauncher(sessionId);
+ if (sessionInfo != null) {
+ tryQueuePromiseAppIcon(sessionInfo);
+ }
}
private SessionInfo pushSessionDisplayToLauncher(int sessionId) {
diff --git a/src/com/android/launcher3/config/BaseFlags.java b/src/com/android/launcher3/config/BaseFlags.java
index 1523278..46243f7 100644
--- a/src/com/android/launcher3/config/BaseFlags.java
+++ b/src/com/android/launcher3/config/BaseFlags.java
@@ -23,11 +23,11 @@
import androidx.annotation.GuardedBy;
import androidx.annotation.Keep;
-
import androidx.annotation.VisibleForTesting;
-import com.android.launcher3.Utilities;
+import com.android.launcher3.Utilities;
import com.android.launcher3.uioverrides.TogglableFlag;
+
import java.util.ArrayList;
import java.util.List;
import java.util.SortedMap;
@@ -74,9 +74,6 @@
//Feature flag to enable pulling down navigation shade from workspace.
public static final boolean PULL_DOWN_STATUS_BAR = true;
- // When true, custom widgets are loaded using CustomWidgetParser.
- public static final boolean ENABLE_CUSTOM_WIDGETS = false;
-
// Features to control Launcher3Go behavior
public static final boolean GO_DISABLE_WIDGETS = false;
diff --git a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
index 6e60773..dfd5a70 100644
--- a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
+++ b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
@@ -124,13 +124,11 @@
// App was installed while launcher was in the background.
itemInfo = new AppInfo(app.getContext(), activities.get(0), item.user)
.makeWorkspaceItem();
- PackageItemInfo info = new PackageItemInfo(packageName);
WorkspaceItemInfo wii = (WorkspaceItemInfo) itemInfo;
- app.getIconCache().getTitleAndIconForApp(info, wii.usingLowResIcon());
- wii.title = info.title;
- wii.contentDescription = info.contentDescription;
- wii.iconBitmap = info.iconBitmap;
- wii.iconColor = info.iconColor;
+ wii.title = "";
+ wii.applyFrom(app.getIconCache().getDefaultIcon(item.user));
+ app.getIconCache().getTitleAndIcon(wii,
+ ((WorkspaceItemInfo) itemInfo).usingLowResIcon());
} else {
// Session was cancelled, do not add.
continue;
diff --git a/src/com/android/launcher3/provider/RestoreDbTask.java b/src/com/android/launcher3/provider/RestoreDbTask.java
index 0a2d4e3..fb33551 100644
--- a/src/com/android/launcher3/provider/RestoreDbTask.java
+++ b/src/com/android/launcher3/provider/RestoreDbTask.java
@@ -172,12 +172,6 @@
values.put(Favorites.PROFILE_ID, newProfileId);
db.update(Favorites.TABLE_NAME, values, "profileId = ?",
new String[]{Long.toString(oldProfileId)});
-
- // Change default value of the column.
- db.execSQL("ALTER TABLE favorites RENAME TO favorites_old;");
- Favorites.addTableToDb(db, newProfileId, false);
- db.execSQL("INSERT INTO favorites SELECT * FROM favorites_old;");
- dropTable(db, "favorites_old");
}
diff --git a/src/com/android/launcher3/testing/TestProtocol.java b/src/com/android/launcher3/testing/TestProtocol.java
index 520598a..d569d40 100644
--- a/src/com/android/launcher3/testing/TestProtocol.java
+++ b/src/com/android/launcher3/testing/TestProtocol.java
@@ -83,4 +83,5 @@
public static final String NO_DRAG_TO_WORKSPACE = "b/138729456";
public static final String APP_NOT_DISABLED = "b/139891609";
public static final String ALL_APPS_UPON_RECENTS = "b/139941530";
+ public static final String STABLE_STATE_MISMATCH = "b/140311911";
}
diff --git a/src/com/android/launcher3/views/AbstractSlideInView.java b/src/com/android/launcher3/views/AbstractSlideInView.java
index f948beb..a4518ba 100644
--- a/src/com/android/launcher3/views/AbstractSlideInView.java
+++ b/src/com/android/launcher3/views/AbstractSlideInView.java
@@ -153,15 +153,15 @@
}
protected void handleClose(boolean animate, long defaultDuration) {
- if (mIsOpen && !animate) {
+ if (!mIsOpen) {
+ return;
+ }
+ if (!animate) {
mOpenCloseAnimator.cancel();
setTranslationShift(TRANSLATION_SHIFT_CLOSED);
onCloseComplete();
return;
}
- if (!mIsOpen) {
- return;
- }
mOpenCloseAnimator.setValues(
PropertyValuesHolder.ofFloat(TRANSLATION_SHIFT, TRANSLATION_SHIFT_CLOSED));
mOpenCloseAnimator.addListener(new AnimatorListenerAdapter() {
diff --git a/src/com/android/launcher3/views/OptionsPopupView.java b/src/com/android/launcher3/views/OptionsPopupView.java
index 63f7427..465df44 100644
--- a/src/com/android/launcher3/views/OptionsPopupView.java
+++ b/src/com/android/launcher3/views/OptionsPopupView.java
@@ -18,10 +18,8 @@
import static com.android.launcher3.Utilities.EXTRA_WALLPAPER_FLAVOR;
import static com.android.launcher3.Utilities.EXTRA_WALLPAPER_OFFSET;
-import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
-import android.content.pm.ResolveInfo;
import android.graphics.Rect;
import android.graphics.RectF;
import android.text.TextUtils;
@@ -33,6 +31,9 @@
import android.view.View.OnLongClickListener;
import android.widget.Toast;
+import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
+
import com.android.launcher3.Launcher;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
@@ -46,7 +47,6 @@
import java.util.ArrayList;
import java.util.List;
-import androidx.annotation.VisibleForTesting;
/**
* Popup shown on long pressing an empty space in launcher
@@ -169,16 +169,17 @@
}
public static boolean onWidgetsClicked(View view) {
- return openWidgets(Launcher.getLauncher(view.getContext()));
+ return openWidgets(Launcher.getLauncher(view.getContext())) != null;
}
- public static boolean openWidgets(Launcher launcher) {
+ /** Returns WidgetsFullSheet that was opened, or null if nothing was opened. */
+ @Nullable
+ public static WidgetsFullSheet openWidgets(Launcher launcher) {
if (launcher.getPackageManager().isSafeMode()) {
Toast.makeText(launcher, R.string.safemode_widget_error, Toast.LENGTH_SHORT).show();
- return false;
+ return null;
} else {
- WidgetsFullSheet.show(launcher, true /* animated */);
- return true;
+ return WidgetsFullSheet.show(launcher, true /* animated */);
}
}
diff --git a/src/com/android/launcher3/views/ScrimView.java b/src/com/android/launcher3/views/ScrimView.java
index c360117..da1df3f 100644
--- a/src/com/android/launcher3/views/ScrimView.java
+++ b/src/com/android/launcher3/views/ScrimView.java
@@ -18,14 +18,14 @@
import static android.content.Context.ACCESSIBILITY_SERVICE;
import static android.view.MotionEvent.ACTION_DOWN;
+import static androidx.core.graphics.ColorUtils.compositeColors;
+
import static com.android.launcher3.LauncherState.ALL_APPS;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.anim.Interpolators.ACCEL;
import static com.android.launcher3.anim.Interpolators.DEACCEL;
import static com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound;
-import static androidx.core.graphics.ColorUtils.compositeColors;
-
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.Keyframe;
@@ -47,6 +47,13 @@
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.core.view.ViewCompat;
+import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
+import androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat;
+import androidx.customview.widget.ExploreByTouchHelper;
+
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Insettable;
import com.android.launcher3.Launcher;
@@ -62,15 +69,10 @@
import com.android.launcher3.util.MultiValueAlpha;
import com.android.launcher3.util.MultiValueAlpha.AlphaProperty;
import com.android.launcher3.util.Themes;
+import com.android.launcher3.widget.WidgetsFullSheet;
import java.util.List;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.core.view.ViewCompat;
-import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
-import androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat;
-import androidx.customview.widget.ExploreByTouchHelper;
/**
* Simple scrim which draws a flat color
@@ -325,7 +327,7 @@
if (enabled) {
stateManager.addStateListener(this);
- handleStateChangedComplete(mLauncher.getStateManager().getState());
+ handleStateChangedComplete(stateManager.getState());
} else {
setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
}
@@ -437,7 +439,24 @@
} else if (action == WALLPAPERS) {
return OptionsPopupView.startWallpaperPicker(ScrimView.this);
} else if (action == WIDGETS) {
- return OptionsPopupView.onWidgetsClicked(ScrimView.this);
+ int originalImportanceForAccessibility = getImportantForAccessibility();
+ setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
+ WidgetsFullSheet widgetsFullSheet = OptionsPopupView.openWidgets(mLauncher);
+ if (widgetsFullSheet == null) {
+ setImportantForAccessibility(originalImportanceForAccessibility);
+ return false;
+ }
+ widgetsFullSheet.addOnAttachStateChangeListener(new OnAttachStateChangeListener() {
+ @Override
+ public void onViewAttachedToWindow(View view) {}
+
+ @Override
+ public void onViewDetachedFromWindow(View view) {
+ setImportantForAccessibility(originalImportanceForAccessibility);
+ widgetsFullSheet.removeOnAttachStateChangeListener(this);
+ }
+ });
+ return true;
} else if (action == SETTINGS) {
return OptionsPopupView.startSettings(ScrimView.this);
}
diff --git a/src/com/android/launcher3/widget/custom/CustomWidgetManager.java b/src/com/android/launcher3/widget/custom/CustomWidgetManager.java
new file mode 100644
index 0000000..cf3e26d
--- /dev/null
+++ b/src/com/android/launcher3/widget/custom/CustomWidgetManager.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2019 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.widget.custom;
+
+import static com.android.launcher3.LauncherAppWidgetProviderInfo.CLS_CUSTOM_WIDGET_PREFIX;
+
+import android.appwidget.AppWidgetManager;
+import android.appwidget.AppWidgetProviderInfo;
+import android.content.ComponentName;
+import android.content.Context;
+import android.os.Parcel;
+import android.os.Process;
+import android.util.SparseArray;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.launcher3.LauncherAppWidgetInfo;
+import com.android.launcher3.LauncherAppWidgetProviderInfo;
+import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
+import com.android.launcher3.util.MainThreadInitializedObject;
+import com.android.launcher3.util.PackageUserKey;
+import com.android.launcher3.widget.LauncherAppWidgetHostView;
+import com.android.systemui.plugins.CustomWidgetPlugin;
+import com.android.systemui.plugins.PluginListener;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Consumer;
+
+/**
+ * CustomWidgetManager handles custom widgets implemented as a plugin.
+ */
+public class CustomWidgetManager implements PluginListener<CustomWidgetPlugin> {
+
+ public static final MainThreadInitializedObject<CustomWidgetManager> INSTANCE =
+ new MainThreadInitializedObject<>(CustomWidgetManager::new);
+
+ private final List<CustomWidgetPlugin> mPlugins;
+ private final List<CustomAppWidgetProviderInfo> mCustomWidgets;
+ private final SparseArray<ComponentName> mWidgetsIdMap;
+ private Consumer<PackageUserKey> mWidgetRefreshCallback;
+
+ private CustomWidgetManager(Context context) {
+ mPlugins = new ArrayList<>();
+ mCustomWidgets = new ArrayList<>();
+ mWidgetsIdMap = new SparseArray<>();
+ PluginManagerWrapper.INSTANCE.get(context)
+ .addPluginListener(this, CustomWidgetPlugin.class, true);
+ }
+
+ @Override
+ public void onPluginConnected(CustomWidgetPlugin plugin, Context context) {
+ mPlugins.add(plugin);
+ List<AppWidgetProviderInfo> providers = AppWidgetManager.getInstance(context)
+ .getInstalledProvidersForProfile(Process.myUserHandle());
+ if (providers.isEmpty()) return;
+ Parcel parcel = Parcel.obtain();
+ providers.get(0).writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ CustomAppWidgetProviderInfo info = newInfo(plugin, parcel, context);
+ parcel.recycle();
+ mCustomWidgets.add(info);
+ mWidgetsIdMap.put(plugin.getProviderId(), info.provider);
+ mWidgetRefreshCallback.accept(null);
+ }
+
+ @Override
+ public void onPluginDisconnected(CustomWidgetPlugin plugin) {
+ mPlugins.remove(plugin);
+ mCustomWidgets.remove(getWidgetProvider(plugin.getProviderId()));
+ mWidgetsIdMap.remove(plugin.getProviderId());
+ }
+
+ /**
+ * Inject a callback function to refresh the widgets.
+ */
+ public void setWidgetRefreshCallback(Consumer<PackageUserKey> cb) {
+ mWidgetRefreshCallback = cb;
+ }
+
+ /**
+ * Callback method to inform a plugin it's corresponding widget has been created.
+ */
+ public void onViewCreated(LauncherAppWidgetHostView view) {
+ CustomAppWidgetProviderInfo info = (CustomAppWidgetProviderInfo) view.getAppWidgetInfo();
+ CustomWidgetPlugin plugin = findPlugin(info.providerId);
+ if (plugin == null) return;
+ plugin.onViewCreated(view);
+ }
+
+ /**
+ * Returns the list of custom widgets.
+ */
+ @NonNull
+ public List<CustomAppWidgetProviderInfo> getCustomWidgets() {
+ return mCustomWidgets;
+ }
+
+ /**
+ * Returns the widget id for a specific provider.
+ */
+ public int getWidgetIdForCustomProvider(@NonNull ComponentName provider) {
+ int index = mWidgetsIdMap.indexOfValue(provider);
+ if (index >= 0) {
+ return LauncherAppWidgetInfo.CUSTOM_WIDGET_ID - mWidgetsIdMap.keyAt(index);
+ } else {
+ return AppWidgetManager.INVALID_APPWIDGET_ID;
+ }
+ }
+
+ /**
+ * Returns the widget provider in respect to given widget id.
+ */
+ @Nullable
+ public LauncherAppWidgetProviderInfo getWidgetProvider(int widgetId) {
+ ComponentName cn = mWidgetsIdMap.get(LauncherAppWidgetInfo.CUSTOM_WIDGET_ID - widgetId);
+ for (LauncherAppWidgetProviderInfo info : mCustomWidgets) {
+ if (info.provider.equals(cn)) return info;
+ }
+ return null;
+ }
+
+ private static CustomAppWidgetProviderInfo newInfo(
+ CustomWidgetPlugin plugin, Parcel parcel, Context context) {
+ int providerId = plugin.getProviderId();
+ CustomAppWidgetProviderInfo info = new CustomAppWidgetProviderInfo(
+ parcel, false, providerId);
+ info.provider = new ComponentName(
+ context.getPackageName(), CLS_CUSTOM_WIDGET_PREFIX + providerId);
+
+ info.label = plugin.getLabel();
+ info.icon = plugin.getIcon();
+ info.previewImage = plugin.getPreviewImage();
+ info.resizeMode = plugin.getResizeMode();
+
+ info.spanX = plugin.getSpanX();
+ info.spanY = plugin.getSpanY();
+ info.minSpanX = plugin.getMinSpanX();
+ info.minSpanY = plugin.getMinSpanY();
+ return info;
+ }
+
+ @Nullable
+ private CustomWidgetPlugin findPlugin(int providerId) {
+ return mPlugins.stream().filter((p) -> p.getProviderId() == providerId).findFirst()
+ .orElse(null);
+ }
+}
diff --git a/src/com/android/launcher3/widget/custom/CustomWidgetParser.java b/src/com/android/launcher3/widget/custom/CustomWidgetParser.java
deleted file mode 100644
index 00720c4..0000000
--- a/src/com/android/launcher3/widget/custom/CustomWidgetParser.java
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * 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.widget.custom;
-
-import android.appwidget.AppWidgetManager;
-import android.appwidget.AppWidgetProviderInfo;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.content.res.XmlResourceParser;
-import android.os.Parcel;
-import android.os.Process;
-import android.util.SparseArray;
-import android.util.Xml;
-
-import com.android.launcher3.LauncherAppWidgetInfo;
-import com.android.launcher3.LauncherAppWidgetProviderInfo;
-import com.android.launcher3.R;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-
-import static com.android.launcher3.LauncherAppWidgetProviderInfo.CLS_CUSTOM_WIDGET_PREFIX;
-
-/**
- * Utility class to parse {@ink CustomAppWidgetProviderInfo} definitions from xml
- */
-public class CustomWidgetParser {
-
- private static List<LauncherAppWidgetProviderInfo> sCustomWidgets;
- private static SparseArray<ComponentName> sWidgetsIdMap;
-
- public static List<LauncherAppWidgetProviderInfo> getCustomWidgets(Context context) {
- if (sCustomWidgets == null) {
- // Synchronization not needed as it it safe to load multiple times
- parseCustomWidgets(context);
- }
-
- return sCustomWidgets;
- }
-
- public static int getWidgetIdForCustomProvider(Context context, ComponentName provider) {
- if (sWidgetsIdMap == null) {
- parseCustomWidgets(context);
- }
- int index = sWidgetsIdMap.indexOfValue(provider);
- if (index >= 0) {
- return LauncherAppWidgetInfo.CUSTOM_WIDGET_ID - sWidgetsIdMap.keyAt(index);
- } else {
- return AppWidgetManager.INVALID_APPWIDGET_ID;
- }
- }
-
- public static LauncherAppWidgetProviderInfo getWidgetProvider(Context context, int widgetId) {
- if (sWidgetsIdMap == null || sCustomWidgets == null) {
- parseCustomWidgets(context);
- }
- ComponentName cn = sWidgetsIdMap.get(LauncherAppWidgetInfo.CUSTOM_WIDGET_ID - widgetId);
- for (LauncherAppWidgetProviderInfo info : sCustomWidgets) {
- if (info.provider.equals(cn)) {
- return info;
- }
- }
- return null;
- }
-
- private static void parseCustomWidgets(Context context) {
- ArrayList<LauncherAppWidgetProviderInfo> widgets = new ArrayList<>();
- SparseArray<ComponentName> idMap = new SparseArray<>();
-
- List<AppWidgetProviderInfo> providers = AppWidgetManager.getInstance(context)
- .getInstalledProvidersForProfile(Process.myUserHandle());
- if (providers.isEmpty()) {
- sCustomWidgets = widgets;
- sWidgetsIdMap = idMap;
- return;
- }
-
- Parcel parcel = Parcel.obtain();
- providers.get(0).writeToParcel(parcel, 0);
-
- try (XmlResourceParser parser = context.getResources().getXml(R.xml.custom_widgets)) {
- final int depth = parser.getDepth();
- int type;
-
- while (((type = parser.next()) != XmlPullParser.END_TAG ||
- parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) {
- if ((type == XmlPullParser.START_TAG) && "widget".equals(parser.getName())) {
- TypedArray a = context.obtainStyledAttributes(
- Xml.asAttributeSet(parser), R.styleable.CustomAppWidgetProviderInfo);
-
- parcel.setDataPosition(0);
- CustomAppWidgetProviderInfo info = newInfo(a, parcel, context);
- widgets.add(info);
- a.recycle();
-
- idMap.put(info.providerId, info.provider);
- }
- }
- } catch (IOException | XmlPullParserException e) {
- throw new RuntimeException(e);
- }
- parcel.recycle();
- sCustomWidgets = widgets;
- sWidgetsIdMap = idMap;
- }
-
- private static CustomAppWidgetProviderInfo newInfo(TypedArray a, Parcel parcel, Context context) {
- int providerId = a.getInt(R.styleable.CustomAppWidgetProviderInfo_providerId, 0);
- CustomAppWidgetProviderInfo info = new CustomAppWidgetProviderInfo(parcel, false, providerId);
- info.provider = new ComponentName(context.getPackageName(), CLS_CUSTOM_WIDGET_PREFIX + providerId);
-
- info.label = a.getString(R.styleable.CustomAppWidgetProviderInfo_android_label);
- info.initialLayout = a.getResourceId(R.styleable.CustomAppWidgetProviderInfo_android_initialLayout, 0);
- info.icon = a.getResourceId(R.styleable.CustomAppWidgetProviderInfo_android_icon, 0);
- info.previewImage = a.getResourceId(R.styleable.CustomAppWidgetProviderInfo_android_previewImage, 0);
- info.resizeMode = a.getInt(R.styleable.CustomAppWidgetProviderInfo_android_resizeMode, 0);
-
- info.spanX = a.getInt(R.styleable.CustomAppWidgetProviderInfo_numColumns, 1);
- info.spanY = a.getInt(R.styleable.CustomAppWidgetProviderInfo_numRows, 1);
- info.minSpanX = a.getInt(R.styleable.CustomAppWidgetProviderInfo_numMinColumns, 1);
- info.minSpanY = a.getInt(R.styleable.CustomAppWidgetProviderInfo_numMinRows, 1);
- return info;
- }
-}
diff --git a/src_plugins/com/android/systemui/plugins/CustomWidgetPlugin.java b/src_plugins/com/android/systemui/plugins/CustomWidgetPlugin.java
new file mode 100644
index 0000000..77ad7ea
--- /dev/null
+++ b/src_plugins/com/android/systemui/plugins/CustomWidgetPlugin.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2019 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.systemui.plugins;
+
+import android.appwidget.AppWidgetHostView;
+
+import com.android.systemui.plugins.annotations.ProvidesInterface;
+
+/**
+ * Implement this plugin interface to add a custom widget.
+ */
+@ProvidesInterface(action = CustomWidgetPlugin.ACTION, version = CustomWidgetPlugin.VERSION)
+public interface CustomWidgetPlugin extends Plugin {
+
+ String ACTION = "com.android.systemui.action.PLUGIN_CUSTOM_WIDGET";
+ int VERSION = 1;
+
+ /**
+ * An unique identifier for this widget. Must be a non-negative integer.
+ */
+ int getProviderId();
+
+ /**
+ * The label to display to the user in the AppWidget picker.
+ */
+ String getLabel();
+
+ /**
+ * A preview of what the AppWidget will look like after it's configured.
+ * If not supplied, the AppWidget's icon will be used.
+ */
+ int getPreviewImage();
+
+ /**
+ * The icon to display for this AppWidget in the AppWidget picker. If not supplied in the
+ * xml, the application icon will be used.
+ */
+ int getIcon();
+
+ /**
+ * The default width of the widget when added to a host, in dp. The widget will get
+ * at least this width, and will often be given more, depending on the host.
+ */
+ int getSpanX();
+
+ /**
+ * The default height of the widget when added to a host, in dp. The widget will get
+ * at least this height, and will often be given more, depending on the host.
+ */
+ int getSpanY();
+
+ /**
+ * Minimum width (in dp) which the widget can be resized to. This field has no effect if it
+ * is greater than minWidth or if horizontal resizing isn't enabled.
+ */
+ int getMinSpanX();
+
+ /**
+ * Minimum height (in dp) which the widget can be resized to. This field has no effect if it
+ * is greater than minHeight or if vertical resizing isn't enabled.
+ */
+ int getMinSpanY();
+
+ /**
+ * The rules by which a widget can be resized.
+ */
+ int getResizeMode();
+
+ /**
+ * Notify the plugin that container of the widget has been rendered, where the custom widget
+ * can be attached to.
+ */
+ void onViewCreated(AppWidgetHostView parent);
+}
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index 6d636cf..761253d 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -112,6 +112,7 @@
launcher ->
checkLauncherIntegrity(launcher, containerType)));
}
+ mLauncher.enableDebugTracing();
}
protected final LauncherActivityRule mActivityMonitor = new LauncherActivityRule();
@@ -202,6 +203,7 @@
resetLoaderState();
} else {
clearPackageData(mDevice.getLauncherPackageName());
+ mLauncher.enableDebugTracing();
}
}
diff --git a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
index 0c87ab9..c2a3c1c 100644
--- a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
+++ b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
@@ -173,7 +173,6 @@
@Test
public void testWorkspace() throws Exception {
- mLauncher.enableDebugTracing();
final Workspace workspace = mLauncher.getWorkspace();
// Test that ensureWorkspaceIsScrollable adds a page by dragging an icon there.
@@ -209,7 +208,6 @@
// Test starting a workspace app.
final AppIcon app = workspace.getWorkspaceAppIcon("Chrome");
assertNotNull("No Chrome app in workspace", app);
- mLauncher.disableDebugTracing();
}
public static void runIconLaunchFromAllAppsTest(AbstractLauncherUiTest test, AllApps allApps) {
@@ -300,7 +298,6 @@
@Test
@PortraitLandscape
public void testDragAppIcon() throws Throwable {
- mLauncher.enableDebugTracing();
// 1. Open all apps and wait for load complete.
// 2. Drag icon to homescreen.
// 3. Verify that the icon works on homescreen.
@@ -317,13 +314,11 @@
"Launcher activity is the top activity; expecting another activity to be the top "
+ "one",
isInBackground(launcher)));
- mLauncher.disableDebugTracing();
}
@Test
@PortraitLandscape
public void testDragShortcut() throws Throwable {
- mLauncher.enableDebugTracing();
// 1. Open all apps and wait for load complete.
// 2. Find the app and long press it to show shortcuts.
// 3. Press icon center until shortcuts appear
@@ -343,7 +338,6 @@
} finally {
allApps.unfreeze();
}
- mLauncher.disableDebugTracing();
}
public static String getAppPackageName() {
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index 9d43352..0bd6362 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -763,8 +763,7 @@
final Bundle parcel = (Bundle) executeAndWaitForEvent(
() -> linearGesture(startX, startY, endX, endY, steps),
event -> TestProtocol.SWITCHED_TO_STATE_MESSAGE.equals(event.getClassName()),
- "Swipe failed to receive an event for the swipe end: " + startX + ", " + startY
- + ", " + endX + ", " + endY);
+ "Swipe failed to receive an event for the swipe end");
assertEquals("Swipe switched launcher to a wrong state;",
TestProtocol.stateOrdinalToString(expectedState),
TestProtocol.stateOrdinalToString(parcel.getInt(TestProtocol.STATE_FIELD)));