Merge "migrate custom widgets in comply with plugin framework" into ub-launcher3-qt-future-dev
This commit is contained in:
@@ -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" />
|
||||
|
||||
@@ -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>
|
||||
@@ -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);
|
||||
}
|
||||
Reference in New Issue
Block a user