summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--res/values/attrs.xml15
-rw-r--r--res/xml/custom_widgets.xml31
-rw-r--r--src/com/android/launcher3/Launcher.java13
-rw-r--r--src/com/android/launcher3/LauncherAppState.java3
-rw-r--r--src/com/android/launcher3/LauncherAppWidgetHost.java6
-rw-r--r--src/com/android/launcher3/LauncherModel.java4
-rw-r--r--src/com/android/launcher3/compat/AppWidgetManagerCompat.java13
-rw-r--r--src/com/android/launcher3/compat/AppWidgetManagerCompatVL.java39
-rw-r--r--src/com/android/launcher3/compat/AppWidgetManagerCompatVO.java4
-rw-r--r--src/com/android/launcher3/config/BaseFlags.java7
-rw-r--r--src/com/android/launcher3/widget/custom/CustomWidgetManager.java178
-rw-r--r--src/com/android/launcher3/widget/custom/CustomWidgetParser.java142
-rw-r--r--src_plugins/com/android/systemui/plugins/CustomWidgetPlugin.java72
13 files changed, 286 insertions, 241 deletions
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index e76b89826..7be584e93 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -159,21 +159,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 4b5438650..000000000
--- 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/Launcher.java b/src/com/android/launcher3/Launcher.java
index d667e8c0c..7bb618ddf 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -79,6 +79,7 @@ import android.view.animation.OvershootInterpolator;
import android.widget.Toast;
import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
import com.android.launcher3.DropTarget.DragObject;
import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
@@ -147,7 +148,7 @@ import com.android.launcher3.widget.WidgetAddFlowHandler;
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;
@@ -158,9 +159,6 @@ import java.util.HashSet;
import java.util.List;
import java.util.function.Predicate;
-import androidx.annotation.Nullable;
-import androidx.annotation.VisibleForTesting;
-
/**
* Default launcher application.
*/
@@ -1666,10 +1664,9 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
} 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 b4a2216c5..d70abc2a9 100644
--- a/src/com/android/launcher3/LauncherAppState.java
+++ b/src/com/android/launcher3/LauncherAppState.java
@@ -37,6 +37,7 @@ import com.android.launcher3.notification.NotificationListener;
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 {
@@ -149,6 +150,8 @@ public class LauncherAppState {
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 64ec73007..1215d4321 100644
--- a/src/com/android/launcher3/LauncherAppWidgetHost.java
+++ b/src/com/android/launcher3/LauncherAppWidgetHost.java
@@ -27,12 +27,12 @@ import android.content.Context;
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;
import java.util.function.IntConsumer;
@@ -193,10 +193,8 @@ public class LauncherAppWidgetHost extends AppWidgetHost {
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 14f659810..c0cf13544 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -22,7 +22,6 @@ import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
import android.content.BroadcastReceiver;
-import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ShortcutInfo;
@@ -54,8 +53,6 @@ import com.android.launcher3.model.PackageUpdatedTask;
import com.android.launcher3.model.ShortcutsChangedTask;
import com.android.launcher3.model.UserLockStateChangedTask;
import com.android.launcher3.shortcuts.DeepShortcutManager;
-import com.android.launcher3.util.ComponentKey;
-import com.android.launcher3.util.IntArray;
import com.android.launcher3.util.IntSparseArrayMap;
import com.android.launcher3.util.ItemInfoMatcher;
import com.android.launcher3.util.PackageUserKey;
@@ -553,5 +550,4 @@ public class LauncherModel extends BroadcastReceiver
public Callbacks getCallback() {
return mCallbacks != null ? mCallbacks.get() : null;
}
-
}
diff --git a/src/com/android/launcher3/compat/AppWidgetManagerCompat.java b/src/com/android/launcher3/compat/AppWidgetManagerCompat.java
index 32432561b..fc5d11c23 100644
--- a/src/com/android/launcher3/compat/AppWidgetManagerCompat.java
+++ b/src/com/android/launcher3/compat/AppWidgetManagerCompat.java
@@ -23,19 +23,18 @@ import android.content.Context;
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 abstract class AppWidgetManagerCompat {
}
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 106574832..c8b1f67c3 100644
--- a/src/com/android/launcher3/compat/AppWidgetManagerCompatVL.java
+++ b/src/com/android/launcher3/compat/AppWidgetManagerCompatVL.java
@@ -24,12 +24,15 @@ import android.os.Process;
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.HashMap;
import java.util.Iterator;
import java.util.List;
-import androidx.annotation.Nullable;
-
class AppWidgetManagerCompatVL extends AppWidgetManagerCompat {
private final UserManager mUserManager;
@@ -54,14 +55,11 @@ class AppWidgetManagerCompatVL extends AppWidgetManagerCompat {
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 @@ class AppWidgetManagerCompatVL extends AppWidgetManagerCompat {
}
}
- 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 @@ class AppWidgetManagerCompatVL extends AppWidgetManagerCompat {
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 @@ class AppWidgetManagerCompatVL extends AppWidgetManagerCompat {
}
}
- 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 @@ class AppWidgetManagerCompatVL extends AppWidgetManagerCompat {
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 b7b0563ba..11ec333d1 100644
--- a/src/com/android/launcher3/compat/AppWidgetManagerCompatVO.java
+++ b/src/com/android/launcher3/compat/AppWidgetManagerCompatVO.java
@@ -19,14 +19,14 @@ package com.android.launcher3.compat;
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/config/BaseFlags.java b/src/com/android/launcher3/config/BaseFlags.java
index 945588941..7c8fe16df 100644
--- a/src/com/android/launcher3/config/BaseFlags.java
+++ b/src/com/android/launcher3/config/BaseFlags.java
@@ -23,11 +23,11 @@ import android.content.SharedPreferences;
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 @@ public abstract class BaseFlags {
//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/widget/custom/CustomWidgetManager.java b/src/com/android/launcher3/widget/custom/CustomWidgetManager.java
new file mode 100644
index 000000000..f20c83d92
--- /dev/null
+++ b/src/com/android/launcher3/widget/custom/CustomWidgetManager.java
@@ -0,0 +1,178 @@
+/*
+ * 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.lang.ref.WeakReference;
+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);
+
+ /**
+ * auto provider Id is an ever-increasing number that serves as the providerId whenever a new
+ * custom widget has been connected.
+ */
+ private int mAutoProviderId = 0;
+ private final SparseArray<CustomWidgetPlugin> mPlugins;
+ private final SparseArray<WeakReference<Context>> mContexts;
+ private final List<CustomAppWidgetProviderInfo> mCustomWidgets;
+ private final SparseArray<ComponentName> mWidgetsIdMap;
+ private Consumer<PackageUserKey> mWidgetRefreshCallback;
+
+ private CustomWidgetManager(Context context) {
+ mPlugins = new SparseArray<>();
+ mContexts = new SparseArray<>();
+ mCustomWidgets = new ArrayList<>();
+ mWidgetsIdMap = new SparseArray<>();
+ PluginManagerWrapper.INSTANCE.get(context)
+ .addPluginListener(this, CustomWidgetPlugin.class, true);
+ }
+
+ @Override
+ public void onPluginConnected(CustomWidgetPlugin plugin, Context context) {
+ mPlugins.put(mAutoProviderId, plugin);
+ mContexts.put(mAutoProviderId, new WeakReference<>(context));
+ 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(mAutoProviderId, plugin, parcel, context);
+ parcel.recycle();
+ mCustomWidgets.add(info);
+ mWidgetsIdMap.put(mAutoProviderId, info.provider);
+ mWidgetRefreshCallback.accept(null);
+ mAutoProviderId++;
+ }
+
+ @Override
+ public void onPluginDisconnected(CustomWidgetPlugin plugin) {
+ int providerId = findProviderId(plugin);
+ if (providerId == -1) return;
+ mPlugins.remove(providerId);
+ mContexts.remove(providerId);
+ mCustomWidgets.remove(getWidgetProvider(providerId));
+ mWidgetsIdMap.remove(providerId);
+ }
+
+ /**
+ * 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 = mPlugins.get(info.providerId);
+ WeakReference<Context> context = mContexts.get(info.providerId);
+ if (plugin == null) return;
+ plugin.onViewCreated(context == null ? null : context.get(), 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(int providerId, CustomWidgetPlugin plugin,
+ Parcel parcel, Context context) {
+ CustomAppWidgetProviderInfo info = new CustomAppWidgetProviderInfo(
+ parcel, false, providerId);
+ info.provider = new ComponentName(
+ context.getPackageName(), CLS_CUSTOM_WIDGET_PREFIX + providerId);
+
+ info.label = plugin.getLabel(context);
+ info.resizeMode = plugin.getResizeMode(context);
+
+ info.spanX = plugin.getSpanX(context);
+ info.spanY = plugin.getSpanY(context);
+ info.minSpanX = plugin.getMinSpanX(context);
+ info.minSpanY = plugin.getMinSpanY(context);
+ return info;
+ }
+
+ private int findProviderId(CustomWidgetPlugin plugin) {
+ for (int i = 0; i < mPlugins.size(); i++) {
+ int providerId = mPlugins.keyAt(i);
+ if (mPlugins.get(providerId) == plugin) {
+ return providerId;
+ }
+ }
+ return -1;
+ }
+}
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 00720c449..000000000
--- 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 000000000..47aa94b40
--- /dev/null
+++ b/src_plugins/com/android/systemui/plugins/CustomWidgetPlugin.java
@@ -0,0 +1,72 @@
+/*
+ * 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 android.content.Context;
+
+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;
+
+ /**
+ * The label to display to the user in the AppWidget picker.
+ */
+ String getLabel(Context context);
+
+ /**
+ * 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(Context context);
+
+ /**
+ * 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(Context context);
+
+ /**
+ * 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(Context context);
+
+ /**
+ * 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(Context context);
+
+ /**
+ * The rules by which a widget can be resized.
+ */
+ int getResizeMode(Context context);
+
+ /**
+ * Notify the plugin that container of the widget has been rendered, where the custom widget
+ * can be attached to.
+ */
+ void onViewCreated(Context context, AppWidgetHostView parent);
+}