diff options
-rw-r--r-- | res/values/attrs.xml | 15 | ||||
-rw-r--r-- | res/xml/custom_widgets.xml | 31 | ||||
-rw-r--r-- | src/com/android/launcher3/Launcher.java | 13 | ||||
-rw-r--r-- | src/com/android/launcher3/LauncherAppState.java | 3 | ||||
-rw-r--r-- | src/com/android/launcher3/LauncherAppWidgetHost.java | 6 | ||||
-rw-r--r-- | src/com/android/launcher3/LauncherModel.java | 4 | ||||
-rw-r--r-- | src/com/android/launcher3/compat/AppWidgetManagerCompat.java | 13 | ||||
-rw-r--r-- | src/com/android/launcher3/compat/AppWidgetManagerCompatVL.java | 39 | ||||
-rw-r--r-- | src/com/android/launcher3/compat/AppWidgetManagerCompatVO.java | 4 | ||||
-rw-r--r-- | src/com/android/launcher3/config/BaseFlags.java | 7 | ||||
-rw-r--r-- | src/com/android/launcher3/widget/custom/CustomWidgetManager.java | 178 | ||||
-rw-r--r-- | src/com/android/launcher3/widget/custom/CustomWidgetParser.java | 142 | ||||
-rw-r--r-- | src_plugins/com/android/systemui/plugins/CustomWidgetPlugin.java | 72 |
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); +} |