2009-03-03 19:32:27 -08:00
|
|
|
/*
|
|
|
|
|
* Copyright (C) 2009 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.
|
|
|
|
|
*/
|
|
|
|
|
|
2021-02-22 14:03:44 +00:00
|
|
|
package com.android.launcher3.widget;
|
2009-03-03 19:32:27 -08:00
|
|
|
|
2022-11-08 16:46:07 -08:00
|
|
|
import static com.android.launcher3.widget.LauncherWidgetHolder.APPWIDGET_HOST_ID;
|
2017-11-14 16:55:22 -08:00
|
|
|
|
2009-03-11 12:11:58 -07:00
|
|
|
import android.appwidget.AppWidgetHost;
|
|
|
|
|
import android.appwidget.AppWidgetProviderInfo;
|
2009-03-03 19:32:27 -08:00
|
|
|
import android.content.Context;
|
2024-01-05 09:29:06 -08:00
|
|
|
import android.view.accessibility.AccessibilityNodeInfo;
|
|
|
|
|
import android.widget.RemoteViews;
|
2017-07-03 13:50:52 -07:00
|
|
|
|
2022-10-25 15:17:58 -07:00
|
|
|
import androidx.annotation.NonNull;
|
2021-05-18 16:16:14 +00:00
|
|
|
import androidx.annotation.Nullable;
|
|
|
|
|
|
2021-02-22 14:03:44 +00:00
|
|
|
import com.android.launcher3.LauncherAppState;
|
2024-01-05 09:29:06 -08:00
|
|
|
import com.android.launcher3.util.Executors;
|
|
|
|
|
import com.android.launcher3.util.SafeCloseable;
|
|
|
|
|
import com.android.launcher3.widget.LauncherWidgetHolder.ProviderChangedListener;
|
2009-03-03 19:32:27 -08:00
|
|
|
|
2014-08-11 17:05:23 -07:00
|
|
|
import java.util.ArrayList;
|
2024-01-05 09:29:06 -08:00
|
|
|
import java.util.Collections;
|
|
|
|
|
import java.util.List;
|
|
|
|
|
import java.util.Set;
|
|
|
|
|
import java.util.WeakHashMap;
|
2019-08-26 15:00:30 -07:00
|
|
|
import java.util.function.IntConsumer;
|
2014-08-11 17:05:23 -07:00
|
|
|
|
2009-03-03 19:32:27 -08:00
|
|
|
/**
|
2009-03-11 12:11:58 -07:00
|
|
|
* Specific {@link AppWidgetHost} that creates our {@link LauncherAppWidgetHostView}
|
2009-03-03 19:32:27 -08:00
|
|
|
* which correctly captures all long-press events. This ensures that users can
|
2009-03-11 12:11:58 -07:00
|
|
|
* always pick up and move widgets.
|
2009-03-03 19:32:27 -08:00
|
|
|
*/
|
2022-11-08 16:46:07 -08:00
|
|
|
class LauncherAppWidgetHost extends AppWidgetHost {
|
2022-10-25 15:17:58 -07:00
|
|
|
@NonNull
|
2024-01-05 09:29:06 -08:00
|
|
|
private final List<ProviderChangedListener> mProviderChangeListeners;
|
2012-06-14 11:59:51 -07:00
|
|
|
|
2022-10-25 15:17:58 -07:00
|
|
|
@NonNull
|
2017-07-03 13:50:52 -07:00
|
|
|
private final Context mContext;
|
2019-08-26 15:00:30 -07:00
|
|
|
|
2022-10-25 15:17:58 -07:00
|
|
|
@Nullable
|
|
|
|
|
private final IntConsumer mAppWidgetRemovedCallback;
|
2022-10-24 14:28:19 -07:00
|
|
|
|
2024-02-14 12:32:59 -08:00
|
|
|
@Nullable
|
|
|
|
|
private ListenableHostView mViewToRecycle;
|
|
|
|
|
|
2022-10-25 15:17:58 -07:00
|
|
|
public LauncherAppWidgetHost(@NonNull Context context,
|
2024-01-05 09:29:06 -08:00
|
|
|
@Nullable IntConsumer appWidgetRemovedCallback,
|
|
|
|
|
List<ProviderChangedListener> providerChangeListeners) {
|
2017-07-03 13:50:52 -07:00
|
|
|
super(context, APPWIDGET_HOST_ID);
|
|
|
|
|
mContext = context;
|
2019-08-26 15:00:30 -07:00
|
|
|
mAppWidgetRemovedCallback = appWidgetRemovedCallback;
|
2024-01-05 09:29:06 -08:00
|
|
|
mProviderChangeListeners = providerChangeListeners;
|
2017-11-14 16:55:22 -08:00
|
|
|
}
|
|
|
|
|
|
2017-07-03 13:50:52 -07:00
|
|
|
@Override
|
2012-06-14 11:59:51 -07:00
|
|
|
protected void onProvidersChanged() {
|
2015-04-20 18:19:25 -07:00
|
|
|
if (!mProviderChangeListeners.isEmpty()) {
|
2022-10-25 15:17:58 -07:00
|
|
|
for (LauncherWidgetHolder.ProviderChangedListener callback :
|
|
|
|
|
new ArrayList<>(mProviderChangeListeners)) {
|
2017-07-03 13:50:52 -07:00
|
|
|
callback.notifyWidgetProvidersChanged();
|
2015-04-20 18:19:25 -07:00
|
|
|
}
|
2014-08-11 17:05:23 -07:00
|
|
|
}
|
2012-06-14 11:59:51 -07:00
|
|
|
}
|
2014-03-05 18:07:04 -08:00
|
|
|
|
2024-02-14 12:32:59 -08:00
|
|
|
/**
|
|
|
|
|
* Sets the view to be recycled for the next widget creation.
|
|
|
|
|
*/
|
|
|
|
|
public void recycleViewForNextCreation(ListenableHostView viewToRecycle) {
|
|
|
|
|
mViewToRecycle = viewToRecycle;
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-25 15:17:58 -07:00
|
|
|
@Override
|
|
|
|
|
@NonNull
|
|
|
|
|
public LauncherAppWidgetHostView onCreateView(Context context, int appWidgetId,
|
|
|
|
|
AppWidgetProviderInfo appWidget) {
|
2024-02-14 12:32:59 -08:00
|
|
|
ListenableHostView result =
|
|
|
|
|
mViewToRecycle != null ? mViewToRecycle : new ListenableHostView(context);
|
|
|
|
|
mViewToRecycle = null;
|
|
|
|
|
return result;
|
2014-03-05 18:07:04 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Called when the AppWidget provider for a AppWidget has been upgraded to a new apk.
|
|
|
|
|
*/
|
|
|
|
|
@Override
|
2022-10-25 15:17:58 -07:00
|
|
|
protected void onProviderChanged(int appWidgetId, @NonNull AppWidgetProviderInfo appWidget) {
|
2014-03-05 18:07:04 -08:00
|
|
|
LauncherAppWidgetProviderInfo info = LauncherAppWidgetProviderInfo.fromProviderInfo(
|
2017-07-03 13:50:52 -07:00
|
|
|
mContext, appWidget);
|
2014-03-05 18:07:04 -08:00
|
|
|
super.onProviderChanged(appWidgetId, info);
|
2015-10-05 10:36:54 -07:00
|
|
|
// The super method updates the dimensions of the providerInfo. Update the
|
|
|
|
|
// launcher spans accordingly.
|
2021-02-22 14:03:44 +00:00
|
|
|
info.initSpans(mContext, LauncherAppState.getIDP(mContext));
|
2014-03-05 18:07:04 -08:00
|
|
|
}
|
2016-11-04 10:19:58 -07:00
|
|
|
|
2019-09-19 10:10:34 -07:00
|
|
|
/**
|
|
|
|
|
* Called on an appWidget is removed for a widgetId
|
2020-02-24 17:06:28 -08:00
|
|
|
*
|
|
|
|
|
* @param appWidgetId TODO: make this override when SDK is updated
|
2019-09-19 10:10:34 -07:00
|
|
|
*/
|
2022-10-25 15:17:58 -07:00
|
|
|
@Override
|
2019-09-19 10:10:34 -07:00
|
|
|
public void onAppWidgetRemoved(int appWidgetId) {
|
2019-08-26 15:00:30 -07:00
|
|
|
if (mAppWidgetRemovedCallback == null) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2024-01-05 09:29:06 -08:00
|
|
|
// Route the call via model thread, in case it comes while a loader-bind is in progress
|
|
|
|
|
Executors.MODEL_EXECUTOR.execute(
|
|
|
|
|
() -> Executors.MAIN_EXECUTOR.execute(
|
|
|
|
|
() -> mAppWidgetRemovedCallback.accept(appWidgetId)));
|
2019-08-26 15:00:30 -07:00
|
|
|
}
|
|
|
|
|
|
2022-10-25 15:17:58 -07:00
|
|
|
/**
|
|
|
|
|
* The same as super.clearViews(), except with the scope exposed
|
|
|
|
|
*/
|
2016-11-04 10:19:58 -07:00
|
|
|
@Override
|
2018-02-27 19:20:15 -08:00
|
|
|
public void clearViews() {
|
2016-11-04 10:19:58 -07:00
|
|
|
super.clearViews();
|
2017-07-03 13:50:52 -07:00
|
|
|
}
|
|
|
|
|
|
2024-01-05 09:29:06 -08:00
|
|
|
public static class ListenableHostView extends LauncherAppWidgetHostView {
|
|
|
|
|
|
|
|
|
|
private Set<Runnable> mUpdateListeners = Collections.EMPTY_SET;
|
|
|
|
|
|
|
|
|
|
ListenableHostView(Context context) {
|
|
|
|
|
super(context);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void updateAppWidget(RemoteViews remoteViews) {
|
|
|
|
|
super.updateAppWidget(remoteViews);
|
|
|
|
|
mUpdateListeners.forEach(Runnable::run);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
|
|
|
|
|
super.onInitializeAccessibilityNodeInfo(info);
|
|
|
|
|
info.setClassName(LauncherAppWidgetHostView.class.getName());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Adds a callback to be run everytime the provided app widget updates.
|
|
|
|
|
* @return a closable to remove this callback
|
|
|
|
|
*/
|
|
|
|
|
public SafeCloseable addUpdateListener(Runnable callback) {
|
|
|
|
|
if (mUpdateListeners == Collections.EMPTY_SET) {
|
|
|
|
|
mUpdateListeners = Collections.newSetFromMap(new WeakHashMap<>());
|
|
|
|
|
}
|
|
|
|
|
mUpdateListeners.add(callback);
|
|
|
|
|
return () -> mUpdateListeners.remove(callback);
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-03-03 19:32:27 -08:00
|
|
|
}
|