migrate custom widgets in comply with plugin framework

Bug: 139888225
Change-Id: I8a3d0fe2689ad5ba24b19309728bbad0b6287f71
Merged-In: I8a3d0fe2689ad5ba24b19309728bbad0b6287f71
(cherry picked from commit c7a6c2979c)
This commit is contained in:
Pinyao Ting
2019-08-26 14:36:02 -07:00
parent 0b72d6a891
commit 59e908b54f
13 changed files with 286 additions and 241 deletions
-15
View File
@@ -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" />
-31
View File
@@ -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>
+5 -8
View File
@@ -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();
}
@@ -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;
}
@@ -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);
@@ -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;
}
}
@@ -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);
}
@@ -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();
}
}
@@ -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) {
@@ -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;
@@ -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;
}
}
@@ -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;
}
}
@@ -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);
}